Skip to content
Open
Show file tree
Hide file tree
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
30 changes: 26 additions & 4 deletions snapcraft/commands/extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from pydantic import BaseModel
from typing_extensions import override

from snapcraft import errors, extensions, models
from snapcraft import const, errors, extensions, models
from snapcraft.parts.yaml_utils import (
apply_yaml,
extract_parse_info,
Expand All @@ -55,23 +55,45 @@ def marshal(self) -> dict[str, str]:


class ExtensionsCommand(AppCommand):
"""List available extensions for all supported bases."""
"""List available extensions."""

name = "extensions"
help_msg = "List available extensions for all supported bases."
help_msg = "List available extensions, optionally for a given base."
overview = textwrap.dedent(
"""
List available extensions and their corresponding bases.
List available extensions, optionally for a given base.
"""
)

@override
def fill_parser(self, parser: argparse.ArgumentParser) -> None:
"""Add arguments specific to the extensions command."""
parser.add_argument(
"--base",
metavar="base",
type=str,
help="Show extensions for <base>",
)

@override
def run(self, parsed_args: argparse.Namespace) -> None:
base = getattr(parsed_args, "base", None)

if base in const.ESM_BASES:
raise errors.MaintenanceBase(base=base)

if base is not None and base not in const.CURRENT_BASES:
raise errors.SnapcraftError(f"{base} not supported")

extension_presentation: dict[str, ExtensionModel] = {}

for extension_name in extensions.registry.get_extension_names():
extension_class = extensions.registry.get_extension_class(extension_name)
extension_bases = list(extension_class.get_supported_bases())

if base is not None and base not in extension_bases:
continue

extension_presentation[extension_name] = ExtensionModel(
name=extension_name, bases=extension_bases
)
Expand Down
41 changes: 41 additions & 0 deletions tests/unit/commands/test_list_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,47 @@ def test_command(emitter, fake_app_config):
)


@pytest.mark.usefixtures("fake_extension")
def test_command_base_option(emitter, fake_app_config):
cmd = snapcraft.commands.ExtensionsCommand(fake_app_config)

cmd.run(Namespace(base="core22"))

emitter.assert_message(
dedent(
"""\
Extension name Supported bases
-------------------- ----------------------
fake-extension core22, core24, core26
gnome core22, core24
gpu core22, core24, core26
kde-neon core22, core24
kde-neon-6 core22, core24
kde-neon-qt6 core22, core24
ros2-humble core22
ros2-humble-desktop core22
ros2-humble-ros-base core22
ros2-humble-ros-core core22"""
)
)


def test_command_base_option_unsupported(fake_app_config):
cmd = snapcraft.commands.ExtensionsCommand(fake_app_config)

with pytest.raises(errors.SnapcraftError, match="core99 not supported"):
cmd.run(Namespace(base="core99"))


def test_command_base_option_esm_base_error(fake_app_config):
cmd = snapcraft.commands.ExtensionsCommand(fake_app_config)

expected = re.escape("'core20' is not supported on this version of Snapcraft.")

with pytest.raises(errors.MaintenanceBase, match=expected):
cmd.run(Namespace(base="core20"))


def test_list_extensions_error(fake_app_config):
"""Error on removed 'list-extensions' command."""
cmd = snapcraft.commands.ListExtensionsCommand(fake_app_config)
Expand Down
Loading