diff --git a/components/polylith/info/collect.py b/components/polylith/info/collect.py index da23ac4d..c3514863 100644 --- a/components/polylith/info/collect.py +++ b/components/polylith/info/collect.py @@ -39,7 +39,7 @@ def get_bricks_in_projects( res = [ { - **{"name": p["name"]}, + **{"name": p["name"], "path": p["path"]}, **get_project_bricks(p["packages"], components, bases, namespace), } for p in packages_for_projects diff --git a/components/polylith/libs/report.py b/components/polylith/libs/report.py index a0decfe0..1b70e06f 100644 --- a/components/polylith/libs/report.py +++ b/components/polylith/libs/report.py @@ -40,7 +40,9 @@ def calculate_diff(brick_imports: dict, third_party_libs: Set[str]) -> Set[str]: bases_imports = flatten_imports(brick_imports, "bases") components_imports = flatten_imports(brick_imports, "components") - return set().union(bases_imports, components_imports).difference(third_party_libs) + normalized_libs = {t.replace("-", "_") for t in third_party_libs} + + return set().union(bases_imports, components_imports).difference(normalized_libs) def print_libs_summary(brick_imports: dict, project_name: str) -> None: @@ -85,16 +87,15 @@ def print_libs_in_bricks(brick_imports: dict) -> None: def print_missing_installed_libs( - brick_imports: dict, third_party_libs: Set[str], project_data: dict -) -> None: + brick_imports: dict, third_party_libs: Set[str], project_name: str +) -> bool: diff = calculate_diff(brick_imports, third_party_libs) if not diff: - return + return True console = Console(theme=info_theme) - project_name = project_data["name"] missing = ", ".join(sorted(diff)) console.print( @@ -102,3 +103,4 @@ def print_missing_installed_libs( ) console.print(f":thinking_face: {missing}") + return False diff --git a/components/polylith/poetry/commands/libs.py b/components/polylith/poetry/commands/libs.py index d3aa7dc5..73d39c62 100644 --- a/components/polylith/poetry/commands/libs.py +++ b/components/polylith/poetry/commands/libs.py @@ -1,7 +1,8 @@ from pathlib import Path -from typing import List, Set +from typing import List, Set, Union from poetry.console.commands.command import Command +from poetry.factory import Factory from polylith import info, project, repo, workspace from polylith.libs import report @@ -13,22 +14,38 @@ def get_projects_data(root: Path, ns: str) -> List[dict]: return info.get_bricks_in_projects(root, components, bases, ns) -def get_project_data(root: Path, ns: str, project_name: str) -> List[dict]: - projects_data = get_projects_data(root, ns) +class LibsCommand(Command): + name = "poly libs" + description = "Show third-party libraries used in the workspace." + + def find_third_party_libs(self, path: Union[Path, None]) -> Set: + project_poetry = Factory().create_poetry(path) if path else self.poetry - filtered = next((p for p in projects_data if p["name"] == project_name), None) + if not project_poetry.locker.is_locked(): + raise ValueError("poetry.lock not found. Run `poetry lock` to create it.") - return [filtered] if filtered else projects_data + packages = project_poetry.locker.locked_repository().packages + return {p.name for p in packages} -class LibsCommand(Command): - name = "poly libs" - description = "Show third-party libraries used in the workspace." + def print_report(self, root: Path, ns: str, data: dict) -> bool: + name = data["name"] + path = data["path"] - def find_third_party_libs(self) -> Set[str]: - packages = self.poetry.locker.locked_repository().packages + brick_imports = report.get_third_party_imports(root, ns, data) - return {p.name for p in packages if p.category == "main"} + report.print_libs_summary(brick_imports, name) + report.print_libs_in_bricks(brick_imports) + + try: + third_party_libs = self.find_third_party_libs(path) + + return report.print_missing_installed_libs( + brick_imports, third_party_libs, name + ) + except ValueError as e: + self.line_error(f"{name}: {e}") + return False def handle(self) -> int: root = repo.find_workspace_root(Path.cwd()) @@ -38,25 +55,24 @@ def handle(self) -> int: "Didn't find the workspace root. Expected to find a workspace.toml file." ) - if not self.poetry.locker.is_locked(): - raise ValueError("poetry.lock not found. Run `poetry lock` to create it.") - - third_party_libs = self.find_third_party_libs() - ns = workspace.parser.get_namespace_from_config(root) - project_name = project.get_project_name(self.poetry.pyproject.data) + projects_data = get_projects_data(root, ns) - projects_data = get_project_data(root, ns, project_name) + if self.option("directory"): + self.line("in directory!") + project_name = project.get_project_name(self.poetry.pyproject.data) - for project_data in projects_data: - brick_imports = report.get_third_party_imports(root, ns, project_data) + data = next((p for p in projects_data if p["name"] == project_name), None) - report.print_libs_summary(brick_imports, project_data["name"]) - report.print_libs_in_bricks(brick_imports) + if not data: + raise ValueError(f"Didn't find project in {self.option('directory')}") - report.print_missing_installed_libs( - brick_imports, third_party_libs, project_data - ) + res = self.print_report(root, ns, data) + result_code = 0 if res else 1 + else: + results = {self.print_report(root, ns, data) for data in projects_data} + + result_code = 0 if all(results) else 1 - return 0 + return result_code diff --git a/components/polylith/project/__init__.py b/components/polylith/project/__init__.py index bd758ec8..cdf68e5e 100644 --- a/components/polylith/project/__init__.py +++ b/components/polylith/project/__init__.py @@ -2,7 +2,6 @@ from polylith.project.get import ( get_packages_for_projects, get_project_name, - get_project_names, get_project_names_and_paths, ) from polylith.project.parser import parse_package_paths @@ -10,7 +9,6 @@ __all__ = [ "create_project", "get_project_name", - "get_project_names", "get_project_names_and_paths", "get_packages_for_projects", "parse_package_paths", diff --git a/components/polylith/project/get.py b/components/polylith/project/get.py index 72a092c8..f68df96c 100644 --- a/components/polylith/project/get.py +++ b/components/polylith/project/get.py @@ -23,23 +23,21 @@ def get_project_files(root: Path) -> Generator: return root.glob(f"projects/**/{default_toml}") -def get_toml_files(root: Path) -> List[tomlkit.TOMLDocument]: +def get_toml_files(root: Path) -> List[dict]: project_files = get_project_files(root) - return [get_toml(p) for p in project_files] - - -def get_project_names(root: Path) -> List[str]: - tomls = get_toml_files(root) - - return [get_project_name(d) for d in tomls] + return [{"toml": get_toml(p), "path": p.parent} for p in project_files] def get_packages_for_projects(root: Path) -> List[dict]: tomls = get_toml_files(root) return [ - {"name": get_project_name(d), "packages": get_project_package_includes(d)} + { + "name": get_project_name(d["toml"]), + "packages": get_project_package_includes(d["toml"]), + "path": d["path"], + } for d in tomls ] diff --git a/projects/poetry_polylith_plugin/pyproject.toml b/projects/poetry_polylith_plugin/pyproject.toml index f432fe40..ac064e70 100644 --- a/projects/poetry_polylith_plugin/pyproject.toml +++ b/projects/poetry_polylith_plugin/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "poetry-polylith-plugin" -version = "1.3.0" +version = "1.3.1" description = "A Poetry plugin that adds tooling support for the Polylith Architecture" authors = ["David Vujic"] homepage = "https://github.com/davidvujic/python-polylith"