Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions bases/polylith/cli/core.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pathlib import Path
from typing import List, Union

from polylith import commands, configuration, info, repo
from polylith.cli import create, options
Expand All @@ -14,6 +15,14 @@
)


def filtered_projects_data(
projects_data: List[dict], directory: Union[str, None]
) -> List[dict]:
dir_path = Path(directory).as_posix() if directory else Path.cwd().name

return [p for p in projects_data if dir_path in p["path"].as_posix()]


@app.command("info")
def info_command(short: Annotated[bool, options.short_workspace] = False):
"""Info about the Polylith workspace."""
Expand Down Expand Up @@ -42,8 +51,8 @@ def check_command(
"alias": str.split(alias, ",") if alias else [],
}

dir_path = Path(directory).as_posix() if directory else Path.cwd().name
projects_data = [p for p in only_projects_data if dir_path in p["path"].as_posix()]
projects_data = filtered_projects_data(only_projects_data, directory)

results = {commands.check.run(root, ns, p, cli_options) for p in projects_data}

if not all(results):
Expand All @@ -70,15 +79,15 @@ def libs_command(
root = repo.get_workspace_root(Path.cwd())
ns = configuration.get_namespace_from_config(root)

projects_data = info.get_projects_data(root, ns)
all_projects_data = info.get_projects_data(root, ns)

cli_options = {
"strict": strict,
"alias": str.split(alias, ",") if alias else [],
}

dir_path = Path(directory).as_posix() if directory else Path.cwd().name
projects_data = [p for p in projects_data if dir_path in p["path"].as_posix()]
projects_data = filtered_projects_data(all_projects_data, directory)

results = {commands.libs.run(root, ns, p, cli_options) for p in projects_data}

if not all(results):
Expand All @@ -96,20 +105,30 @@ def sync_command(
root = repo.get_workspace_root(Path.cwd())
ns = configuration.get_namespace_from_config(root)

projects_data = info.get_projects_data(root, ns)
all_projects_data = info.get_projects_data(root, ns)

cli_options = {
"strict": strict,
"quiet": quiet,
"verbose": verbose,
}

dir_path = Path(directory).as_posix() if directory else Path.cwd().name
projects_data = [p for p in projects_data if dir_path in p["path"].as_posix()]
projects_data = filtered_projects_data(all_projects_data, directory)

for p in projects_data:
commands.sync.run(root, ns, p, cli_options)


@app.command("deps")
def deps_command(directory: Annotated[str, options.directory] = ""):
"""Visualize the dependencies between bricks."""
root = repo.get_workspace_root(Path.cwd())
ns = configuration.get_namespace_from_config(root)

dir_path = Path(directory).as_posix() if directory else None

commands.deps.run(root, ns, dir_path)


if __name__ == "__main__":
app()
2 changes: 2 additions & 0 deletions bases/polylith/poetry_plugin/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
CreateComponentCommand,
CreateProjectCommand,
CreateWorkspaceCommand,
DepsCommand,
DiffCommand,
InfoCommand,
LibsCommand,
Expand All @@ -18,6 +19,7 @@
CreateComponentCommand,
CreateProjectCommand,
CreateWorkspaceCommand,
DepsCommand,
DiffCommand,
InfoCommand,
LibsCommand,
Expand Down
6 changes: 3 additions & 3 deletions components/polylith/check/collect.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pathlib import Path
from typing import List, Set
from typing import Set

from polylith import check, imports, workspace

Expand Down Expand Up @@ -31,13 +31,13 @@ def with_unknown_components(root: Path, ns: str, brick_imports: dict) -> dict:
return with_unknown_components(root, ns, collected)


def diff(known_bricks: Set[str], bases: List[str], components: List[str]) -> Set[str]:
def diff(known_bricks: Set[str], bases: Set[str], components: Set[str]) -> Set[str]:
bricks = set().union(bases, components)

return known_bricks.difference(bricks)


def imports_diff(brick_imports: dict, bases: List, components: List) -> Set[str]:
def imports_diff(brick_imports: dict, bases: Set[str], components: Set[str]) -> Set[str]:
flattened_bases = set().union(*brick_imports["bases"].values())
flattened_components = set().union(*brick_imports["components"].values())

Expand Down
2 changes: 1 addition & 1 deletion components/polylith/check/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def create_report(
brick_imports = collected_imports["brick_imports"]
third_party_imports = collected_imports["third_party_imports"]

brick_diff = collect.imports_diff(brick_imports, list(bases), list(components))
brick_diff = collect.imports_diff(brick_imports, bases, components)
libs_diff = libs.report.calculate_diff(
third_party_imports, third_party_libs, is_strict
)
Expand Down
4 changes: 2 additions & 2 deletions components/polylith/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from polylith.commands import check, create, diff, info, libs, sync
from polylith.commands import check, create, deps, diff, info, libs, sync

__all__ = ["check", "create", "diff", "info", "libs", "sync"]
__all__ = ["check", "create", "deps", "diff", "info", "libs", "sync"]
40 changes: 40 additions & 0 deletions components/polylith/commands/deps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from pathlib import Path
from typing import List, Set, Union

from polylith import bricks, deps, info


def print_report(root: Path, ns: str, bases: Set[str], components: Set[str]):
brick_imports = deps.get_brick_imports(root, ns, bases, components)

flattened = {**brick_imports["bases"], **brick_imports["components"]}

deps.print_deps(bases, components, flattened)


def pick_name(data: List[dict]) -> Set[str]:
return {b["name"] for b in data}


def get_bases(root: Path, ns: str, project_data: dict) -> Set[str]:
if project_data:
return set(project_data.get("bases", []))

return pick_name(bricks.get_bases_data(root, ns))


def get_components(root: Path, ns: str, project_data: dict) -> Set[str]:
if project_data:
return set(project_data.get("components", []))

return pick_name(bricks.get_components_data(root, ns))


def run(root: Path, ns: str, directory: Union[str, None]):
projects_data = info.get_projects_data(root, ns) if directory else []
project = next((p for p in projects_data if directory in p["path"].as_posix()), {})

bases = get_bases(root, ns, project)
components = get_components(root, ns, project)

print_report(root, ns, bases, components)
4 changes: 4 additions & 0 deletions components/polylith/deps/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from polylith.deps.core import get_brick_imports
from polylith.deps.report import print_deps

__all__ = ["get_brick_imports", "print_deps"]
23 changes: 23 additions & 0 deletions components/polylith/deps/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from pathlib import Path
from typing import Set

from polylith import check, workspace


def get_brick_imports(
root: Path, ns: str, bases: Set[str], components: Set[str]
) -> dict:
bases_paths = workspace.paths.collect_bases_paths(root, ns, bases)
comp_paths = workspace.paths.collect_components_paths(root, ns, components)

brick_imports_in_bases = check.collect.extract_bricks(bases_paths, ns)
brick_imports_in_components = check.collect.extract_bricks(comp_paths, ns)

return {
"bases": check.collect.with_unknown_components(
root, ns, brick_imports_in_bases
),
"components": check.collect.with_unknown_components(
root, ns, brick_imports_in_components
),
}
84 changes: 84 additions & 0 deletions components/polylith/deps/report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from functools import reduce
from typing import List, Set, Tuple

from polylith.reporting import theme
from rich import box
from rich.console import Console
from rich.table import Table


def calculate_tag(brick: str, project_data: dict) -> str:
return "base" if brick in project_data.get("bases", []) else "comp"


def to_col(brick: str, tag: str) -> str:
name = "\n".join(brick)

return f"[{tag}]{name}[/]"


def brick_status(bricks: List[str], brick_name: str, imported: str) -> str:
status = theme.check_emoji if imported in bricks and imported != brick_name else "-"

return f"[data]{status}[/]"


def to_row(name: str, tag: str, brick_imports: dict, imported: List[str]) -> List[str]:
bricks = brick_imports[name]
statuses = [brick_status(bricks, name, i) for i in imported]

return [f"[{tag}]{name}[/]"] + statuses


def flatten_import(acc: Set[str], kv: Tuple[str, Set[str]]) -> set:
key = kv[0]
values = kv[1]

return set().union(acc, values.difference({key}))


def flatten_imports(brick_imports: dict) -> Set[str]:
"""Flatten the dict into a set of imports, with the actual brick filtered away when existing as an import"""
return reduce(flatten_import, brick_imports.items(), set())


def create_columns(
imported_bases: List[str], imported_components: List[str]
) -> List[str]:
base_cols = [to_col(brick, "base") for brick in imported_bases]
comp_cols = [to_col(brick, "comp") for brick in imported_components]

return comp_cols + base_cols


def create_rows(
bases: Set[str], components: Set[str], import_data: dict, imported: List[str]
) -> List[List[str]]:
base_rows = [to_row(b, "base", import_data, imported) for b in sorted(bases)]
comp_rows = [to_row(c, "comp", import_data, imported) for c in sorted(components)]

return comp_rows + base_rows


def print_deps(bases: Set[str], components: Set[str], import_data: dict):
flattened = flatten_imports(import_data)

imported_bases = sorted({b for b in flattened if b in bases})
imported_components = sorted({c for c in flattened if c in components})
imported_bricks = imported_components + imported_bases

table = Table(box=box.SIMPLE_HEAD)
table.add_column("[data]brick[/]")

cols = create_columns(imported_bases, imported_components)
rows = create_rows(bases, components, import_data, imported_bricks)

for col in cols:
table.add_column(col, justify="center")

for row in rows:
table.add_row(*row)

console = Console(theme=theme.poly_theme)

console.print(table, overflow="ellipsis")
2 changes: 1 addition & 1 deletion components/polylith/info/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


def brick_status(brick, bricks, command: str) -> str:
emoji = ":heavy_check_mark:" if command == "info" else ":gear:"
emoji = theme.check_emoji if command == "info" else ":gear:"

status = emoji if brick in bricks else "-"

Expand Down
2 changes: 2 additions & 0 deletions components/polylith/poetry/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from polylith.poetry.commands.create_component import CreateComponentCommand
from polylith.poetry.commands.create_project import CreateProjectCommand
from polylith.poetry.commands.create_workspace import CreateWorkspaceCommand
from polylith.poetry.commands.deps import DepsCommand
from polylith.poetry.commands.diff import DiffCommand
from polylith.poetry.commands.info import InfoCommand
from polylith.poetry.commands.libs import LibsCommand
Expand All @@ -14,6 +15,7 @@
"CreateComponentCommand",
"CreateProjectCommand",
"CreateWorkspaceCommand",
"DepsCommand",
"DiffCommand",
"InfoCommand",
"LibsCommand",
Expand Down
20 changes: 20 additions & 0 deletions components/polylith/poetry/commands/deps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from pathlib import Path

from poetry.console.commands.command import Command
from polylith import commands, configuration, repo


class DepsCommand(Command):
name = "poly deps"
description = "Visualize the dependencies between <comment>bricks</>."

def handle(self) -> int:
directory = self.option("directory")
root = repo.get_workspace_root(Path.cwd())
ns = configuration.get_namespace_from_config(root)

dir_path = Path(directory).as_posix() if directory else None

commands.deps.run(root, ns, dir_path)

return 0
2 changes: 2 additions & 0 deletions components/polylith/reporting/theme.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@
"base": "#6495ED",
}
)

check_emoji = ":heavy_check_mark:"
29 changes: 4 additions & 25 deletions components/polylith/sync/collect.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,6 @@
from pathlib import Path

from polylith import check, info, workspace


def get_brick_imports(root: Path, ns: str, project_data: dict) -> dict:
bases = {b for b in project_data.get("bases", [])}
components = {c for c in project_data.get("components", [])}

bases_paths = workspace.paths.collect_bases_paths(root, ns, bases)
components_paths = workspace.paths.collect_components_paths(root, ns, components)

brick_imports_in_bases = check.collect.extract_bricks(bases_paths, ns)
brick_imports_in_components = check.collect.extract_bricks(components_paths, ns)

return {
"bases": check.collect.with_unknown_components(
root, ns, brick_imports_in_bases
),
"components": check.collect.with_unknown_components(
root, ns, brick_imports_in_components
),
}
from polylith import check, deps, info


def calculate_diff(
Expand All @@ -29,14 +9,13 @@ def calculate_diff(
project_data: dict,
workspace_data: dict,
) -> dict:
brick_imports = get_brick_imports(root, namespace, project_data)
bases = set(project_data["bases"])
components = set(project_data["components"])

all_bases = workspace_data["bases"]
all_components = workspace_data["components"]

bases = project_data["bases"]
components = project_data["components"]

brick_imports = deps.get_brick_imports(root, namespace, bases, components)
is_project = info.is_project(project_data)

if is_project:
Expand Down
Loading