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

fix: set project variables for core24 #4757

Merged
merged 3 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
7 changes: 7 additions & 0 deletions snapcraft/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from snapcraft.commands import unimplemented
from snapcraft.extensions import apply_extensions
from snapcraft.models.project import SnapcraftBuildPlanner, apply_root_packages
from snapcraft.parts import set_global_environment
from snapcraft.utils import get_host_architecture
from snapcraft_legacy.cli import legacy

Expand Down Expand Up @@ -230,6 +231,12 @@ def _create_dispatcher(self) -> craft_cli.Dispatcher:
default_command=craft_app_commands.lifecycle.PackCommand,
)

@override
def _set_global_environment(self, info: craft_parts.ProjectInfo) -> None:
"""Set global environment variables."""
super()._set_global_environment(info)
set_global_environment(info)


def create_app() -> Snapcraft:
"""Create a Snapcraft application with the proper commands."""
Expand Down
12 changes: 9 additions & 3 deletions snapcraft/parts/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2022 Canonical Ltd.
# Copyright 2022,2024 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
Expand All @@ -18,7 +18,13 @@

from craft_parts import validate_part

from .lifecycle import patch_elf
from .lifecycle import patch_elf, set_global_environment, set_step_environment
from .parts import PartsLifecycle

__all__ = ["PartsLifecycle", "patch_elf", "validate_part"]
__all__ = [
"PartsLifecycle",
"patch_elf",
"set_global_environment",
"set_step_environment",
"validate_part",
]
22 changes: 15 additions & 7 deletions snapcraft/parts/lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ def run(command_name: str, parsed_args: "argparse.Namespace") -> None:
build_plan = get_build_plan(yaml_data, parsed_args)

# Register our own callbacks
callbacks.register_prologue(_set_global_environment)
callbacks.register_pre_step(_set_step_environment)
callbacks.register_prologue(set_global_environment)
callbacks.register_pre_step(set_step_environment)
callbacks.register_post_step(patch_elf, step_list=[Step.PRIME])

