"""GitSync - A quick way to create .gitignore (:mod:`qurry.capsule.mori.gitsync`)"""
import os
from pathlib import Path
from typing import Union, Optional
from ..utils import OpenArgs, PrintArgs, create_open_args, create_print_args
[docs]
class GitSyncControl(list[str]):
"""A gitignore file generator. A quick way to create .gitignore"""
[docs]
def sync(self, filename: str, force: bool = False) -> bool:
"""Add file to sync.
Args:
filename (str): Filename.
force (bool, optional): Force to add the file to sync.
If the file is already added, then it will be added again.
Defaults to False.
Returns:
bool: The file is added to be synchronized and return True.
If `force` is True, it will add the file again even if it's already added,
otherwise it will return False if the file is already added.
"""
line = f"!{filename}"
if line in self:
if force:
self.append(line)
return True
return False
self.append(line)
return True
[docs]
def ignore(self, filename: str, force: bool = False) -> bool:
"""Add file to ignore from sync.
Args:
filename (str): Filename.
force (bool, optional): Force to add the file to ignore.
If the file is already added, then it will be added again.
Defaults to False.
Returns:
bool: The file is added to be ignored and return True.
If `force` is True, it will add the file again even if it's already added,
otherwise it will return False if the file is already added.
"""
line = f"{filename}"
if line in self:
if force:
self.append(line)
return True
return False
self.append(line)
return True
[docs]
def export(
self,
save_location: Union[Path, str] = Path("./"),
open_args: Optional[OpenArgs] = None,
print_args: Optional[PrintArgs] = None,
) -> None:
"""Export .gitignore
Args:
save_location (Path): The location of .gitignore.
open_args (Optional[OpenArgs], optional):
The other arguments for :func:`open` function.
Defaults to None,
it will be set to :const:`~qurry.capsule.utils.DEFAULT_OPEN_ARGS`.
print_args (Optional[PrintArgs], optional):
The other arguments for :func:`print` function.
Defaults to None,
it will be set to :const:`~qurry.capsule.utils.DEFAULT_PRINT_ARGS`.
"""
open_args = create_open_args(open_args=open_args)
print_args = create_print_args(print_args=print_args)
assert "encoding" in open_args, "encoding must be specified in open_args"
encoding = open_args.pop("encoding")
assert "encoding" not in open_args, "encoding must not be in open_args after pop"
if isinstance(save_location, str):
save_location = Path(save_location)
elif isinstance(save_location, Path):
...
else:
raise ValueError("'save_location' needs to be the type of 'str' or 'Path'.")
if not os.path.exists(save_location):
raise FileNotFoundError(f"Such location not found: {save_location}")
with open(save_location / ".gitignore", encoding=encoding, **open_args) as ignore_list:
for item in self:
print(item, file=ignore_list, **print_args)
[docs]
def clear_duplicates(self) -> None:
"""Clear duplicate items in .gitignore."""
seen = set()
unique_items = []
for item in self:
if item not in seen:
seen.add(item)
unique_items.append(item)
self.clear()
self.extend(unique_items)
[docs]
def load(
self,
save_location: Union[Path, str],
take_duplicate: bool = False,
open_args: Optional[OpenArgs] = None,
):
"""Read existed .gitignore
Args:
save_location (Path): The location of .gitignore.
take_duplicate (bool, optional):
Take duplicate item in .gitignore. Defaults to False.
open_args (Optional[OpenArgs], optional):
The other arguments for :func:`open` function.
Defaults to None,
it will be set to the returned valuse of
:func:`~qurry.capsule.utils.create_open_args`
with `is_read_only` set to True. It will be like:
.. code-block:: python
{
"mode": "r",
"encoding": "utf-8",
}
Raises:
FileNotFoundError: The .gitignore is not found.
TypeError: The save_location is not the type of 'str' or 'Path'.
"""
open_args = create_open_args(open_args=open_args, is_read_only=True)
assert "encoding" in open_args, "encoding must be specified in open_args"
encoding = open_args.pop("encoding")
assert "encoding" not in open_args, "encoding must not be in open_args after pop"
if isinstance(save_location, str):
save_location = Path(save_location)
elif isinstance(save_location, Path):
...
else:
raise ValueError("'save_location' needs to be the type of 'str' or 'Path'.")
if not os.path.exists(save_location):
raise FileNotFoundError(f"Such location not found: {save_location}")
actual_file_path = save_location / ".gitignore"
if not os.path.exists(actual_file_path):
raise FileNotFoundError(f"The .gitignore is not found on '{save_location}'.")
tmp_list = []
with open(actual_file_path, encoding=encoding, **open_args) as ignore_list:
for line in ignore_list.readlines():
tmp_list.append(line.strip())
if not take_duplicate:
tmp_list = list(set(tmp_list))
self += tmp_list