From b4f7ab0c2913dec7a51f3a4330c3885c2f79de18 Mon Sep 17 00:00:00 2001 From: Lotem Amiel Date: Tue, 1 Aug 2023 17:06:40 +0300 Subject: [PATCH 1/2] Add Archive Bundler --- .../bundlers/archive_bundler.py | 63 ++++++++++++++++++ .../bundlers/bundler_manager.py | 2 + .../console/commands/bundle/archive.py | 64 +++++++++++++++++++ src/poetry_plugin_bundle/plugin.py | 3 +- 4 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/poetry_plugin_bundle/bundlers/archive_bundler.py create mode 100644 src/poetry_plugin_bundle/console/commands/bundle/archive.py diff --git a/src/poetry_plugin_bundle/bundlers/archive_bundler.py b/src/poetry_plugin_bundle/bundlers/archive_bundler.py new file mode 100644 index 0000000..6dd4930 --- /dev/null +++ b/src/poetry_plugin_bundle/bundlers/archive_bundler.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +import os.path +import tempfile +from pathlib import Path +from typing import TYPE_CHECKING + +from cleo.io.null_io import NullIO + +from poetry_plugin_bundle.bundlers.venv_bundler import VenvBundler + +if TYPE_CHECKING: + from typing import Self + + from cleo.io.io import IO + from poetry.poetry import Poetry + + +class ArchiveBundler(VenvBundler): + name = "archive" + + def __init__(self) -> None: + super().__init__() + self._ar_path = "output" + self._format = "zip" + self._site_packages_only = False + + def set_path(self, path: Path) -> Self: + self._ar_path = path + return self + + def set_format(self, ar_format: str) -> Self: + self._format = ar_format + + return self + + def set_site_packages_only(self, value: bool) -> Self: + self._site_packages_only = value + + return self + + def bundle(self, poetry: Poetry, io: IO) -> bool: + with tempfile.TemporaryDirectory() as temp_dir: + self._path = Path(temp_dir) + + if not super().bundle(poetry, NullIO()): + return False + + import shutil + + dir_path = self._path + if self._site_packages_only: + dir_path = os.path.join(dir_path, 'Lib', 'site-packages') + + self._write(io, f"Creating archive {self._ar_path} using format {self._format}") + + try: + shutil.make_archive(str(self._ar_path), self._format, dir_path) + except (ValueError, PermissionError) as e: + self._write(io, f"Error while creating archive: {e!s}") + return False + + return True diff --git a/src/poetry_plugin_bundle/bundlers/bundler_manager.py b/src/poetry_plugin_bundle/bundlers/bundler_manager.py index 353afe7..b14715f 100644 --- a/src/poetry_plugin_bundle/bundlers/bundler_manager.py +++ b/src/poetry_plugin_bundle/bundlers/bundler_manager.py @@ -12,11 +12,13 @@ class BundlerManager: def __init__(self) -> None: from poetry_plugin_bundle.bundlers.venv_bundler import VenvBundler + from poetry_plugin_bundle.bundlers.archive_bundler import ArchiveBundler self._bundler_classes: dict[str, type[Bundler]] = {} # Register default bundlers self.register_bundler_class(VenvBundler) + self.register_bundler_class(ArchiveBundler) def bundler(self, name: str) -> Bundler: if name.lower() not in self._bundler_classes: diff --git a/src/poetry_plugin_bundle/console/commands/bundle/archive.py b/src/poetry_plugin_bundle/console/commands/bundle/archive.py new file mode 100644 index 0000000..b7f5f3c --- /dev/null +++ b/src/poetry_plugin_bundle/console/commands/bundle/archive.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +from pathlib import Path +from typing import TYPE_CHECKING + +from cleo.helpers import argument +from cleo.helpers import option + +from poetry_plugin_bundle.console.commands.bundle.bundle_command import BundleCommand + + +if TYPE_CHECKING: + from poetry_plugin_bundle.bundlers.archive_bundler import ArchiveBundler + + +class BundleArchiveCommand(BundleCommand): + name = "bundle archive" + description = "Bundle the current project into an archive (.zip, .tar)" + + arguments = [ # noqa: RUF012 + argument("path", "Path to save archive in") + ] + + options = [ # noqa: RUF012 + *BundleCommand._group_dependency_options(), + option( + "python", + "p", + "The Python executable to use to create the virtual environment. " + "Defaults to the current Python executable", + flag=False, + value_required=True, + ), + option( + "clear", + None, + "Clear the existing virtual environment if it exists. ", + flag=True, + ), + option( + "format", + "f", + "Archive format as supported by shutil.make_archive", + flag=False, + default="zip" + ), + option( + "site-packages-only", + None, + "Only archive the Lib/site-packages directory", + flag=True, + ) + ] + + bundler_name = "archive" + + def configure_bundler(self, bundler: ArchiveBundler) -> None: # type: ignore[override] + bundler.set_path(Path(self.argument("path"))) + bundler.set_executable(self.option("python")) + bundler.set_remove(self.option("clear")) + bundler.set_activated_groups(self.activated_groups) + + bundler.set_format(self.option("format")) + bundler.set_site_packages_only(self.option("site-packages-only")) diff --git a/src/poetry_plugin_bundle/plugin.py b/src/poetry_plugin_bundle/plugin.py index 0900f91..8dd1ca1 100644 --- a/src/poetry_plugin_bundle/plugin.py +++ b/src/poetry_plugin_bundle/plugin.py @@ -7,6 +7,7 @@ from cleo.events.console_events import COMMAND from poetry.plugins.application_plugin import ApplicationPlugin +from poetry_plugin_bundle.console.commands.bundle.archive import BundleArchiveCommand from poetry_plugin_bundle.console.commands.bundle.venv import BundleVenvCommand @@ -19,7 +20,7 @@ class BundleApplicationPlugin(ApplicationPlugin): @property def commands(self) -> list[type[Command]]: - return [BundleVenvCommand] + return [BundleVenvCommand, BundleArchiveCommand] def activate(self, application: Application) -> None: assert application.event_dispatcher From 8f9819cbe09f7ad515dcf6814146c6452881a26b Mon Sep 17 00:00:00 2001 From: Lotem Amiel Date: Tue, 1 Aug 2023 17:18:42 +0300 Subject: [PATCH 2/2] Fix mypy, black and ruff --- .../bundlers/archive_bundler.py | 14 ++++++++------ .../bundlers/bundler_manager.py | 2 +- .../console/commands/bundle/archive.py | 12 ++++++------ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/poetry_plugin_bundle/bundlers/archive_bundler.py b/src/poetry_plugin_bundle/bundlers/archive_bundler.py index 6dd4930..3118146 100644 --- a/src/poetry_plugin_bundle/bundlers/archive_bundler.py +++ b/src/poetry_plugin_bundle/bundlers/archive_bundler.py @@ -1,7 +1,7 @@ from __future__ import annotations -import os.path import tempfile + from pathlib import Path from typing import TYPE_CHECKING @@ -9,11 +9,11 @@ from poetry_plugin_bundle.bundlers.venv_bundler import VenvBundler -if TYPE_CHECKING: - from typing import Self +if TYPE_CHECKING: from cleo.io.io import IO from poetry.poetry import Poetry + from typing_extensions import Self class ArchiveBundler(VenvBundler): @@ -21,7 +21,7 @@ class ArchiveBundler(VenvBundler): def __init__(self) -> None: super().__init__() - self._ar_path = "output" + self._ar_path = Path("output") self._format = "zip" self._site_packages_only = False @@ -50,9 +50,11 @@ def bundle(self, poetry: Poetry, io: IO) -> bool: dir_path = self._path if self._site_packages_only: - dir_path = os.path.join(dir_path, 'Lib', 'site-packages') + dir_path = dir_path.joinpath("Lib", "site-packages") - self._write(io, f"Creating archive {self._ar_path} using format {self._format}") + self._write( + io, f"Creating archive {self._ar_path} using format {self._format}" + ) try: shutil.make_archive(str(self._ar_path), self._format, dir_path) diff --git a/src/poetry_plugin_bundle/bundlers/bundler_manager.py b/src/poetry_plugin_bundle/bundlers/bundler_manager.py index b14715f..3576b75 100644 --- a/src/poetry_plugin_bundle/bundlers/bundler_manager.py +++ b/src/poetry_plugin_bundle/bundlers/bundler_manager.py @@ -11,8 +11,8 @@ class BundlerManager: def __init__(self) -> None: - from poetry_plugin_bundle.bundlers.venv_bundler import VenvBundler from poetry_plugin_bundle.bundlers.archive_bundler import ArchiveBundler + from poetry_plugin_bundle.bundlers.venv_bundler import VenvBundler self._bundler_classes: dict[str, type[Bundler]] = {} diff --git a/src/poetry_plugin_bundle/console/commands/bundle/archive.py b/src/poetry_plugin_bundle/console/commands/bundle/archive.py index b7f5f3c..f6019ba 100644 --- a/src/poetry_plugin_bundle/console/commands/bundle/archive.py +++ b/src/poetry_plugin_bundle/console/commands/bundle/archive.py @@ -17,9 +17,7 @@ class BundleArchiveCommand(BundleCommand): name = "bundle archive" description = "Bundle the current project into an archive (.zip, .tar)" - arguments = [ # noqa: RUF012 - argument("path", "Path to save archive in") - ] + arguments = [argument("path", "Path to save archive in")] # noqa: RUF012 options = [ # noqa: RUF012 *BundleCommand._group_dependency_options(), @@ -42,19 +40,21 @@ class BundleArchiveCommand(BundleCommand): "f", "Archive format as supported by shutil.make_archive", flag=False, - default="zip" + default="zip", ), option( "site-packages-only", None, "Only archive the Lib/site-packages directory", flag=True, - ) + ), ] bundler_name = "archive" - def configure_bundler(self, bundler: ArchiveBundler) -> None: # type: ignore[override] + def configure_bundler( + self, bundler: ArchiveBundler # type: ignore[override] + ) -> None: bundler.set_path(Path(self.argument("path"))) bundler.set_executable(self.option("python")) bundler.set_remove(self.option("clear"))