Skip to content

Commit

Permalink
chore: 7.5.3 hotfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
sergiusens authored Sep 8, 2023
2 parents 2eddbfe + 7b8341e commit 184730f
Show file tree
Hide file tree
Showing 13 changed files with 245 additions and 9 deletions.
3 changes: 3 additions & 0 deletions snapcraft/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

import pkg_resources

# For legacy compatibility
import snapcraft.sources # noqa: F401


def _get_version():
if os.environ.get("SNAP_NAME") == "snapcraft":
Expand Down
3 changes: 3 additions & 0 deletions snapcraft/parts/lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ def _run_lifecycle_and_pack(
step_name,
shell=getattr(parsed_args, "shell", False),
shell_after=getattr(parsed_args, "shell_after", False),
# Repriming needs to happen to take into account any changes to
# the actual target directory.
rerun_step=command_name == "try",
)

# Extract metadata and generate snap.yaml
Expand Down
14 changes: 14 additions & 0 deletions snapcraft/parts/parts.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,14 @@ def run(
*,
shell: bool = False,
shell_after: bool = False,
rerun_step: bool = False,
) -> None:
"""Run the parts lifecycle.
:param target_step: The final step to execute.
:param shell: Enter a shell instead of running step_name.
:param shell_after: Enter a shell after running step_name.
:param rerun_step: Force running step_name.
:raises PartsLifecycleError: On error during lifecycle.
:raises RuntimeError: On unexpected error.
Expand All @@ -171,6 +175,16 @@ def run(

with self._lcm.action_executor() as aex:
for action in actions:
# Workaround until canonical/craft-parts#540 is fixed
if action.step == target_step and rerun_step:
action = craft_parts.Action(
part_name=action.part_name,
step=action.step,
action_type=ActionType.RERUN,
reason="forced rerun",
project_vars=action.project_vars,
properties=action.properties,
)
message = _action_message(action)
emit.progress(f"Executing parts lifecycle: {message}")
with emit.open_stream("Executing action") as stream:
Expand Down
4 changes: 3 additions & 1 deletion snapcraft/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,9 @@ def _validate_list_stream(cls, listen_stream):
f"{listen_stream!r} is not an integer between 1 and 65535 (inclusive)."
)
elif isinstance(listen_stream, str):
if not re.match(r"^[A-Za-z0-9/._#:$-]*$", listen_stream):
if not listen_stream.startswith("@snap.") and not re.match(
r"^[A-Za-z0-9/._#:$-]*$", listen_stream
):
raise ValueError(
f"{listen_stream!r} is not a valid socket path (e.g. /tmp/mysocket.sock)."
)
Expand Down
26 changes: 26 additions & 0 deletions snapcraft/sources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2023 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 <http://www.gnu.org/licenses/>.

"""Legacy support for local plugins."""

import sys as _sys

if _sys.platform == "linux":
from snapcraft_legacy.sources import get

__all__ = [
"get",
]
24 changes: 24 additions & 0 deletions tests/spread/core22/set-version-twice/modified-snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: test-set-version-twice
base: core22
version: '0.1'
summary: Test fix for set version and out of order step execution
description: |
As described in https://bugs.launchpad.net/snapcraft/+bug/1831135/comments/10,
a bug in craft-parts caused unexpected double setting of project variables
such as `version`. Make sure this scenario builds correctly.
adopt-info: part1

grade: devel
confinement: devmode

parts:
part1:
plugin: nil
override-pull: |
craftctl default
craftctl set version=xx
echo
part2:
plugin: nil
after: [part1]
23 changes: 23 additions & 0 deletions tests/spread/core22/set-version-twice/original-snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: test-set-version-twice
base: core22
version: '0.1'
summary: Test fix for set version and out of order step execution
description: |
As described in https://bugs.launchpad.net/snapcraft/+bug/1831135/comments/10,
a bug in craft-parts caused unexpected double setting of project variables
such as `version`. Make sure this scenario builds correctly.
adopt-info: part1

grade: devel
confinement: devmode

parts:
part1:
plugin: nil
override-pull: |
craftctl default
craftctl set version=xx
part2:
plugin: nil
after: [part1]
29 changes: 29 additions & 0 deletions tests/spread/core22/set-version-twice/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
summary: Test fix for version setting corner case

prepare: |
#shellcheck source=tests/spread/tools/snapcraft-yaml.sh
. "$TOOLS_DIR/snapcraft-yaml.sh"
restore: |
snapcraft clean
rm -Rf subdir ./*.snap
rm -f snap/*.yaml
#shellcheck source=tests/spread/tools/snapcraft-yaml.sh
. "$TOOLS_DIR/snapcraft-yaml.sh"
execute: |
mkdir -p snap
cp original-snapcraft.yaml snap/snapcraft.yaml
snapcraft prime
cp modified-snapcraft.yaml snap/snapcraft.yaml
snapcraft build part2
snapcraft prime
cp original-snapcraft.yaml snap/snapcraft.yaml
snapcraft build part2
snapcraft prime
5 changes: 4 additions & 1 deletion tests/spread/core22/try/task.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ execute: |
chmod a+w prime
unset SNAPCRAFT_BUILD_ENVIRONMENT
# Prime first to regression test snapcore/snapcraft#4219
snapcraft prime --use-lxd
# Followed by the actual try
snapcraft try --use-lxd
find prime/meta/snap.yaml
find prime/usr/bin/hello
snap try prime
hello-try | MATCH "Hello, world"
snap remove hello-try
snap remove hello-try
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2023 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 <http://www.gnu.org/licenses/>.

import snapcraft
from snapcraft.plugins.v1 import PluginV1


class LocalPlugin(PluginV1):
@classmethod
def schema(cls):
schema = super().schema()

schema["properties"]["foo"] = {"type": "string"}

return schema

@classmethod
def get_pull_properties(cls):
return ["foo", "stage-packages"]

@classmethod
def get_build_properties(cls):
return ["foo", "stage-packages"]

def pull(self):
super().pull()
print(snapcraft.sources.get)

def build(self):
return self.run(["touch", "build-stamp"], self.installdir)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: test-local-plugins
base: core18
version: "0.1"
summary: local plugin using snapcraft.sources.get
description: Tests if local plugins load and can build
confinement: strict
grade: devel

parts:
x-local-plugin:
plugin: x-local-plugin
source: .
50 changes: 45 additions & 5 deletions tests/unit/parts/test_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,45 @@ def test_lifecycle_run_command_step(
parsed_args=parsed_args,
)

call_args = {"shell": False, "shell_after": False}
call_args = {"shell": False, "shell_after": False, "rerun_step": False}
if debug_shell:
call_args[debug_shell] = True

assert run_mock.mock_calls == [call(step, **call_args)]


def test_lifecycle_run_try_command(snapcraft_yaml, project_vars, new_dir, mocker):
project = Project.unmarshal(snapcraft_yaml(base="core22"))
run_mock = mocker.patch("snapcraft.parts.PartsLifecycle.run")
mocker.patch("snapcraft.meta.snap_yaml.write")
mocker.patch("snapcraft.pack.pack_snap")

parsed_args = argparse.Namespace(
debug=False,
destructive_mode=True,
enable_manifest=False,
shell=False,
shell_after=False,
use_lxd=False,
ua_token=None,
parts=[],
)

parts_lifecycle._run_command(
"try",
project=project,
parse_info={},
assets_dir=Path(),
start_time=datetime.now(),
parallel_build_count=8,
parsed_args=parsed_args,
)

assert run_mock.mock_calls == [
call("prime", shell=False, shell_after=False, rerun_step=True)
]


@pytest.mark.parametrize("managed_mode", [True, False])
@pytest.mark.parametrize("build_env", [None, "host", "multipass", "lxd", "other"])
@pytest.mark.parametrize("cmd", ["pack", "snap"])
Expand Down Expand Up @@ -356,7 +388,9 @@ def test_lifecycle_run_local_destructive_mode(
)

assert run_in_provider_mock.mock_calls == []
assert run_mock.mock_calls == [call("prime", shell=False, shell_after=False)]
assert run_mock.mock_calls == [
call("prime", shell=False, shell_after=False, rerun_step=False)
]
assert pack_mock.mock_calls[:1] == [
call(
new_dir / "home/prime" if managed_mode else new_dir / "prime",
Expand Down Expand Up @@ -419,7 +453,9 @@ def test_lifecycle_run_local_managed_mode(
)

assert run_in_provider_mock.mock_calls == []
assert run_mock.mock_calls == [call("prime", shell=False, shell_after=False)]
assert run_mock.mock_calls == [
call("prime", shell=False, shell_after=False, rerun_step=False)
]
assert pack_mock.mock_calls[:1] == [
call(
new_dir / "home/prime",
Expand Down Expand Up @@ -482,7 +518,9 @@ def test_lifecycle_run_local_build_env(
)

assert run_in_provider_mock.mock_calls == []
assert run_mock.mock_calls == [call("prime", shell=False, shell_after=False)]
assert run_mock.mock_calls == [
call("prime", shell=False, shell_after=False, rerun_step=False)
]
assert pack_mock.mock_calls[:1] == [
call(
new_dir / "home/prime" if managed_mode else new_dir / "prime",
Expand Down Expand Up @@ -656,7 +694,9 @@ def test_lifecycle_pack_metadata_error(cmd, snapcraft_yaml, new_dir, mocker):
assert str(raised.value) == (
"error setting grade: unexpected value; permitted: 'stable', 'devel'"
)
assert run_mock.mock_calls == [call("prime", shell=False, shell_after=False)]
assert run_mock.mock_calls == [
call("prime", shell=False, shell_after=False, rerun_step=False)
]
assert pack_mock.mock_calls == []


Expand Down
18 changes: 16 additions & 2 deletions tests/unit/test_projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -1084,7 +1084,9 @@ def test_app_command_chain(self, command_chain, app_yaml_data):
assert project.apps is not None
assert project.apps["app1"].command_chain == command_chain

@pytest.mark.parametrize("listen_stream", [1, 100, 65535, "/tmp/mysocket.sock"])
@pytest.mark.parametrize(
"listen_stream", [1, 100, 65535, "/tmp/mysocket.sock", "@snap.foo"]
)
def test_app_sockets_valid_listen_stream(self, listen_stream, socket_yaml_data):
data = socket_yaml_data(listen_stream=listen_stream)

Expand All @@ -1094,13 +1096,25 @@ def test_app_sockets_valid_listen_stream(self, listen_stream, socket_yaml_data):
assert project.apps["app1"].sockets["socket1"].listen_stream == listen_stream

@pytest.mark.parametrize("listen_stream", [-1, 0, 65536])
def test_app_sockets_invalid_listen_stream(self, listen_stream, socket_yaml_data):
def test_app_sockets_invalid_int_listen_stream(
self, listen_stream, socket_yaml_data
):
data = socket_yaml_data(listen_stream=listen_stream)

error = f".*{listen_stream} is not an integer between 1 and 65535"
with pytest.raises(errors.ProjectValidationError, match=error):
Project.unmarshal(data)

@pytest.mark.parametrize("listen_stream", ["@foo"])
def test_app_sockets_invalid_socket_listen_stream(
self, listen_stream, socket_yaml_data
):
data = socket_yaml_data(listen_stream=listen_stream)

error = f".*{listen_stream!r} is not a valid socket path.*"
with pytest.raises(errors.ProjectValidationError, match=error):
Project.unmarshal(data)

def test_app_sockets_missing_listen_stream(self, socket_yaml_data):
data = socket_yaml_data()

Expand Down

0 comments on commit 184730f

Please sign in to comment.