Skip to content

Commit

Permalink
Merge branch 'hotfix/7.5' into fix-missing-built_at-during-upload
Browse files Browse the repository at this point in the history
  • Loading branch information
mr-cal authored Jul 14, 2023
2 parents 4886ebf + de56fe6 commit 6e9ba86
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 1 deletion.
41 changes: 40 additions & 1 deletion snapcraft/meta/snap_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from pydantic_yaml import YamlModel

from snapcraft import errors
from snapcraft.projects import App, Project
from snapcraft.projects import App, Project, UniqueStrList
from snapcraft.utils import get_ld_library_paths, process_version


Expand Down Expand Up @@ -176,6 +176,41 @@ def get_content_dirs(self, installed_path: Path) -> Set[Path]:
return content_dirs


class Links(_SnapMetadataModel):
"""Metadata links used in snaps."""

contact: Optional[UniqueStrList]
donation: Optional[UniqueStrList]
issues: Optional[UniqueStrList]
source_code: Optional[UniqueStrList]
website: Optional[UniqueStrList]

@staticmethod
def _normalize_value(
value: Optional[Union[str, UniqueStrList]]
) -> Optional[List[str]]:
if isinstance(value, str):
value = [value]
return value

@classmethod
def from_project(cls, project: Project) -> "Links":
"""Create Links from a Project."""
return cls(
contact=cls._normalize_value(project.contact),
donation=cls._normalize_value(project.donation),
issues=cls._normalize_value(project.issues),
source_code=cls._normalize_value(project.source_code),
website=cls._normalize_value(project.website),
)

def __bool__(self) -> bool:
"""Return True if any of the Links attributes are set."""
return any(
[self.contact, self.donation, self.issues, self.source_code, self.website]
)


