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
89 changes: 89 additions & 0 deletions bases/polylith/cli/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from pathlib import Path

import tomlkit
from polylith import building, repo, toml
from polylith.cli import options
from typer import Exit, Typer
from typing_extensions import Annotated

app = Typer()


def get_work_dir(root: Path, directory: str) -> Path:
work_dir = building.get_work_dir({})
work_path = Path(directory) / work_dir if directory else work_dir

return root / work_path


def get_build_dir(root: Path, directory: str) -> Path:
return root / Path(directory) if directory else root


def get_project_data(build_dir: Path) -> tomlkit.TOMLDocument:
fullpath = build_dir / repo.default_toml

if not fullpath.exists():
raise Exit(code=1)

return toml.read_toml_document(fullpath)


@app.command("setup")
def setup_command(directory: Annotated[str, options.directory] = ""):
"""Prepare a project before building a wheel or a source distribution (sdist).
Run it before the build command of your Package & Dependency Management tool.

"""
root = Path.cwd()
build_dir = get_build_dir(root, directory)
print(f"Build directory: {build_dir}")

data = get_project_data(build_dir)
bricks = toml.get_project_packages_from_polylith_section(data)

if not bricks:
print("No bricks found.")
return

bricks_with_paths = {build_dir / k: v for k, v in bricks.items()}
custom_top_ns = toml.get_custom_top_namespace_from_polylith_section(data)

if not custom_top_ns:
building.copy_bricks_as_is(bricks_with_paths, build_dir)
else:
work_dir = get_work_dir(root, directory)
print(f"Using temporary working directory: {work_dir}")

rewritten = building.copy_and_rewrite_bricks(
bricks_with_paths, custom_top_ns, work_dir, build_dir
)

for item in rewritten:
print(f"Updated {item} with new top namespace for local imports.")


@app.command("teardown")
def teardown_command(directory: Annotated[str, options.directory] = ""):
"""Clean up temporary directories. Run it after the build command of your Package & Dependency Management tool."""
root = Path.cwd()

work_dir = get_work_dir(root, directory)
build_dir = get_build_dir(root, directory)

data = get_project_data(build_dir)
bricks = toml.get_project_packages_from_polylith_section(data)

if not bricks:
return

destination_dir = building.calculate_destination_dir(data)

if work_dir.exists():
print(f"Removing temporary working directory: {work_dir}")
building.cleanup(work_dir)

if destination_dir:
destination_path = build_dir / destination_dir
print(f"Removing bricks path used during build: {destination_path}")
building.cleanup(destination_path)
9 changes: 8 additions & 1 deletion bases/polylith/cli/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import List, Union

from polylith import commands, configuration, info, repo
from polylith.cli import create, options
from polylith.cli import build, create, options
from typer import Exit, Option, Typer
from typing_extensions import Annotated

Expand All @@ -15,6 +15,13 @@
)


app.add_typer(
build.app,
name="build",
help="For Package & Dependency Management tools without support for plugins or build hooks.",
)


def filtered_projects_data(
projects_data: List[dict], directory: Union[str, None]
) -> List[dict]:
Expand Down
10 changes: 10 additions & 0 deletions components/polylith/building/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from polylith.building.core import cleanup, copy_and_rewrite_bricks, copy_bricks_as_is
from polylith.building.paths import calculate_destination_dir, get_work_dir

__all__ = [
"calculate_destination_dir",
"cleanup",
"copy_and_rewrite_bricks",
"copy_bricks_as_is",
"get_work_dir",
]
47 changes: 47 additions & 0 deletions components/polylith/building/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import operator
import shutil
from functools import reduce
from pathlib import Path
from typing import List

from polylith import parsing


def copy_bricks_as_is(bricks: dict, build_dir: Path) -> None:
for source, brick in bricks.items():
parsing.copy_brick(source, brick, build_dir)


def copy_and_rewrite(source: str, brick: str, options: dict) -> List[str]:
work_dir = options["work_dir"]
build_dir = options["build_dir"]
top_ns = options["top_ns"]
ns = options["ns"]

path = parsing.copy_brick(source, brick, work_dir)
rewritten = parsing.rewrite_modules(path, ns, top_ns)

