diff --git a/pyproject.toml b/pyproject.toml index 5124c97d..d878626d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,6 +95,7 @@ include = [ "CONTRIBUTING.md", "SECURITY.md", "package", + "subpackages.py", "web.png", ] exclude = [ diff --git a/src/ahriman/application/ahriman.py b/src/ahriman/application/ahriman.py index 63ed92c1..ffd486d8 100644 --- a/src/ahriman/application/ahriman.py +++ b/src/ahriman/application/ahriman.py @@ -105,11 +105,11 @@ def run() -> int: Returns: int: application status code """ - args_parser = _parser() - args = args_parser.parse_args() + parser = _parser() + args = parser.parse_args() if args.command is None: # in case of empty command we would like to print help message - args_parser.exit(status=2, message=args_parser.format_help()) + parser.exit(status=2, message=parser.format_help()) handler: Handler = args.handler return handler.execute(args) diff --git a/subpackages.py b/subpackages.py new file mode 100644 index 00000000..56b1f2c7 --- /dev/null +++ b/subpackages.py @@ -0,0 +1,120 @@ +# +# Copyright (c) 2021-2024 ahriman team. +# +# This file is part of ahriman +# (see https://github.com/arcan1s/ahriman). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +import argparse +import shutil +import site +import sys + +from pathlib import Path + + +prefix = Path(sys.prefix).relative_to("/") +site_packages = Path(site.getsitepackages()[0]).relative_to("/") +SUBPACKAGES = { + "ahriman": [ + Path("etc"), + prefix / "lib" / "systemd", + prefix / "share", + site_packages / "ahriman", + ], + "ahriman-web": [ + site_packages / "ahriman" / "application" / "handlers" / "web.py", + site_packages / "ahriman" / "core" / "auth", + site_packages / "ahriman" / "web", + ], +} + + +def subpackages(root: Path) -> dict[str, list[Path]]: + """ + extend list of subpackages + + Args: + root(Path): root directory + + Returns: + dict[str, list[Path]]: extended list of files which belong to a specific package + """ + for package, paths in SUBPACKAGES.items(): + new_paths = [] + for path in paths: + full_path = root / path + + match path.suffix: + case ".py": + pycache_path = full_path.parent / "__pycache__" + new_paths.extend( + new_path.relative_to(root) for new_path in pycache_path.glob(f"{full_path.stem}.*.pyc") + ) + + SUBPACKAGES[package].extend(new_paths) + + return SUBPACKAGES + + +def process(root: Path, include: list[Path], exclude: list[Path]) -> None: + """ + remove files based on patterns + + Args: + root(Path): root directory + include(list[Path]): list of files to include to the subpackage + exclude(list[Path]): list of files to exclude from the subpackage + """ + for subdirectory, _, files in root.walk(top_down=False): + for file in files: + full_path = subdirectory / file + relative_path = full_path.relative_to(root) + + if not any(relative_path.is_relative_to(path) for path in include): + full_path.unlink() + elif any(relative_path.is_relative_to(path) for path in exclude): + full_path.unlink() + + content = list(subdirectory.iterdir()) + if not content: + shutil.rmtree(subdirectory) + + +def run() -> None: + """ + run application + """ + parser = argparse.ArgumentParser(description="Split package into subpackages") + parser.add_argument("root", help="package root", type=Path) + parser.add_argument("subpackage", help="subpackage name", choices=SUBPACKAGES.keys()) + + args = parser.parse_args() + + full_subpackages = subpackages(args.root) + include = full_subpackages[args.subpackage] + exclude = [ + path + for subpackage, portion in full_subpackages.items() + if subpackage != args.subpackage + for path in portion + if not any(include_path.is_relative_to(path) for include_path in include) + ] + + process(args.root, include, exclude) + + +if __name__ == "__main__": + run() diff --git a/tests/ahriman/core/upload/test_github.py b/tests/ahriman/core/upload/test_github.py index e39b1914..045ad7a4 100644 --- a/tests/ahriman/core/upload/test_github.py +++ b/tests/ahriman/core/upload/test_github.py @@ -132,7 +132,7 @@ def test_get_local_files(github: GitHub, resource_path_root: Path, mocker: Mocke """ must get all local files recursively """ - walk_mock = mocker.patch("ahriman.core.utils.walk") + walk_mock = mocker.patch("ahriman.core.upload.github.walk") github.get_local_files(resource_path_root) walk_mock.assert_called() diff --git a/tests/ahriman/core/upload/test_s3.py b/tests/ahriman/core/upload/test_s3.py index dc3ba4dc..6655af7d 100644 --- a/tests/ahriman/core/upload/test_s3.py +++ b/tests/ahriman/core/upload/test_s3.py @@ -103,7 +103,7 @@ def test_get_local_files(s3: S3, resource_path_root: Path, mocker: MockerFixture """ must get all local files recursively """ - walk_mock = mocker.patch("ahriman.core.utils.walk") + walk_mock = mocker.patch("ahriman.core.upload.s3.walk") s3.get_local_files(resource_path_root) walk_mock.assert_called()