diff --git a/snapcraft/application.py b/snapcraft/application.py index df84454fa8..f8fd99f980 100644 --- a/snapcraft/application.py +++ b/snapcraft/application.py @@ -135,9 +135,6 @@ def _register_default_plugins(self) -> None: """Register per application plugins when initializing.""" super()._register_default_plugins() - # poetry plugin needs integration work, see #5025 - craft_parts.plugins.unregister("poetry") - if self._known_core24: # dotnet is disabled for core24 and newer because it is pending a rewrite craft_parts.plugins.unregister("dotnet") diff --git a/snapcraft/parts/plugins/python_common.py b/snapcraft/parts/plugins/python_common.py new file mode 100644 index 0000000000..127d896487 --- /dev/null +++ b/snapcraft/parts/plugins/python_common.py @@ -0,0 +1,55 @@ +# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- +# +# Copyright 2023-2024 Canonical Ltd. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +"""Common functions for Python-based Snapcraft plugins.""" +import logging +from pathlib import Path + +from craft_parts import StepInfo + +logger = logging.getLogger(__name__) + + +def post_prime(step_info: StepInfo) -> None: + """Perform Python-specific actions right before packing.""" + base = step_info.project_base + + if base in ("core20", "core22"): + # Only fix pyvenv.cfg on core24+ snaps + return + + root_path: Path = step_info.prime_dir + + pyvenv = root_path / "pyvenv.cfg" + if not pyvenv.is_file(): + return + + snap_path = Path(f"/snap/{step_info.project_name}/current") + new_home = f"home = {snap_path}" + + candidates = ( + step_info.part_install_dir, + step_info.stage_dir, + ) + + old_contents = contents = pyvenv.read_text() + for candidate in candidates: + old_home = f"home = {candidate}" + contents = contents.replace(old_home, new_home) + + if old_contents != contents: + logger.debug("Updating pyvenv.cfg to:\n%s", contents) + pyvenv.write_text(contents) diff --git a/snapcraft/services/lifecycle.py b/snapcraft/services/lifecycle.py index 61f8f95472..38a5b8efa1 100644 --- a/snapcraft/services/lifecycle.py +++ b/snapcraft/services/lifecycle.py @@ -94,7 +94,7 @@ def post_prime(self, step_info: StepInfo) -> bool: plugin_name = project.parts[part_name]["plugin"] # Handle plugin-specific prime fixes - if plugin_name == "python": + if plugin_name in ("python", "poetry"): plugins.PythonPlugin.post_prime(step_info) # Handle patch-elf diff --git a/tests/spread/core24/python-hello/poetry/snap/snapcraft.yaml b/tests/spread/core24/python-hello/poetry/snap/snapcraft.yaml new file mode 100644 index 0000000000..025dab575a --- /dev/null +++ b/tests/spread/core24/python-hello/poetry/snap/snapcraft.yaml @@ -0,0 +1,14 @@ +name: python-hello-poetry +version: "1.0" +summary: simple python application +description: build a python application using core24 +base: core24 +confinement: strict + +apps: + python-hello-strict: + command: bin/hello +parts: + hello: + plugin: poetry + source: src diff --git a/tests/spread/core24/python-hello/poetry/src/pyproject.toml b/tests/spread/core24/python-hello/poetry/src/pyproject.toml new file mode 100644 index 0000000000..eef363c29b --- /dev/null +++ b/tests/spread/core24/python-hello/poetry/src/pyproject.toml @@ -0,0 +1,18 @@ +[tool.poetry] +name = "hello" +version = "0.1.0" +description = "" +authors = ["Your Name "] + +[tool.poetry.dependencies] +python = "^3.10" +black = "^24.8.0" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry.scripts] +hello = "hello:main" diff --git a/tests/spread/core24/python-hello/task.yaml b/tests/spread/core24/python-hello/task.yaml index 2db4043b9e..47a434462b 100644 --- a/tests/spread/core24/python-hello/task.yaml +++ b/tests/spread/core24/python-hello/task.yaml @@ -8,6 +8,7 @@ systems: environment: PARAM/strict: "" PARAM/classic: "--classic" + PARAM/poetry: "" restore: | cd ./"${SPREAD_VARIANT}" diff --git a/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/snap/snapcraft.yaml b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/snap/snapcraft.yaml new file mode 100644 index 0000000000..e3471b76dc --- /dev/null +++ b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/snap/snapcraft.yaml @@ -0,0 +1,15 @@ +name: python-hello +version: "1.0" +summary: simple python application +description: build a python application using core22 +base: core22 +confinement: strict + +apps: + python-hello: + command: bin/hello + +parts: + hello: + plugin: poetry + source: src diff --git a/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/hello/__init__.py b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/hello/__init__.py new file mode 100644 index 0000000000..e3095b2229 --- /dev/null +++ b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/hello/__init__.py @@ -0,0 +1,2 @@ +def main(): + print("hello world") diff --git a/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/pyproject.toml b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/pyproject.toml new file mode 100644 index 0000000000..eef363c29b --- /dev/null +++ b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/pyproject.toml @@ -0,0 +1,18 @@ +[tool.poetry] +name = "hello" +version = "0.1.0" +description = "" +authors = ["Your Name "] + +[tool.poetry.dependencies] +python = "^3.10" +black = "^24.8.0" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry.scripts] +hello = "hello:main" diff --git a/tests/spread/plugins/craft-parts/build-and-run-hello/task.yaml b/tests/spread/plugins/craft-parts/build-and-run-hello/task.yaml index bbb9bbea02..01b9eb9aa2 100644 --- a/tests/spread/plugins/craft-parts/build-and-run-hello/task.yaml +++ b/tests/spread/plugins/craft-parts/build-and-run-hello/task.yaml @@ -8,6 +8,7 @@ environment: SNAP/colcon_ros2_wrapper: colcon-ros2-wrapper SNAP/flutter: flutter-hello SNAP/python: python-hello + SNAP/poetry: poetry-hello SNAP/qmake: qmake-hello SNAP/maven: maven-hello SNAP/dotnet: dotnet-hello diff --git a/tests/unit/parts/plugins/test_python_plugin.py b/tests/unit/parts/plugins/test_python_plugin.py index d41f6d295a..ed357cd3fe 100644 --- a/tests/unit/parts/plugins/test_python_plugin.py +++ b/tests/unit/parts/plugins/test_python_plugin.py @@ -19,7 +19,7 @@ import pytest from craft_parts import Part, PartInfo, ProjectInfo, Step, StepInfo, errors -from snapcraft.parts.plugins import PythonPlugin +from snapcraft.parts.plugins import PythonPlugin, python_common @pytest.fixture @@ -224,7 +224,7 @@ def test_fix_pyvenv(new_dir, home_attr): step_info = StepInfo(part_info, Step.PRIME) - PythonPlugin.post_prime(step_info) + python_common.post_prime(step_info) new_contents = pyvenv.read_text() assert "home = /snap/test-snap/current/usr/bin" in new_contents