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.2.11' into 'main' #4852

Merged
merged 2 commits into from
Jun 14, 2024
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
66 changes: 43 additions & 23 deletions snapcraft/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,11 @@ def _get_esm_error_for_base(base: str) -> None:
class Snapcraft(Application):
"""Snapcraft application definition."""

_known_core24: bool
"""True if the project should use the core24/craft-application codepath."""

def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
# Whether we know that we should use the core24-based codepath.
self._known_core24 = False
self._parse_info: dict[str, list[str]] = {}

# Locate the project file. It's used in early execution to determine
Expand All @@ -98,22 +99,40 @@ def __init__(self, *args, **kwargs) -> None:
self._snapcraft_yaml_path: pathlib.Path | None = self._resolve_project_path(
None
)
with self._snapcraft_yaml_path.open() as file:
self._snapcraft_yaml_data = util.safe_yaml_load(file)
except FileNotFoundError:
self._snapcraft_yaml_path = None
self._snapcraft_yaml_path = self._snapcraft_yaml_data = None

self._known_core24 = self._get_known_core24()

for craft_var, snapcraft_var in MAPPED_ENV_VARS.items():
if env_val := os.getenv(snapcraft_var):
os.environ[craft_var] = env_val

def _get_known_core24(self) -> bool:
"""Return true if the project is known to be core24."""
if self._snapcraft_yaml_data:
base = self._snapcraft_yaml_data.get("base")
build_base = self._snapcraft_yaml_data.get("build-base")

# We know for sure that we're handling a core24 project
if "core24" in (base, build_base) or build_base == "devel":
return True

return False

def _get_app_plugins(self) -> dict[str, PluginType]:
return plugins.get_plugins(core22=False)

@override
def _register_default_plugins(self) -> None:
"""Register per application plugins when initializing."""
super()._register_default_plugins()
# dotnet is disabled for core24 because it is pending a rewrite
craft_parts.plugins.unregister("dotnet")

if self._known_core24:
# dotnet is disabled for core24 and newer because it is pending a rewrite
craft_parts.plugins.unregister("dotnet")

@override
def _configure_services(self, provider_name: str | None) -> None:
Expand Down Expand Up @@ -190,29 +209,28 @@ def _get_argv_command() -> str | None:

@override
def _get_dispatcher(self) -> craft_cli.Dispatcher:
# Handle "multiplexing" of Snapcraft "codebases" depending on the
# project's base (if any). Here, we handle the case where there *is*
# a project and it's core24, which means it should definitely fall into
# the craft-application-based flow.
"""Handle multiplexing of Snapcraft "codebases" depending on the project's base.

The ClassicFallback-based flow is used in any of the following scenarios:
- there is no project to load
- for core20 remote builds if SNAPCRAFT_REMOTE_BUILD_STRATEGY is not "disable-fallback"
- for core22 remote builds if SNAPCRAFT_REMOTE_BUILD_STRATEGY is "force-fallback"

The craft-application-based flow is used in any of the following scenarios:
- the project base is core24 or newer
- for the "version" command
"""
argv_command = self._get_argv_command()
if argv_command == "lint":
# We don't need to check for core24 if we're just linting
return super()._get_dispatcher()

if self._snapcraft_yaml_path:
with self._snapcraft_yaml_path.open() as file:
yaml_data = util.safe_yaml_load(file)
base = yaml_data.get("base")
build_base = yaml_data.get("build-base")
if self._snapcraft_yaml_data:
base = self._snapcraft_yaml_data.get("base")
build_base = self._snapcraft_yaml_data.get("build-base")
_get_esm_error_for_base(base)
if "core24" in (base, build_base) or build_base == "devel":
# We know for sure that we're handling a core24 project
self._known_core24 = True
elif (
argv_command == "version" or "--version" in sys.argv or "-V" in sys.argv
):
pass
elif argv_command == "remote-build" and any(

if argv_command == "remote-build" and any(
b in ("core20", "core22") for b in (base, build_base)
):
build_strategy = os.environ.get("SNAPCRAFT_REMOTE_BUILD_STRATEGY", None)
Expand All @@ -239,7 +257,9 @@ def _get_dispatcher(self) -> craft_cli.Dispatcher:
and build_strategy == "force-fallback"
):
raise errors.ClassicFallback()
else:
elif not self._known_core24 and not (
argv_command == "version" or "--version" in sys.argv or "-V" in sys.argv
):
raise errors.ClassicFallback()
return super()._get_dispatcher()

Expand Down
18 changes: 18 additions & 0 deletions tests/spread/core24/dotnet/snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: dotnet-hello
base: core24
version: '1.0'
summary: a simple dotnet snap
description: a simple dotnet snap

confinement: strict

apps:
dotnet-hello:
command: dotnet

parts:
hello:
plugin: dotnet
source: .
dotnet-self-contained-runtime-identifier: linux-x64
build-snaps: [dotnet-sdk]
11 changes: 11 additions & 0 deletions tests/spread/core24/dotnet/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
summary: Build a snap with the dotnet plugin