class SnapMetadata(_SnapMetadataModel):
"""The snap.yaml model.
Expand Down Expand Up @@ -210,6 +245,7 @@ class Config:
layout: Optional[Dict[str, Dict[str, str]]]
system_usernames: Optional[Dict[str, Any]]
provenance: Optional[str]
links: Optional[Links]

@classmethod
def unmarshal(cls, data: Dict[str, Any]) -> "SnapMetadata":
Expand Down Expand Up @@ -403,6 +439,8 @@ def write(project: Project, prime_dir: Path, *, arch: str):
# project provided assumes and computed assumes
total_assumes = sorted(project.assumes + list(assumes))

links = Links.from_project(project)

snap_metadata = SnapMetadata(
name=project.name,
title=project.title,
Expand All @@ -425,6 +463,7 @@ def write(project: Project, prime_dir: Path, *, arch: str):
layout=project.layout,
system_usernames=project.system_usernames,
provenance=project.provenance,
links=links if links else None,
)
if project.passthrough:
for name, value in project.passthrough.items():
Expand Down
41 changes: 41 additions & 0 deletions tests/spread/core22/patchelf/classic-python/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
summary: Build and run a Python-based core22 classic snap

# To ensure the patchelf fixes are correct, we run this test on focal systems.
systems:
- ubuntu-20.04
- ubuntu-20.04-64
- ubuntu-20.04-amd64
- ubuntu-20.04-arm64
- ubuntu-20.04-armhf
- ubuntu-20.04-s390x
- ubuntu-20.04-ppc64el

prepare: |
# Clone the snapcraft-docs/python-ctypes-example
git clone https://github.com/snapcraft-docs/python-ctypes-example.git
cd python-ctypes-example
# A known "good" commit from "main" at the time of writing this test
git checkout 31939ef68d8c383b9202f2588a704b3271bae009
# Replace the existing snap command with a call to the provisioned python3
sed -i 's|command: bin/test-ctypes.py|command: bin/python3|' snap/snapcraft.yaml
execute: |
cd python-ctypes-example
# Build the core22 snap
unset SNAPCRAFT_BUILD_ENVIRONMENT
snapcraft --use-lxd
# Install the new snap
sudo snap install --classic --dangerous example-python-ctypes*.snap
# Run the snap's command; success means patchelf correctly linked the Python
# interpreter to core22's libc. Failure would output things like:
# version `GLIBC_2.35' not found (required by /snap/example-python-ctypes/x1/bin/python3)
example-python-ctypes -c "import ctypes; print(ctypes.__file__)" | MATCH "/snap/example-python-ctypes/"
restore: |
cd python-ctypes-example
snapcraft clean
rm -f ./*.snap
8 changes: 8 additions & 0 deletions tests/spread/general/metadata-links/task.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@ environment:
prepare: |
snap install yq
#shellcheck source=tests/spread/tools/snapcraft-yaml.sh
. "$TOOLS_DIR/snapcraft-yaml.sh"
set_base snapcraft.yaml
restore: |
snapcraft clean
rm -rf ./*.snap
#shellcheck source=tests/spread/tools/snapcraft-yaml.sh
. "$TOOLS_DIR/snapcraft-yaml.sh"
restore_yaml snapcraft.yaml
execute: |
# Create a snap to trigger `snap pack`.
snapcraft
Expand Down
162 changes: 162 additions & 0 deletions tests/unit/meta/test_snap_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,111 @@ def test_assumes(simple_project, new_dir):
)


def test_links_scalars(simple_project, new_dir):
snap_yaml.write(
simple_project(
contact="me@acme.com",
issues="https://hubhub.com/issues",
donation="https://moneyfornothing.com",
source_code="https://closed.acme.com",
website="https://acme.com",
),
prime_dir=Path(new_dir),
arch="amd64",
)
yaml_file = Path("meta/snap.yaml")
assert yaml_file.is_file()

content = yaml_file.read_text()
assert content == textwrap.dedent(
"""\
name: mytest
version: 1.29.3
summary: Single-line elevator pitch for your amazing snap
description: test-description
architectures:
- amd64
base: core22
apps:
app1:
command: bin/mytest
confinement: strict
grade: stable
environment:
LD_LIBRARY_PATH: ${SNAP_LIBRARY_PATH}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
PATH: $SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/sbin:$SNAP/bin:$PATH
links:
contact:
- me@acme.com
donation:
- https://moneyfornothing.com
issues:
- https://hubhub.com/issues
source-code:
- https://closed.acme.com
website:
- https://acme.com
"""
)


def test_links_lists(simple_project, new_dir):
snap_yaml.write(
simple_project(
contact=[
"me@acme.com",
"you@acme.com",
],
issues=[
"https://hubhub.com/issues",
"https://corner.com/issues",
],
donation=["https://moneyfornothing.com", "https://prince.com"],
source_code="https://closed.acme.com",
website="https://acme.com",
),
prime_dir=Path(new_dir),
arch="amd64",
)
yaml_file = Path("meta/snap.yaml")
assert yaml_file.is_file()

content = yaml_file.read_text()
assert content == textwrap.dedent(
"""\
name: mytest
version: 1.29.3
summary: Single-line elevator pitch for your amazing snap
description: test-description
architectures:
- amd64
base: core22
apps:
app1:
command: bin/mytest
confinement: strict
grade: stable
environment:
LD_LIBRARY_PATH: ${SNAP_LIBRARY_PATH}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
PATH: $SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/sbin:$SNAP/bin:$PATH
links:
contact:
- me@acme.com
- you@acme.com
donation:
- https://moneyfornothing.com
- https://prince.com
issues:
- https://hubhub.com/issues
- https://corner.com/issues
source-code:
- https://closed.acme.com
website:
- https://acme.com
"""
)


@pytest.fixture
def complex_project():
snapcraft_yaml = textwrap.dedent(
Expand Down Expand Up @@ -1025,3 +1130,60 @@ def test_architectures_all(simple_project, new_dir):
"${SNAP_LIBRARY_PATH}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}:"
"$SNAP/lib:$SNAP/usr/lib\n"
) in content


##############
# Test Links #
##############


def test_links_for_scalars(simple_project):
project = simple_project(
contact="me@acme.com",
issues="https://hubhub.com/issues",
donation="https://moneyfornothing.com",
source_code="https://closed.acme.com",
website="https://acme.com",
)

links = snap_yaml.Links.from_project(project)

assert links.contact == [project.contact]
assert links.issues == [project.issues]
assert links.donation == [project.donation]
assert links.source_code == [project.source_code]
assert links.website == [project.website]

assert bool(links) is True


def test_links_for_lists(simple_project):
project = simple_project(
contact=[
"me@acme.com",
"you@acme.com",
],
issues=[
"https://hubhub.com/issues",
"https://corner.com/issues",
],
donation=["https://moneyfornothing.com", "https://prince.com"],
)

links = snap_yaml.Links.from_project(project)

assert links.contact == project.contact
assert links.issues == project.issues
assert links.donation == project.donation
assert links.source_code is None
assert links.website is None

assert bool(links) is True


def test_no_links(simple_project):
project = simple_project()

links = snap_yaml.Links.from_project(project)

assert bool(links) is False

0 comments on commit 6e9ba86

Please sign in to comment.