From c64cea886e540d5ef675b6c33fdfb7ec60447437 Mon Sep 17 00:00:00 2001 From: Alex Lowe Date: Wed, 9 Oct 2024 19:30:13 -0400 Subject: [PATCH] fix(expand-extensions): use the Application's project Fixes LP bug https://bugs.launchpad.net/snapcraft/+bug/2083964 Instead of parsing the project again itself, expand-extensions now uses the project provided by the application. The output is changed slightly, but I believe it reflects a more accurate expansion. --- snapcraft/commands/extensions.py | 33 ++--------- tests/unit/commands/test_expand_extensions.py | 59 +++++++++++++------ tests/unit/conftest.py | 6 ++ 3 files changed, 53 insertions(+), 45 deletions(-) diff --git a/snapcraft/commands/extensions.py b/snapcraft/commands/extensions.py index 65aa16ab43..1440a3d155 100644 --- a/snapcraft/commands/extensions.py +++ b/snapcraft/commands/extensions.py @@ -17,7 +17,7 @@ """Snapcraft extension commands.""" import textwrap -from typing import Dict, List +from typing import Dict, List, cast import tabulate from craft_application.commands import AppCommand @@ -26,13 +26,6 @@ from pydantic import BaseModel from snapcraft import extensions, models -from snapcraft.parts.yaml_utils import ( - apply_yaml, - extract_parse_info, - get_snap_project, - process_yaml, -) -from snapcraft.utils import get_host_architecture from snapcraft_legacy.internal.project_loader import ( find_extension, supported_extension_names, @@ -114,25 +107,9 @@ class ExpandExtensionsCommand(AppCommand): """ ) + always_load_project = True + @overrides def run(self, parsed_args): - snap_project = get_snap_project() - - # load yaml file and trigger legacy behavior if base is core, core18, or core20 - yaml_data = process_yaml(snap_project.project_file) - - # process yaml before unmarshalling the data - arch = get_host_architecture() - yaml_data_for_arch = apply_yaml(yaml_data, arch, arch) - - # `apply_yaml()` adds or replaces the architectures keyword with an Architecture - # object, which does not easily dump to a yaml file - yaml_data_for_arch.pop("architectures", None) - yaml_data_for_arch.pop("platforms", None) - - # `parse-info` keywords must be removed before unmarshalling, because they are - # not part of the Project model - extract_parse_info(yaml_data_for_arch) - - project_data = models.Project.unmarshal(yaml_data_for_arch) - emit.message(project_data.to_yaml_string()) + project = cast(models.Project, self._services.project) + emit.message(project.to_yaml_string()) diff --git a/tests/unit/commands/test_expand_extensions.py b/tests/unit/commands/test_expand_extensions.py index 7eda7af40d..478b441ada 100644 --- a/tests/unit/commands/test_expand_extensions.py +++ b/tests/unit/commands/test_expand_extensions.py @@ -14,7 +14,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from argparse import Namespace from dataclasses import dataclass from pathlib import Path from textwrap import dedent @@ -22,7 +21,7 @@ import pytest from craft_platforms import DebianArchitecture -from snapcraft import commands, const +from snapcraft import application, const @dataclass @@ -45,7 +44,7 @@ def valid_core_data(request) -> CoreData: @pytest.mark.usefixtures("fake_extension") -def test_expand_extensions_simple_core22(new_dir, emitter): +def test_expand_extensions_simple_core22(new_dir, emitter, mocker): """Expand an extension for a simple snapcraft.yaml file.""" with Path("snapcraft.yaml").open("w") as yaml_file: print( @@ -73,8 +72,8 @@ def test_expand_extensions_simple_core22(new_dir, emitter): file=yaml_file, ) - cmd = commands.ExpandExtensionsCommand(None) - cmd.run(Namespace()) + mocker.patch("sys.argv", ["snapcraft", "expand-extensions"]) + application.main() emitter.assert_message( dedent( f"""\ @@ -110,7 +109,7 @@ def test_expand_extensions_simple_core22(new_dir, emitter): @pytest.mark.usefixtures("fake_extension") -def test_expand_extensions_simple(new_dir, emitter, valid_core_data): +def test_expand_extensions_simple(new_dir, emitter, valid_core_data, mocker): """Expand an extension for a simple snapcraft.yaml file.""" with Path("snapcraft.yaml").open("w") as yaml_file: print( @@ -139,8 +138,8 @@ def test_expand_extensions_simple(new_dir, emitter, valid_core_data): file=yaml_file, ) - cmd = commands.ExpandExtensionsCommand(None) - cmd.run(Namespace()) + mocker.patch("sys.argv", ["snapcraft", "expand-extensions"]) + application.main() emitter.assert_message( dedent( f"""\ @@ -216,11 +215,11 @@ def test_expand_extensions_complex_core22(new_dir, emitter, mocker): file=yaml_file, ) - cmd = commands.ExpandExtensionsCommand(None) - cmd.run(Namespace()) + mocker.patch("sys.argv", ["snapcraft", "expand-extensions"]) + application.main() emitter.assert_message( dedent( - f"""\ + """\ name: test-name version: '0.1' summary: testing extensions @@ -241,9 +240,17 @@ def test_expand_extensions_complex_core22(new_dir, emitter, mocker): grade: stable architectures: - build-on: - - {DebianArchitecture.from_host()} + - amd64 + build-for: + - amd64 + - build-on: + - arm64 build-for: - - {DebianArchitecture.from_host()} + - arm64 + - build-on: + - armhf + build-for: + - armhf apps: app1: command: app1 @@ -279,7 +286,10 @@ def test_expand_extensions_complex(new_dir, emitter, mocker, valid_core_data): build-base: {valid_core_data.build_base} confinement: strict grade: {valid_core_data.grade} - platforms: [amd64, arm64, armhf] + platforms: + amd64: + arm64: + armhf: apps: app1: @@ -301,9 +311,8 @@ def test_expand_extensions_complex(new_dir, emitter, mocker, valid_core_data): ), file=yaml_file, ) - - cmd = commands.ExpandExtensionsCommand(None) - cmd.run(Namespace()) + mocker.patch("sys.argv", ["snapcraft", "expand-extensions"]) + application.main() emitter.assert_message( dedent( f"""\ @@ -313,6 +322,22 @@ def test_expand_extensions_complex(new_dir, emitter, mocker, valid_core_data): description: expand a fake extension base: {valid_core_data.base} build-base: {valid_core_data.build_base} + platforms: + amd64: + build-on: + - amd64 + build-for: + - amd64 + arm64: + build-on: + - arm64 + build-for: + - arm64 + armhf: + build-on: + - armhf + build-for: + - armhf parts: nil: plugin: nil diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 285cddb152..92ec2e72bf 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -44,6 +44,12 @@ def reset_plugins(): plugins.unregister_all() +@pytest.fixture(autouse=True) +def set_debug(monkeypatch): + # Instead of eating exceptions, calls to app.run() will raise them. + monkeypatch.setenv("CRAFT_DEBUG", "1") + + @pytest.fixture def snapcraft_yaml(new_dir): """Return a fixture that can write a snapcraft.yaml."""