Skip to content

Commit cdfc820

Browse files
authored
feat(poly deps, info, libs): save contents to file command option (#372)
* feat(poly deps): save command output to file * feat(poly info): save command output to file * refactor(poetry): command options with less duplications * feat(poly libs): save command output to file * fix(poly sync): remove unused 'strict' option * bump the Poetry plugin to 1.42.0 * bump the CLI to 1.35.0 * bump the PDM Polylith bricks hook to 1.3.3 * bump the PDM Polylith workspace hook to 1.3.3
1 parent 087089f commit cdfc820

File tree

28 files changed

+287
-121
lines changed

28 files changed

+287
-121
lines changed

bases/polylith/cli/core.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,20 @@ def enriched_with_lock_files_data(
5959

6060

6161
@app.command("info")
62-
def info_command(short: Annotated[bool, options.short_workspace] = False):
62+
def info_command(
63+
short: Annotated[bool, options.short_workspace] = False,
64+
save: Annotated[bool, options.save] = False,
65+
):
6366
"""Info about the Polylith workspace."""
64-
commands.info.run(short)
67+
root = repo.get_workspace_root(Path.cwd())
68+
output = configuration.get_output_dir(root, "info") if save else None
69+
70+
cli_options = {
71+
"short": short,
72+
"save": save,
73+
"output": output,
74+
}
75+
commands.info.run(root, cli_options)
6576

6677

6778
@app.command("check")
@@ -120,17 +131,21 @@ def libs_command(
120131
directory: Annotated[str, options.directory] = "",
121132
alias: Annotated[str, options.alias] = "",
122133
short: Annotated[bool, options.short] = False,
134+
save: Annotated[bool, options.save] = False,
123135
):
124136
"""Show third-party libraries used in the workspace."""
125137
root = repo.get_workspace_root(Path.cwd())
126138
ns = configuration.get_namespace_from_config(root)
127139

128140
all_projects_data = info.get_projects_data(root, ns)
141+
output = configuration.get_output_dir(root, "libs") if save else None
129142

130143
cli_options = {
131144
"strict": strict,
132145
"alias": str.split(alias, ",") if alias else [],
133146
"short": short,
147+
"save": save,
148+
"output": output,
134149
}
135150

136151
projects_data = filtered_projects_data(all_projects_data, directory)
@@ -145,7 +160,6 @@ def libs_command(
145160

146161
@app.command("sync")
147162
def sync_command(
148-
strict: Annotated[bool, options.strict] = False,
149163
quiet: Annotated[bool, options.quiet] = False,
150164
directory: Annotated[str, options.directory] = "",
151165
verbose: Annotated[bool, options.verbose] = False,
@@ -157,7 +171,6 @@ def sync_command(
157171
all_projects_data = info.get_projects_data(root, ns)
158172

159173
cli_options = {
160-
"strict": strict,
161174
"quiet": quiet,
162175
"verbose": verbose,
163176
}
@@ -172,14 +185,23 @@ def sync_command(
172185
def deps_command(
173186
directory: Annotated[str, options.directory] = "",
174187
brick: Annotated[str, options.brick] = "",
188+
save: Annotated[bool, options.save] = False,
175189
):
176190
"""Visualize the dependencies between bricks."""
177191
root = repo.get_workspace_root(Path.cwd())
178192
ns = configuration.get_namespace_from_config(root)
179193

180194
dir_path = Path(directory).as_posix() if directory else None
195+
output = configuration.get_output_dir(root, "deps") if save else None
196+
197+
cli_options = {
198+
"directory": dir_path,
199+
"brick": brick or None,
200+
"save": save,
201+
"output": output,
202+
}
181203

182-
commands.deps.run(root, ns, dir_path, brick or None)
204+
commands.deps.run(root, ns, cli_options)
183205

184206

185207
if __name__ == "__main__":

bases/polylith/cli/options.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@
1818
quiet = Option(help="Do not output any messages.")
1919

2020
brick = Option(help="Shows dependencies for selected brick.")
21+
save = Option(help="Store the contents of this command to file.")

components/polylith/commands/deps.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
from pathlib import Path
2-
from typing import List, Set, Union
2+
from typing import List, Set
33

44
from polylith import bricks, deps, info
55

66

7-
def get_imports(root: Path, ns: str, bases: Set[str], components: Set[str]) -> dict:
7+
def get_imports(root: Path, ns: str, bricks: dict) -> dict:
8+
bases = bricks["bases"]
9+
components = bricks["components"]
810
brick_imports = deps.get_brick_imports(root, ns, bases, components)
911

1012
return {**brick_imports["bases"], **brick_imports["components"]}
@@ -28,17 +30,22 @@ def get_components(root: Path, ns: str, project_data: dict) -> Set[str]:
2830
return pick_name(bricks.get_components_data(root, ns))
2931

3032

31-
def run(root: Path, ns: str, directory: Union[str, None], brick: Union[str, None]):
33+
def run(root: Path, ns: str, options: dict):
34+
directory = options.get("directory")
35+
brick = options.get("brick")
36+
3237
projects_data = info.get_projects_data(root, ns) if directory else []
3338
project = next((p for p in projects_data if directory in p["path"].as_posix()), {})
3439

35-
bases = get_bases(root, ns, project)
36-
components = get_components(root, ns, project)
40+
bricks = {
41+
"bases": get_bases(root, ns, project),
42+
"components": get_components(root, ns, project),
43+
}
3744

38-
imports = get_imports(root, ns, bases, components)
45+
imports = get_imports(root, ns, bricks)
3946

4047
if brick and imports.get(brick):
41-
deps.print_brick_deps(brick, bases, components, imports)
48+
deps.print_brick_deps(brick, bricks, imports, options)
4249
return
4350

44-
deps.print_deps(bases, components, imports)
51+
deps.print_deps(bricks, imports, options)

components/polylith/commands/info.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
from pathlib import Path
22

3-
from polylith import configuration, info, repo
3+
from polylith import configuration, info
44

55

6-
def run(short: bool):
7-
root = repo.get_workspace_root(Path.cwd())
8-
6+
def run(root: Path, options: dict):
97
ns = configuration.get_namespace_from_config(root)
108
bases = info.get_bases(root, ns)
119
components = info.get_components(root, ns)
1210
projects_data = info.get_bricks_in_projects(root, components, bases, ns)
1311

14-
info.print_workspace_summary(projects_data, bases, components)
12+
info.print_workspace_summary(projects_data, bases, components, options)
1513

1614
if not components and not bases:
1715
return
1816

19-
if short:
20-
info.print_compressed_view_for_bricks_in_projects(
21-
projects_data, bases, components
22-
)
23-
else:
24-
info.print_bricks_in_projects(projects_data, bases, components)
17+
info.print_bricks_in_projects(projects_data, bases, components, options)

components/polylith/commands/libs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,6 @@ def run(
6161
flattened: dict = reduce(flatten_imports, imports.values(), {})
6262

6363
report.print_libs_summary()
64-
report.print_libs_in_bricks(flattened)
64+
report.print_libs_in_bricks(flattened, options)
6565

6666
return {missing_libs(p, imports, options) for p in projects_data}

components/polylith/configuration/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from polylith.configuration.core import (
22
get_brick_structure_from_config,
33
get_namespace_from_config,
4+
get_output_dir,
45
get_resources_structure_from_config,
56
get_tag_pattern_from_config,
67
get_tag_sort_options_from_config,
@@ -13,6 +14,7 @@
1314
__all__ = [
1415
"get_brick_structure_from_config",
1516
"get_namespace_from_config",
17+
"get_output_dir",
1618
"get_resources_structure_from_config",
1719
"get_tag_pattern_from_config",
1820
"get_tag_sort_options_from_config",

components/polylith/configuration/core.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,18 @@ def get_resources_structure_from_config(path: Path) -> str:
8181
return "{brick}/{namespace}/{package}"
8282

8383
return "{brick}/{package}"
84+
85+
86+
def get_output_dir(path: Path, command_name: str) -> str:
87+
toml: dict = repo.load_workspace_config(path)
88+
89+
key = "output"
90+
91+
tool = toml["tool"]["polylith"]
92+
commands = tool.get("commands", {})
93+
command = commands.get(command_name, {})
94+
95+
output = command.get(key) or commands.get(key)
96+
fallback = f"{repo.development_dir}/poly"
97+
98+
return output or fallback

components/polylith/deps/report.py

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from functools import reduce
22
from itertools import zip_longest
3-
from typing import List, Set, Tuple
3+
from typing import List, Set, Tuple, Union
44

5+
from polylith import output
56
from polylith.reporting import theme
67
from rich import box
78
from rich.console import Console
@@ -57,15 +58,33 @@ def create_rows(
5758
return comp_rows + base_rows
5859

5960

60-
def print_deps(bases: Set[str], components: Set[str], import_data: dict):
61+
def find_longest_brick_name(bases: Set[str], components: Set[str]) -> str:
62+
bricks = set().union(bases, components)
63+
64+
return max(bricks, key=len)
65+
66+
67+
def calculate_brick_column_width(
68+
bases: Set[str], components: Set[str]
69+
) -> Union[int, None]:
70+
longest = find_longest_brick_name(bases, components)
71+
72+
return len(longest)
73+
74+
75+
def print_deps(bricks: dict, import_data: dict, options: dict):
76+
bases = bricks["bases"]
77+
components = bricks["components"]
6178
flattened = flatten_imports(import_data)
6279

6380
imported_bases = sorted({b for b in flattened if b in bases})
6481
imported_components = sorted({c for c in flattened if c in components})
6582
imported_bricks = imported_components + imported_bases
83+
save = options.get("save", False)
6684

6785
table = Table(box=box.SIMPLE_HEAD)
68-
table.add_column("[data]brick[/]")
86+
brick_width = calculate_brick_column_width(bases, components)
87+
table.add_column("[data]brick[/]", width=brick_width)
6988

7089
cols = create_columns(imported_bases, imported_components)
7190
rows = create_rows(bases, components, import_data, imported_bricks)
@@ -79,6 +98,9 @@ def print_deps(bases: Set[str], components: Set[str], import_data: dict):
7998
console = Console(theme=theme.poly_theme)
8099
console.print(table, overflow="ellipsis")
81100

101+
if save:
102+
output.save(table, options, "deps")
103+
82104

83105
def without(key: str, bricks: Set[str]) -> Set[str]:
84106
return {b for b in bricks if b != key}
@@ -111,9 +133,12 @@ def calculate_tag(brick: str, bases: Set[str]) -> str:
111133
return "base" if brick in bases else "comp"
112134

113135

114-
def print_brick_deps(
115-
brick: str, bases: Set[str], components: Set[str], import_data: dict
116-
):
136+
def print_brick_deps(brick: str, bricks: dict, import_data: dict, options: dict):
137+
bases = bricks["bases"]
138+
components = bricks["components"]
139+
140+
save = options.get("save", False)
141+
117142
brick_used_by = sorted_used_by(brick, bases, components, import_data)
118143
brick_uses = sorted_uses(brick, bases, components, import_data)
119144

@@ -142,3 +167,6 @@ def print_brick_deps(
142167
table.add_row(*row)
143168

144169
console.print(table, overflow="ellipsis")
170+
171+
if save:
172+
output.save(table, options, f"deps_{brick}")

components/polylith/info/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from polylith.info.report import (
99
is_project,
1010
print_bricks_in_projects,
11-
print_compressed_view_for_bricks_in_projects,
1211
print_workspace_summary,
1312
)
1413

@@ -20,6 +19,5 @@
2019
"get_projects_data",
2120
"is_project",
2221
"print_bricks_in_projects",
23-
"print_compressed_view_for_bricks_in_projects",
2422
"print_workspace_summary",
2523
]

components/polylith/info/report.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import List
22

3+
from polylith import output
34
from polylith.reporting import theme
45
from rich import box
56
from rich.console import Console
@@ -67,34 +68,31 @@ def build_bricks_in_projects_table(
6768
return table
6869

6970

70-
def print_table(table: Table) -> None:
71-
console = Console(theme=theme.poly_theme)
72-
73-
console.print(table, overflow="ellipsis")
74-
75-
76-
def print_compressed_view_for_bricks_in_projects(
77-
projects_data: List[dict], bases: List[str], components: List[str]
71+
def print_bricks_in_projects(
72+
projects_data: List[dict],
73+
bases: List[str],
74+
components: List[str],
75+
options: dict,
7876
) -> None:
79-
options = {"short": True}
8077
table = build_bricks_in_projects_table(projects_data, bases, components, options)
8178

82-
print_table(table)
83-
79+
save = options.get("save", False)
80+
console = Console(theme=theme.poly_theme)
8481

85-
def print_bricks_in_projects(
86-
projects_data: List[dict], bases: List[str], components: List[str]
87-
) -> None:
88-
options = {"short": False}
89-
table = build_bricks_in_projects_table(projects_data, bases, components, options)
82+
console.print(table, overflow="ellipsis")
9083

91-
print_table(table)
84+
if save:
85+
output.save(table, options, "info")
9286

9387

9488
def print_workspace_summary(
95-
projects_data: List[dict], bases: List[str], components: List[str]
89+
projects_data: List[dict],
90+
bases: List[str],
91+
components: List[str],
92+
options: dict,
9693
) -> None:
97-
console = Console(theme=theme.poly_theme)
94+
save = options.get("save", False)
95+
console = Console(theme=theme.poly_theme, record=save)
9896

9997
console.print(Padding("[data]Workspace summary[/]", (1, 0, 1, 0)))
10098

@@ -107,3 +105,6 @@ def print_workspace_summary(
107105
console.print(f"[comp]components[/]: [data]{number_of_components}[/]")
108106
console.print(f"[base]bases[/]: [data]{number_of_bases}[/]")
109107
console.print(f"[data]development[/]: [data]{number_of_dev}[/]")
108+
109+
if save:
110+
output.save_recorded(console, options, "workspace_summary")

0 commit comments

Comments
 (0)