Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(merge): '8.3.2' into 'main' #4953

Merged
merged 7 commits into from
Aug 6, 2024
Merged
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
37 changes: 37 additions & 0 deletions docs/reference/changelog.rst
Original file line number Diff line number Diff line change
@@ -77,6 +77,40 @@ Changelog

For a complete list of commits, check out the `X.Y.Z`_ release on GitHub.


8.3.2 (2024-Aug-05)
-------------------

Core
====

Bases
#####

core24
""""""

* Fix a bug where classic snaps with a Python virtual environment would attempt
to use the system's Python intepretter (`#4942`_).

Plugins
#######

Kernel
""""""

* Fix a bug where removing a missing symlink would cause the kernel plugin
to fail.

Store
=====

* Fix a bug where ``edit-validation-sets`` would fail when editing a validation
sets with snap revisions (`#4909`_).

For a complete list of commits, check out the `8.3.2`_ release on GitHub.


8.3.1 (2024-Jul-08)
-------------------

@@ -964,6 +998,8 @@ For a complete list of commits, check out the `8.0.0`_ release on GitHub.
.. _#4886: https://github.com/canonical/snapcraft/issues/4886
.. _#4889: https://github.com/canonical/snapcraft/issues/4889
.. _#4890: https://github.com/canonical/snapcraft/issues/4890
.. _#4909: https://github.com/canonical/snapcraft/issues/4909
.. _#4942: https://github.com/canonical/snapcraft/issues/4942

.. _8.0.0: https://github.com/canonical/snapcraft/releases/tag/8.0.0
.. _8.0.1: https://github.com/canonical/snapcraft/releases/tag/8.0.1
@@ -987,3 +1023,4 @@ For a complete list of commits, check out the `8.0.0`_ release on GitHub.
.. _8.2.12: https://github.com/canonical/snapcraft/releases/tag/8.2.12
.. _8.3.0: https://github.com/canonical/snapcraft/releases/tag/8.3.0
.. _8.3.1: https://github.com/canonical/snapcraft/releases/tag/8.3.1
.. _8.3.2: https://github.com/canonical/snapcraft/releases/tag/8.3.2
35 changes: 34 additions & 1 deletion snapcraft/parts/plugins/python_plugin.py
Original file line number Diff line number Diff line change
@@ -17,9 +17,10 @@
"""The Snapcraft Python plugin."""

import logging
from pathlib import Path
from typing import Optional

from craft_parts import errors
from craft_parts import StepInfo, errors
from craft_parts.plugins import python_plugin
from overrides import override

@@ -64,3 +65,35 @@ def _get_system_python_interpreter(self) -> Optional[str]:
confinement,
)
return interpreter

@classmethod
def post_prime(cls, 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)
12 changes: 12 additions & 0 deletions snapcraft/services/lifecycle.py
Original file line number Diff line number Diff line change
@@ -77,6 +77,7 @@ def setup(self) -> None:
extra_build_snaps=project.get_extra_build_snaps(),
confinement=project.confinement,
project_base=project.base or "",
project_name=project.name,
)
callbacks.register_prologue(parts.set_global_environment)
callbacks.register_pre_step(parts.set_step_environment)
@@ -85,8 +86,19 @@ def setup(self) -> None:
@overrides
def post_prime(self, step_info: StepInfo) -> bool:
"""Run post-prime parts steps for Snapcraft."""
from snapcraft.parts import plugins

project = cast(models.Project, self._project)

part_name = step_info.part_name
plugin_name = project.parts[part_name]["plugin"]

# Handle plugin-specific prime fixes
if plugin_name == "python":
plugins.PythonPlugin.post_prime(step_info)

# Handle patch-elf

# do not use system libraries in classic confinement
use_system_libs = not bool(project.confinement == "classic")

Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ execute: |
cat "$file"
for exp in \
"^SNAPCRAFT_PROJECT_GRADE=devel$" \
"^SNAPCRAFT_PROJECT_NAME=None$" \
"^SNAPCRAFT_PROJECT_NAME=variables$" \
"^SNAPCRAFT_PROJECT_VERSION=1$" \
"^SNAPCRAFT_PARALLEL_BUILD_COUNT=[0-9]\+$" \
"^SNAPCRAFT_PROJECT_DIR=${root}$" \
3 changes: 3 additions & 0 deletions tests/spread/core24/python-hello/classic/snap/snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -16,10 +16,13 @@ parts:
hello:
plugin: python
source: src
python-packages:
- black
build-attributes:
- enable-patchelf
stage-packages:
- libpython3.12-minimal
- libpython3.12-stdlib
- python3.12-minimal
- python3.12-venv
- python3-minimal # (for the "python3" symlink)
5 changes: 4 additions & 1 deletion tests/spread/core24/python-hello/src/hello/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
import black