restore: |
rm -rf ./*.snap

execute: |
# Unset SNAPCRAFT_BUILD_ENVIRONMENT=host.
unset SNAPCRAFT_BUILD_ENVIRONMENT

# dotnet is disabled for core24 until the dotnet sdk snap is rewritten
snapcraft pack 2>&1 | MATCH "plugin not registered: 'dotnet'"
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Console.WriteLine("hello world");
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: dotnet-hello
base: core22
version: '1.0'
summary: a simple dotnet snap
description: a simple dotnet snap

confinement: strict

apps:
dotnet-hello:
command: dotnet

parts:
hello:
plugin: dotnet
source: .
dotnet-self-contained-runtime-identifier: linux-x64
build-snaps: [dotnet-sdk]
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ environment:
SNAP/python: python-hello
SNAP/qmake: qmake-hello
SNAP/maven: maven-hello
SNAP/dotnet: dotnet-hello

prepare: |
#shellcheck source=tests/spread/tools/snapcraft-yaml.sh
Expand All @@ -28,6 +29,7 @@ restore: |
# Undo changes to hello
[ -f hello ] && git checkout hello
[ -f hello.c ] && git checkout hello.c
[ -f hello.cs ] && git checkout hello.cs
[ -f subdir/hello.c ] && git checkout subdir/hello.c
[ -f hello.js ] && git checkout hello.js
[ -f main.go ] && git checkout main.go
Expand Down Expand Up @@ -72,6 +74,8 @@ execute: |
modified_file=hello
elif [ -f hello.c ]; then
modified_file=hello.c
elif [ -f hello.cs ]; then
modified_file=hello.cs
elif [ -f subdir/hello.c ]; then
modified_file=subdir/hello.c
elif [ -f hello.js ]; then
Expand Down
9 changes: 8 additions & 1 deletion tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

import pytest
import yaml
from craft_parts import Features, callbacks
from craft_parts import Features, callbacks, plugins
from craft_providers import Executor, Provider
from craft_providers.base import Base
from overrides import override
Expand All @@ -37,6 +37,13 @@ def unregister_callbacks(mocker):
callbacks.unregister_all()


@pytest.fixture(autouse=True)
def reset_plugins():
# craft-part modifies a dictionary of plugins that doesn't get reloaded between tests
# 'unregister_all()' resets to the dictionary to the default value
plugins.unregister_all()


@pytest.fixture
def snapcraft_yaml(new_dir):
"""Return a fixture that can write a snapcraft.yaml."""
Expand Down
64 changes: 60 additions & 4 deletions tests/unit/test_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from textwrap import dedent

import craft_cli
import craft_parts.plugins
import pytest
import yaml
from craft_application import util
Expand Down Expand Up @@ -308,13 +309,45 @@ def test_application_plugins():
assert "kernel" not in plugins


def test_application_dotnet_not_registered():
"""dotnet plugin is disable for core24."""
@pytest.mark.parametrize(
("base", "build_base"),
[
("core20", None),
("core20", "core20"),
("core20", "devel"),
("core22", None),
("core22", "core22"),
("core22", "devel"),
],
)
def test_application_dotnet_registered(base, build_base, snapcraft_yaml):
"""dotnet plugin is enabled for core22."""
snapcraft_yaml(base=base, build_base=build_base)
app = application.create_app()

plugins = app._get_app_plugins()
app._register_default_plugins()

assert "dotnet" in craft_parts.plugins.get_registered_plugins()


@pytest.mark.parametrize(
("base", "build_base"),
[
("core24", None),
("core24", "core20"),
("core24", "core22"),
("core24", "core24"),
("core24", "devel"),
],
)
def test_application_dotnet_not_registered(base, build_base, snapcraft_yaml):
"""dotnet plugin is disabled for core24 and newer bases."""
snapcraft_yaml(base=base, build_base=build_base)
app = application.create_app()

assert "dotnet" not in plugins
app._register_default_plugins()

assert "dotnet" not in craft_parts.plugins.get_registered_plugins()


def test_default_command_integrated(monkeypatch, mocker, new_dir):
Expand Down Expand Up @@ -483,3 +516,26 @@ def test_run_envvar_invalid(snapcraft_yaml, base, monkeypatch):
"'SNAPCRAFT_REMOTE_BUILD_STRATEGY'. Valid values are 'disable-fallback' and "
"'force-fallback'"
)


@pytest.mark.parametrize(
("base", "build_base", "is_known_core24"),
[
("core20", None, False),
("core20", "core20", False),
("core20", "devel", False),
("core22", None, False),
("core22", "core22", False),
("core22", "devel", False),
("core24", "core22", True),
("core24", None, True),
("core24", "core24", True),
("core24", "devel", True),
],
)
def test_known_core24(snapcraft_yaml, base, build_base, is_known_core24):
snapcraft_yaml(base=base, build_base=build_base)

app = application.create_app()

assert app._known_core24 == is_known_core24
Loading