destination_dir = build_dir / top_ns
parsing.copy_brick(path.as_posix(), brick, destination_dir)

return rewritten


def copy_and_rewrite_bricks(
bricks: dict, top_ns: str, work_dir: Path, build_dir: Path
) -> List[str]:
ns = parsing.parse_brick_namespace_from_path(bricks)

options = {"ns": ns, "top_ns": top_ns, "work_dir": work_dir, "build_dir": build_dir}

res = [copy_and_rewrite(source, brick, options) for source, brick in bricks.items()]
flattened: List[str] = reduce(operator.iadd, res, [])

return sorted(flattened)


def cleanup(work_dir: Path) -> None:
if not work_dir.exists() or not work_dir.is_dir():
return

shutil.rmtree(work_dir.as_posix())
32 changes: 32 additions & 0 deletions components/polylith/building/paths.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from pathlib import Path
from typing import Union

from polylith import toml


def get_work_dir(options: dict) -> Path:
work_dir = options.get("work-dir", ".polylith_tmp")

return Path(work_dir)


def calculate_root_dir(bricks: dict) -> Union[str, None]:
brick_path = next((v for v in bricks.values()), None)

return str.split(brick_path, "/")[0] if brick_path else None


def calculate_destination_dir(data: dict) -> Union[Path, None]:
bricks = toml.get_project_packages_from_polylith_section(data)

if not bricks:
return None

custom_top_ns = toml.get_custom_top_namespace_from_polylith_section(data)

if custom_top_ns:
return Path(custom_top_ns)

root = calculate_root_dir(bricks)

return Path(root) if root else None
6 changes: 2 additions & 4 deletions components/polylith/hatch/core.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
from pathlib import Path
from typing import Union

from polylith import toml
from polylith import building, toml


def get_work_dir(config: dict) -> Path:
work_dir = config.get("work-dir", ".polylith_tmp")

return Path(work_dir)
return building.get_work_dir(config)


def get_top_namespace(pyproject: dict, config: dict) -> Union[str, None]:
Expand Down
32 changes: 8 additions & 24 deletions components/polylith/pdm/core.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,24 @@
import shutil
from pathlib import Path

from polylith import parsing
from polylith import building


def get_work_dir(config: dict) -> Path:
build_config = config.get("tool", {}).get("pdm", {}).get("build", {})

work_dir = build_config.get("work-dir", ".polylith_tmp")

return Path(work_dir)
return building.get_work_dir(build_config)


def copy_bricks_as_is(bricks: dict, build_dir: Path) -> None:
for source, brick in bricks.items():
parsing.copy_brick(source, brick, build_dir)
building.copy_bricks_as_is(bricks, build_dir)


def copy_and_rewrite_bricks(
def copy_and_rewrite(
bricks: dict, top_ns: str, work_dir: Path, build_dir: Path
) -> None:
ns = parsing.parse_brick_namespace_from_path(bricks)

for source, brick in bricks.items():
path = parsing.copy_brick(source, brick, work_dir)
rewritten_bricks = parsing.rewrite_modules(path, ns, top_ns)

destination_dir = build_dir / top_ns
parsing.copy_brick(path.as_posix(), brick, destination_dir)

for item in rewritten_bricks:
print(f"Updated {item} with new top namespace for local imports.")

rewritten = building.copy_and_rewrite_bricks(bricks, top_ns, work_dir, build_dir)

def cleanup(work_dir: Path) -> None:
if not work_dir.exists() or not work_dir.is_dir():
return
for item in rewritten:
print(f"Updated {item} with new top namespace for local imports.")

shutil.rmtree(work_dir.as_posix())
building.cleanup(work_dir)
3 changes: 1 addition & 2 deletions components/polylith/pdm/hooks/bricks.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,4 @@ def build_initialize(root: Path, config_data: dict, build_dir: Path) -> None:
if not top_ns:
core.copy_bricks_as_is(bricks, build_dir)
else:
core.copy_and_rewrite_bricks(bricks, top_ns, work_dir, build_dir)
core.cleanup(work_dir)
core.copy_and_rewrite(bricks, top_ns, work_dir, build_dir)
Loading