def main():
print("hello world")
print(f"hello world! black version: {black.__version__}")
2 changes: 2 additions & 0 deletions tests/spread/core24/python-hello/strict/snap/snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -12,3 +12,5 @@ parts:
hello:
plugin: python
source: src
python-packages:
- black
7 changes: 6 additions & 1 deletion tests/spread/core24/python-hello/task.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
summary: Build and run Python-based snaps in core24

systems:
# Must *not* run this on 24.04, which can give false-positives due to the
# presence of the system Python 3.12.
- ubuntu-22.04*

environment:
PARAM/strict: ""
PARAM/classic: "--classic"
@@ -17,4 +22,4 @@ execute: |
# shellcheck disable=SC2086
snap install python-hello-"${SPREAD_VARIANT}"_1.0_*.snap --dangerous ${PARAM}

python-hello-"${SPREAD_VARIANT}" | MATCH "hello world"
python-hello-"${SPREAD_VARIANT}" | MATCH "hello world! black version"
40 changes: 39 additions & 1 deletion tests/unit/parts/plugins/test_python_plugin.py
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
from textwrap import dedent

import pytest
from craft_parts import Part, PartInfo, ProjectInfo, errors
from craft_parts import Part, PartInfo, ProjectInfo, Step, StepInfo, errors

from snapcraft.parts.plugins import PythonPlugin

@@ -190,3 +190,41 @@ def test_get_system_python_interpreter_unknown_base(confinement, new_dir):
expected_error = "Don't know which interpreter to use for base core10"
with pytest.raises(errors.PartsError, match=expected_error):
plugin._get_system_python_interpreter()


@pytest.mark.parametrize("home_attr", ["part_install_dir", "stage_dir"])
def test_fix_pyvenv(new_dir, home_attr):
part_info = PartInfo(
project_info=ProjectInfo(
application_name="test",
project_name="test-snap",
base="core24",
confinement="classic",
project_base="core24",
cache_dir=new_dir,
),
part=Part("my-part", {"plugin": "python"}),
)

prime_dir = part_info.prime_dir
prime_dir.mkdir()

pyvenv = prime_dir / "pyvenv.cfg"
pyvenv.write_text(
dedent(
f"""\
home = {getattr(part_info, home_attr)}/usr/bin
include-system-site-packages = false
version = 3.12.3
executable = /root/parts/my-part/install/usr/bin/python3.12
command = /root/parts/my-part/install/usr/bin/python3 -m venv /root/parts/my-part/install
"""
)
)

step_info = StepInfo(part_info, Step.PRIME)

PythonPlugin.post_prime(step_info)

new_contents = pyvenv.read_text()
assert "home = /snap/test-snap/current/usr/bin" in new_contents
10 changes: 8 additions & 2 deletions tests/unit/services/test_lifecycle.py
Original file line number Diff line number Diff line change
@@ -43,14 +43,18 @@ def test_lifecycle_installs_base(lifecycle_service, mocker):
)


def test_post_prime_no_patchelf(fp, tmp_path, lifecycle_service):
def test_post_prime_no_patchelf(fp, tmp_path, lifecycle_service, default_project):
new_attrs = {"parts": {"my-part": {"plugin": "nil"}}}
default_project.__dict__.update(**new_attrs)

mock_step_info = mock.Mock()
mock_step_info.configure_mock(
**{
"base": "core24",
"build_attributes": [],
"state.files": ["usr/bin/ls"],
"prime_dir": tmp_path / "prime",
"part_name": "my-part",
}
)

@@ -82,7 +86,7 @@ def test_post_prime_patchelf(
use_system_libs,
):
patchelf_spy = mocker.spy(snapcraft.parts, "patch_elf")
new_attrs = {"confinement": confinement}
new_attrs = {"confinement": confinement, "parts": {"my-part": {"plugin": "nil"}}}
default_project.__dict__.update(**new_attrs)

mock_step_info = mock.Mock()
@@ -92,6 +96,7 @@ def test_post_prime_patchelf(
"build_attributes": ["enable-patchelf"],
"state.files": ["usr/bin/ls"],
"prime_dir": tmp_path / "prime",
"part_name": "my-part",
}
)

@@ -207,6 +212,7 @@ def test_lifecycle_custom_arguments(

assert info.project_base == expected_base
assert info.confinement == expected_confinement
assert info.project_name == default_project.name == "default"


@pytest.mark.usefixtures("default_project")
Loading