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

extensions: plugin aware part_snippet values #4271

Merged
merged 1 commit into from
Jul 12, 2023
Merged
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
9 changes: 6 additions & 3 deletions snapcraft/extensions/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,13 @@ def _apply_extension(
app_definition.get(property_name), property_value
)

# Next, apply the part-specific components
part_extension = extension.get_part_snippet()
# Next, apply the part-specific components, this can be plugin
# aware.
parts = yaml_data["parts"]
for _part_name, part_definition in parts.items():
for _, part_definition in parts.items():
part_extension = extension.get_part_snippet(
plugin_name=part_definition["plugin"]
)
for property_name, property_value in part_extension.items():
part_definition[property_name] = _apply_extension_property(
part_definition.get(property_name), property_value
Expand Down
2 changes: 1 addition & 1 deletion snapcraft/extensions/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def get_app_snippet(self) -> Dict[str, Any]:
"""Return the app snippet to apply."""

@abc.abstractmethod
def get_part_snippet(self) -> Dict[str, Any]:
def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
"""Return the part snippet to apply to existing parts."""

@abc.abstractmethod
Expand Down
2 changes: 1 addition & 1 deletion snapcraft/extensions/gnome.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def get_root_snippet(self) -> Dict[str, Any]:
}

@overrides
def get_part_snippet(self) -> Dict[str, Any]:
def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
sdk_snap = self.gnome_snaps.sdk

return {
Expand Down
2 changes: 1 addition & 1 deletion snapcraft/extensions/kde_neon.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def get_root_snippet(self) -> Dict[str, Any]:
}

@overrides
def get_part_snippet(self) -> Dict[str, Any]:
def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
sdk_snap = self.kde_snaps.sdk
cmake_args = self.ext_info.cmake_args

Expand Down
2 changes: 1 addition & 1 deletion snapcraft/extensions/ros2_humble.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def get_app_snippet(self) -> Dict[str, Any]:
}

