Skip to content
2 changes: 2 additions & 0 deletions bases/polylith/cli/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ def project_command(
"""Creates a Polylith project."""
create(name, description, _create_project)

project.interactive.run(name)


@app.command("workspace")
def workspace_command(
Expand Down
7 changes: 1 addition & 6 deletions components/polylith/commands/sync.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
from pathlib import Path

from polylith import info
from polylith import sync


def run(root: Path, ns: str, project_data: dict, options: dict):
is_quiet = options["quiet"]
is_verbose = options["verbose"]

bases = info.get_bases(root, ns)
components = info.get_components(root, ns)
workspace_data = {"bases": bases, "components": components}

diff = sync.calculate_diff(root, ns, project_data, workspace_data)
diff = sync.calculate_diff(root, ns, project_data)

sync.update_project(root, ns, diff)

Expand Down
2 changes: 2 additions & 0 deletions components/polylith/info/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from polylith.info.collect import (
find_unused_bases,
get_bases,
get_bricks_in_projects,
get_components,
Expand All @@ -12,6 +13,7 @@
)

__all__ = [
"find_unused_bases",
"get_bases",
"get_bricks_in_projects",
"get_components",
Expand Down
20 changes: 19 additions & 1 deletion components/polylith/info/collect.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import difflib
from pathlib import Path
from typing import List
from typing import List, Set

from polylith.bricks import base, component
from polylith.project import get_packages_for_projects, parse_package_paths
Expand Down Expand Up @@ -53,3 +54,20 @@ def get_projects_data(root: Path, ns: str) -> List[dict]:
components = get_components(root, ns)

return get_bricks_in_projects(root, components, bases, ns)


def find_unused_bases(root: Path, ns: str) -> Set[str]:
projects_data = get_projects_data(root, ns)

bases = get_bases(root, ns)
bases_in_projects = set().union(*[p["bases"] for p in projects_data])

return set(bases).difference(bases_in_projects)


def sort_bases_by_closest_match(bases: Set[str], name: str) -> List[str]:
closest = difflib.get_close_matches(name, bases, cutoff=0.3)

rest = sorted([b for b in bases if b not in closest])

return closest + rest
2 changes: 2 additions & 0 deletions components/polylith/poetry/commands/create_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ def handle(self) -> int:

create(name, description, create_project)

project.interactive.run(name)

return 0
3 changes: 2 additions & 1 deletion components/polylith/project/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from polylith.project import templates
from polylith.project import interactive, templates
from polylith.project.create import create_project
from polylith.project.get import (
get_packages_for_projects,
Expand All @@ -14,6 +14,7 @@
"get_project_name",
"get_project_template",
"get_toml",
"interactive",
"parse_package_paths",
"templates",
]
103 changes: 103 additions & 0 deletions components/polylith/project/interactive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
from pathlib import Path
from typing import List, Set

from polylith import configuration, info, repo, sync
from polylith.reporting import theme
from rich.console import Console
from rich.padding import Padding
from rich.prompt import Confirm, Prompt

console = Console(theme=theme.poly_theme)


def create_added_brick_message(bricks: Set[str], tag: str, project_name: str) -> str:
number_of_bricks = len(bricks)
plural = "s" if number_of_bricks > 1 else ""

if tag == "base":
grammar = f"base{plural}"
else:
grammar = f"component{plural}"

return f"[data]Added {number_of_bricks} [{tag}]{grammar}[/] to the [proj]{project_name}[/] project.[/]"


def confirmation(diff: dict, project_name: str) -> None:
pad = (1, 0, 0, 0)

if not diff:
nothing_added_message = f"[data]No bricks added to [proj]{project_name}[/][/]."
console.print(Padding(nothing_added_message, pad))

return

bases = diff["bases"]
components = diff["components"]

bases_message = create_added_brick_message(bases, "base", project_name)
console.print(Padding(bases_message, pad))

if len(components) == 0:
return

components_message = create_added_brick_message(components, "comp", project_name)
console.print(components_message)


def add_bricks_to_project(
root: Path,
ns: str,
project_name: str,
possible_bases: List[str],
) -> None:
projects_data = info.get_projects_data(root, ns)
project_data = next((p for p in projects_data if p["name"] == project_name), None)

if not project_data:
return

message = f"[data]Project [proj]{project_name}[/] created.[/]"
console.print(Padding(message, (0, 0, 1, 0)))

first, *_ = possible_bases

if not Confirm.ask(
prompt=f"[data]Do you want to add bricks to the [proj]{project_name}[/] project?[/]",
console=console,
):
return

question = "[data]What's the name of the Polylith [base]base[/] to add?[/]"

base = Prompt.ask(
prompt=question,
console=console,
default=first,
show_default=True,
case_sensitive=False,
)

all_bases = info.get_bases(root, ns)
found_base = next((b for b in all_bases if str.lower(b) == str.lower(base)), None)

if not found_base:
confirmation({}, project_name)
return

diff = sync.calculate_needed_bricks(root, ns, project_data, found_base)

sync.update_project(root, ns, diff)

confirmation(diff, project_name)


def run(project_name: str) -> None:
root = repo.get_workspace_root(Path.cwd())
ns = configuration.get_namespace_from_config(root)

possible_bases = sorted(info.find_unused_bases(root, ns))

if not possible_bases:
return

add_bricks_to_project(root, ns, project_name, possible_bases)
4 changes: 2 additions & 2 deletions components/polylith/sync/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from polylith.sync import report
from polylith.sync.collect import calculate_diff
from polylith.sync.collect import calculate_diff, calculate_needed_bricks
from polylith.sync.update import update_project

__all__ = ["report", "calculate_diff", "update_project"]
__all__ = ["report", "calculate_diff", "calculate_needed_bricks", "update_project"]
31 changes: 22 additions & 9 deletions components/polylith/sync/collect.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
from pathlib import Path
from typing import Set

from polylith import check, deps, info


def calculate_diff(
root: Path,
namespace: str,
project_data: dict,
workspace_data: dict,
) -> dict:
bases = set(project_data["bases"])
def _calculate(root: Path, namespace: str, project_data: dict, bases: Set[str]) -> dict:
components = set(project_data["components"])

all_bases = workspace_data["bases"]
all_components = workspace_data["components"]
all_bases = info.get_bases(root, namespace)
all_components = info.get_components(root, namespace)

brick_imports = deps.get_brick_imports(root, namespace, bases, components)
is_project = info.is_project(project_data)
Expand All @@ -35,3 +30,21 @@ def calculate_diff(
"components": components_diff,
"brick_imports": brick_imports,
}


def calculate_diff(root: Path, namespace: str, project_data: dict) -> dict:
bases = set(project_data["bases"])

return _calculate(root, namespace, project_data, bases)


def calculate_needed_bricks(
root: Path, namespace: str, project_data: dict, base: str
) -> dict:
bases = {base}

res = _calculate(root, namespace, project_data, bases)

needed_bases = res["bases"].union(bases)

return {**res, **{"bases": needed_bases}}
2 changes: 1 addition & 1 deletion projects/poetry_polylith_plugin/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "poetry-polylith-plugin"
version = "1.39.0"
version = "1.40.0"
description = "A Poetry plugin that adds tooling support for the Polylith Architecture"
authors = ["David Vujic"]
homepage = "https://davidvujic.github.io/python-polylith-docs/"
Expand Down
2 changes: 1 addition & 1 deletion projects/polylith_cli/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "polylith-cli"
version = "1.32.0"
version = "1.33.0"
description = "Python tooling support for the Polylith Architecture"
authors = ['David Vujic']
homepage = "https://davidvujic.github.io/python-polylith-docs/"
Expand Down