build_count = utils.get_parallel_build_count()
Expand Down Expand Up @@ -574,12 +574,10 @@ def _expose_prime(
instance.mount(host_source=project_path / "prime", target=dirs.prime_dir)


def _set_global_environment(info: ProjectInfo) -> None:
def set_global_environment(info: ProjectInfo) -> None:
"""Set global environment variables."""
info.global_environment.update(
{
"SNAPCRAFT_ARCH_TRIPLET": info.arch_triplet,
"SNAPCRAFT_TARGET_ARCH": info.target_arch,
"SNAPCRAFT_PARALLEL_BUILD_COUNT": str(info.parallel_build_count),
"SNAPCRAFT_PROJECT_VERSION": info.get_project_var("version", raw_read=True),
"SNAPCRAFT_PROJECT_GRADE": info.get_project_var("grade", raw_read=True),
Expand All @@ -590,6 +588,15 @@ def _set_global_environment(info: ProjectInfo) -> None:
}
)

# add deprecated environment variables for core22
if info.base == "core22":
info.global_environment.update(
{
"SNAPCRAFT_ARCH_TRIPLET": info.arch_triplet,
"SNAPCRAFT_TARGET_ARCH": info.target_arch,
}
)

if info.partitions:
info.global_environment.update(_get_environment_for_partitions(info))

Expand Down Expand Up @@ -645,7 +652,7 @@ def _check_experimental_plugins(
)


def _set_step_environment(step_info: StepInfo) -> bool:
def set_step_environment(step_info: StepInfo) -> bool:
"""Set the step environment before executing each lifecycle step."""
step_info.step_environment.update(
{
Expand Down Expand Up @@ -737,6 +744,7 @@ def _expand_environment(
dirs = craft_parts.ProjectDirs(work_dir=work_dir, partitions=partitions)
info = craft_parts.ProjectInfo(
application_name="snapcraft", # not used in environment expansion
base=yaml_utils.get_base_from_yaml(snapcraft_yaml) or "",
cache_dir=Path(), # not used in environment expansion
arch=convert_architecture_deb_to_platform(target_arch),
parallel_build_count=parallel_build_count,
Expand All @@ -745,7 +753,7 @@ def _expand_environment(
project_vars=project_vars,
partitions=partitions,
)
_set_global_environment(info)
set_global_environment(info)

craft_parts.expand_environment(snapcraft_yaml, info=info, skip=["name", "version"])

Expand Down
14 changes: 13 additions & 1 deletion snapcraft/parts/yaml_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2022-2023 Canonical Ltd.
# Copyright 2022-2024 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
Expand Down Expand Up @@ -127,6 +127,18 @@ def get_base(filestream: TextIO) -> Optional[str]:
:raises SnapcraftError: If the yaml could not be loaded.
"""
data = safe_load(filestream)
return get_base_from_yaml(data)


def get_base_from_yaml(data: dict[str, Any]) -> str | None:
"""Get the effective base from a dictionary of yaml data.

:param data: The YAML data to load.

:returns: Effective base of the project or None if the base cannot be determined.

:raises SnapcraftError: If the yaml could not be loaded.
"""
return utils.get_effective_base(
base=data.get("base"),
build_base=data.get("build-base"),
Expand Down
4 changes: 3 additions & 1 deletion snapcraft/services/lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

from craft_application import AppMetadata, LifecycleService, ServiceFactory
from craft_application.models import BuildInfo
from craft_parts import ProjectInfo, StepInfo
from craft_parts import ProjectInfo, StepInfo, callbacks
from overrides import overrides

from snapcraft import __version__, errors, models, os_release, parts, utils
Expand Down Expand Up @@ -68,6 +68,8 @@ def setup(self) -> None:
confinement=project.confinement,
project_base=project.base or "",
)
callbacks.register_prologue(parts.set_global_environment)
callbacks.register_pre_step(parts.set_step_environment)
super().setup()

@overrides
Expand Down
14 changes: 12 additions & 2 deletions tests/spread/core24-suites/environment/test-variables/task.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,18 @@ execute: |
echo "==== $file ===="
cat "$file"
for exp in \
"^CRAFT_ARCH_TRIPLET=x86_64-linux-gnu$" \
"^CRAFT_TARGET_ARCH=amd64$" \
"^SNAPCRAFT_PROJECT_GRADE=devel$" \
"^SNAPCRAFT_PROJECT_NAME=None$" \
"^SNAPCRAFT_PROJECT_VERSION=1$" \
"^SNAPCRAFT_PARALLEL_BUILD_COUNT=[0-9]\+$" \
"^SNAPCRAFT_PROJECT_DIR=${root}$" \
"^SNAPCRAFT_PART_SRC=${root}/parts/hello/src$" \
"^SNAPCRAFT_PART_SRC_WORK=${root}/parts/hello/src$" \
"^SNAPCRAFT_PART_BUILD=${root}/parts/hello/build$" \
"^SNAPCRAFT_PART_BUILD_WORK=${root}/parts/hello/build$" \
"^SNAPCRAFT_PART_INSTALL=${root}/parts/hello/install$" \
"^SNAPCRAFT_STAGE=${root}/stage$" \
"^SNAPCRAFT_PRIME=${root}/prime$" \
"^CRAFT_PARALLEL_BUILD_COUNT=[0-9]\+$" \
"^CRAFT_PROJECT_DIR=${root}$" \
"^CRAFT_PART_NAME=hello$" \
Expand Down
9 changes: 7 additions & 2 deletions tests/unit/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2022-2023 Canonical Ltd.
# Copyright 2022-2024 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
Expand All @@ -23,7 +23,7 @@

import pytest
import yaml
from craft_parts import Features
from craft_parts import Features, callbacks
from craft_providers import Executor, Provider
from craft_providers.base import Base
from overrides import override
Expand All @@ -32,6 +32,11 @@
from snapcraft.extensions import extension, register, unregister


@pytest.fixture(autouse=True)
def unregister_callbacks(mocker):
callbacks.unregister_all()


@pytest.fixture
def snapcraft_yaml(new_dir):
"""Return a fixture that can write a snapcraft.yaml."""
Expand Down
41 changes: 40 additions & 1 deletion tests/unit/parts/test_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@

import pytest
from craft_cli import EmitterMode, emit
from craft_parts import Action, Features, Step, callbacks
from craft_parts import Action, Features, ProjectInfo, Step, callbacks
from craft_providers.bases.ubuntu import BuilddBaseAlias

from snapcraft import errors
from snapcraft.elf import ElfFile
from snapcraft.models import MANDATORY_ADOPTABLE_FIELDS, Project
from snapcraft.parts import lifecycle as parts_lifecycle
from snapcraft.parts import set_global_environment
from snapcraft.parts.plugins import KernelPlugin, MatterSdkPlugin
from snapcraft.parts.update_metadata import update_project_metadata
from snapcraft.utils import get_host_architecture
Expand Down Expand Up @@ -1205,13 +1206,50 @@ def test_get_snap_project_no_base(snapcraft_yaml, new_dir):
)


@pytest.mark.parametrize("base", ["core22", "core24"])
def test_set_global_environment(base, mocker, new_dir):
"""Set the global environment."""
expected_global_environment = {
"SNAPCRAFT_PARALLEL_BUILD_COUNT": "1",
"SNAPCRAFT_PRIME": f"{new_dir}/prime",
"SNAPCRAFT_PROJECT_DIR": str(new_dir),
"SNAPCRAFT_PROJECT_GRADE": "test-grade",
"SNAPCRAFT_PROJECT_NAME": "None",
"SNAPCRAFT_PROJECT_VERSION": "test-version",
"SNAPCRAFT_STAGE": f"{new_dir}/stage",
}
if base == "core22":
expected_global_environment.update(
{
"SNAPCRAFT_ARCH_TRIPLET": "aarch64-linux-gnu",
"SNAPCRAFT_TARGET_ARCH": "arm64",
}
)
mocker.patch("platform.machine", return_value="aarch64")

info = ProjectInfo(
application_name="test",
base=base,
project_vars={
"version": "test-version",
"grade": "test-grade",
},
arch="aarch64",
cache_dir=new_dir,
)
set_global_environment(info)

assert info.global_environment == expected_global_environment


def test_expand_environment(new_dir, mocker):
mocker.patch("platform.machine", return_value="aarch64")

yaml_data = {
"name": "test-env",
"version": "1.2.3",
"grade": "stable",
"base": "core22",
"field0": "$CRAFT_PROJECT_NAME",
"field1": "$SNAPCRAFT_PROJECT_NAME",
"field2": "$SNAPCRAFT_PROJECT_VERSION",
Expand All @@ -1235,6 +1273,7 @@ def test_expand_environment(new_dir, mocker):
)

assert yaml_data == {
"base": "core22",
"name": "test-env",
"version": "1.2.3",
"grade": "stable",
Expand Down
52 changes: 51 additions & 1 deletion tests/unit/parts/test_yaml_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2022-2023 Canonical Ltd.
# Copyright 2022-2024 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
Expand Down Expand Up @@ -199,3 +199,53 @@ def test_apply_yaml_defines_root_packages(minimal_yaml_data, key, value):
"architectures": [Architecture(build_on="amd64", build_for="amd64")],
"parts": {"nil": {}, "snapcraft/core": {"plugin": "nil", key: ["foo"]}},
}


def test_get_base(mocker):
mock_get_effective_base = mocker.patch(
"snapcraft.parts.yaml_utils.utils.get_effective_base",
return_value="test-effective-base",
)
yaml = io.StringIO(
dedent(
"""\
name: test-name
type: test-type
base: test-base
build-base: test-build-base
"""
)
)

effective_base = yaml_utils.get_base(yaml)

mock_get_effective_base.assert_called_with(
base="test-base",
build_base="test-build-base",
name="test-name",
project_type="test-type",
)
assert effective_base == "test-effective-base"


def test_get_base_from_yaml(mocker):
mock_get_effective_base = mocker.patch(
"snapcraft.parts.yaml_utils.utils.get_effective_base",
return_value="test-effective-base",
)
yaml_dict = {
"name": "test-name",
"type": "test-type",
"base": "test-base",
"build-base": "test-build-base",
}

effective_base = yaml_utils.get_base_from_yaml(yaml_dict)

mock_get_effective_base.assert_called_with(
base="test-base",
build_base="test-build-base",
name="test-name",
project_type="test-type",
)
assert effective_base == "test-effective-base"
Loading