@overrides
def get_part_snippet(self) -> Dict[str, Any]:
def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
return {
"build-environment": [
{"ROS_VERSION": self.ROS_VERSION},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ def __init__(self, *, extension_name: str, yaml_data: Dict[str, Any]) -> None:
self.part_snippet = dict() # type: Dict[str, Any]
self.parts = dict() # type: Dict[str, Any]

def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
"""Return the part snippet to apply to a part."""
return self.part_snippet

def _sanity_check(self, *, extension_name: str, yaml_data: Dict[str, Any]) -> None:
base = yaml_data.get("base")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,13 @@ def _apply_extension(
app_definition.get(property_name), property_value
)

# Next, apply the part-specific components
part_extension = extension.part_snippet
# Next, apply the part-specific components, this can be plugin
# aware.
parts = yaml_data["parts"]
for part_name, part_definition in parts.items():
for _, part_definition in parts.items():
part_extension = extension.get_part_snippet(
plugin_name=part_definition["plugin"]
)
for property_name, property_value in part_extension.items():
part_definition[property_name] = _apply_extension_property(
part_definition.get(property_name), property_value
Expand Down
89 changes: 88 additions & 1 deletion tests/legacy/unit/project_loader/extensions/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import textwrap
from typing import Tuple
from typing import Any, Dict, Tuple

from overrides import overrides
from testtools.matchers import Contains, Equals, Not

import snapcraft_legacy.yaml_utils.errors
Expand All @@ -43,6 +44,7 @@ def setUp(self):
self.useFixture(_daemon_extension_fixture())
self.useFixture(_adopt_info_extension_fixture())
self.useFixture(_invalid_extension_fixture())
self.useFixture(_plugin_aware_part_snippet_extension_fixture())


class BasicExtensionTest(ExtensionTestBase):
Expand Down Expand Up @@ -332,6 +334,61 @@ def test_merge_environment(self):

self.run_test()

def test_plugin_aware_part_snippet1(self):
self.set_attributes(
{
"app_definition": textwrap.dedent(
"""\
command: echo 'hello'
extensions: [pluginextension]
"""
),
"expected_app_definition": {
"command": "echo 'hello'",
},
"part_definition": textwrap.dedent(
"""\
plugin: catkin
"""
),
"expected_part_definition": {
"plugin": "catkin",
"prime": [],
"stage": [],
},
}
)

self.run_test()

def test_plugin_aware_part_snippet2(self):
self.set_attributes(
{
"app_definition": textwrap.dedent(
"""\
command: echo 'hello'
extensions: [pluginextension]
"""
),
"expected_app_definition": {
"command": "echo 'hello'",
},
"part_definition": textwrap.dedent(
"""\
plugin: nil
"""
),
"expected_part_definition": {
"plugin": "nil",
"build-environment": [{"FOO": "bar"}],
"prime": [],
"stage": [],
},
}
)

self.run_test()

def test_merge_build_environment(self):
self.set_attributes(
{
Expand Down Expand Up @@ -831,6 +888,36 @@ def __init__(self, extension_name, yaml_data):
return fixture_setup.FakeExtension("buildenvironment2", ExtensionImpl)


def _plugin_aware_part_snippet_extension_fixture():
class ExtensionImpl(Extension):
@staticmethod
def get_supported_bases() -> Tuple[str, ...]:
return ("core20",)

@staticmethod
def get_supported_confinement() -> Tuple[str, ...]:
return ("strict",)

def __init__(self, extension_name, yaml_data):
super().__init__(extension_name=extension_name, yaml_data=yaml_data)
self.root_snippet = {}
self.app_snippet = {}
self.part_snippet = {
"build-environment": [
{"FOO": "bar"},
],
}
self.parts = {}

@overrides
def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
if plugin_name == "catkin":
return {}
return self.part_snippet

return fixture_setup.FakeExtension("pluginextension", ExtensionImpl)


def _plug_extension_fixture():
class ExtensionImpl(Extension):
@staticmethod
Expand Down
13 changes: 8 additions & 5 deletions tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ def get_root_snippet(self) -> Dict[str, Any]:
def get_app_snippet(self) -> Dict[str, Any]:
return {"plugs": ["fake-plug"]}

def get_part_snippet(self) -> Dict[str, Any]:
def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
if plugin_name == "catkin":
return {}

return {"after": ["fake-extension/fake-part"]}

def get_parts_snippet(self) -> Dict[str, Any]:
Expand Down Expand Up @@ -122,7 +125,7 @@ def get_root_snippet(self) -> Dict[str, Any]:
def get_app_snippet(self) -> Dict[str, Any]:
return {"plugs": ["fake-plug", "fake-plug-extra"]}

def get_part_snippet(self) -> Dict[str, Any]:
def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
return {"after": ["fake-extension-extra/fake-part"]}

def get_parts_snippet(self) -> Dict[str, Any]:
Expand Down Expand Up @@ -156,7 +159,7 @@ def get_root_snippet(self) -> Dict[str, Any]:
def get_app_snippet(self) -> Dict[str, Any]:
return {"plugs": ["fake-plug"]}

def get_part_snippet(self) -> Dict[str, Any]:
def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
return {"after": ["fake-extension/fake-part"]}

def get_parts_snippet(self) -> Dict[str, Any]:
Expand Down Expand Up @@ -192,7 +195,7 @@ def get_root_snippet(self) -> Dict[str, Any]:
def get_app_snippet(self) -> Dict[str, Any]:
return {}

def get_part_snippet(self) -> Dict[str, Any]:
def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
return {}

def get_parts_snippet(self) -> Dict[str, Any]:
Expand Down Expand Up @@ -228,7 +231,7 @@ def get_root_snippet(self) -> Dict[str, Any]:
def get_app_snippet(self) -> Dict[str, Any]:
return {"plugs": ["fake-plug", "fake-plug-extra"]}

def get_part_snippet(self) -> Dict[str, Any]:
def get_part_snippet(self, *, plugin_name: str) -> Dict[str, Any]:
return {"after": ["fake-extension-extra/fake-part"]}

def get_parts_snippet(self) -> Dict[str, Any]:
Expand Down
46 changes: 46 additions & 0 deletions tests/unit/extensions/test_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,52 @@ def test_apply_extension():
}


@pytest.mark.usefixtures("fake_extension")
def test_apply_extension_plugin_dependent():
yaml_data = {
"name": "fake-snap",
"summary": "fake summary",
"description": "fake description",
"base": "core22",
"apps": {
"fake-command": {
"command": "bin/fake-command",
"plugs": ["my-fake-plug"],
"extensions": ["fake-extension"],
}
},
"parts": {
"fake-part": {"source": ".", "plugin": "dump"},
"ros-untouched": {"source": "ros", "plugin": "catkin"},
},
}

assert extensions.apply_extensions(
yaml_data, arch="amd64", target_arch="amd64"
) == {
"name": "fake-snap",
"summary": "fake summary",
"description": "fake description",
"base": "core22",
"grade": "fake-grade",
"apps": {
"fake-command": {
"command": "bin/fake-command",
"plugs": ["fake-plug", "my-fake-plug"],
}
},
"parts": {
"fake-part": {
"source": ".",
"plugin": "dump",
"after": ["fake-extension/fake-part"],
},
"ros-untouched": {"source": "ros", "plugin": "catkin"},
"fake-extension/fake-part": {"plugin": "nil"},
},
}


@pytest.mark.usefixtures("fake_extension")
@pytest.mark.usefixtures("fake_extension_extra")
def test_apply_multiple_extensions():
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/extensions/test_gnome.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def test_get_part_snippet_latest_edge(

@staticmethod
def assert_get_part_snippet(gnome_instance):
assert gnome_instance.get_part_snippet() == {
assert gnome_instance.get_part_snippet(plugin_name="autotools") == {
"build-environment": [
{"PATH": "/snap/gnome-42-2204-sdk/current/usr/bin${PATH:+:$PATH}"},
{
Expand Down Expand Up @@ -254,7 +254,7 @@ def assert_get_part_snippet(gnome_instance):


def test_get_part_snippet_with_external_sdk(gnome_extension_with_build_snap):
assert gnome_extension_with_build_snap.get_part_snippet() == {
assert gnome_extension_with_build_snap.get_part_snippet(plugin_name="meson") == {
"build-environment": [
{"PATH": "/snap/gnome-44-2204-sdk/current/usr/bin${PATH:+:$PATH}"},
{
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/extensions/test_kde_neon.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def test_get_part_snippet_latest_edge(

@staticmethod
def assert_get_part_snippet(kde_neon_instance):
assert kde_neon_instance.get_part_snippet() == {
assert kde_neon_instance.get_part_snippet(plugin_name="cmake") == {
"build-environment": [
{
"PATH": (
Expand All @@ -193,7 +193,7 @@ def assert_get_part_snippet(kde_neon_instance):


def test_get_part_snippet_with_external_sdk(kde_neon_extension_with_build_snap):
assert kde_neon_extension_with_build_snap.get_part_snippet() == {
assert kde_neon_extension_with_build_snap.get_part_snippet(plugin_name="cmake") == {
"build-environment": [
{
"PATH": (
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/parts/extensions/test_ros2_humble.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def test_get_app_snippet(self, setup_method_fixture):

def test_get_part_snippet(self, setup_method_fixture):
extension = setup_method_fixture()
assert extension.get_part_snippet() == {
assert extension.get_part_snippet(plugin_name="colcon") == {
"build-environment": [{"ROS_VERSION": "2"}, {"ROS_DISTRO": "humble"}]
}

Expand Down