Coverage for sel_tools/file_export/copy_item.py: 100%
22 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-04 21:22 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-04 21:22 +0000
1"""Copy file or folder with support for an ignore file."""
3import shutil
4from collections.abc import Callable
5from pathlib import Path
7from sel_tools.file_export.config import EXPORT_IGNORE
10def copy_item(source: Path, dest: Path) -> None:
11 """Copy file or folder 'source' with support for an ignore file to dest."""
12 if source.is_file():
13 shutil.copyfile(str(source), str(dest), follow_symlinks=False)
14 else:
15 ignored_items = get_ignored_items_from(source)
16 shutil.copytree(
17 str(source),
18 str(dest),
19 symlinks=False,
20 dirs_exist_ok=True,
21 ignore=ignore_files(ignored_items),
22 )
25def get_ignored_items_from(folder: Path) -> set[Path]:
26 """Get list of ignored items from export ignore file with absolute paths."""
27 ignore_file = folder / EXPORT_IGNORE
28 if not ignore_file.exists():
29 return set()
31 ignore_file_lines = ignore_file.read_text().splitlines()
32 non_empty_lines = list(filter(None, ignore_file_lines))
33 non_empty_lines.append(f"**/{EXPORT_IGNORE}")
34 ignore_list = [file for ignore_file_line in non_empty_lines for file in folder.glob(ignore_file_line)]
36 return {item.resolve() for item in ignore_list}
39def ignore_files(ignore_set: set[Path]) -> Callable:
40 """Create callable for ignoring files with shutil.copytree."""
42 def ignore_callable(directory: str, contents: list[str]) -> list[str]:
43 """Callable for ignoring files with shutil.copytree."""
44 return [item for item in contents if Path(directory).joinpath(item).resolve() in ignore_set]
46 return ignore_callable