Skip to content

Commit

Permalink
Merge branch 'main' into sgmoore/kde-neon-6
Browse files Browse the repository at this point in the history
  • Loading branch information
ScarlettGatelyMoore authored Apr 5, 2024
2 parents 9f08714 + 6ff73a1 commit a19d949
Show file tree
Hide file tree
Showing 21 changed files with 262 additions and 125 deletions.
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
attrs==23.1.0
catkin-pkg==0.5.2
click==8.1.7
craft-application==2.3.0
craft-application==2.4.0
craft-archives==1.1.3
craft-cli==2.5.1
craft-grammar==1.1.1
Expand Down
2 changes: 1 addition & 1 deletion requirements-devel.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ click==8.1.7
codespell==2.2.6
colorama==0.4.6
coverage==7.4.4
craft-application==2.3.0
craft-application==2.4.0
craft-archives==1.1.3
craft-cli==2.5.1
craft-grammar==1.1.2
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cffi==1.16.0
chardet==5.2.0
charset-normalizer==3.3.2
click==8.1.7
craft-application==2.3.0
craft-application==2.4.0
craft-archives==1.1.3
craft-cli==2.5.1
craft-grammar==1.1.2
Expand Down
92 changes: 50 additions & 42 deletions snapcraft/commands/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from typing import Any, cast

import lazr.restfulclient.errors
from craft_application import errors
from craft_application.application import filter_plan
from craft_application.commands import ExtensibleCommand
from craft_application.errors import RemoteBuildError
Expand Down Expand Up @@ -113,6 +114,38 @@ def _fill_parser(self, parser: argparse.ArgumentParser) -> None:
default=os.getenv("CRAFT_BUILD_FOR"),
help="Set architecture to build for",
)
parser.add_argument(
"--project", help="upload to the specified Launchpad project"
)

def _validate(self, parsed_args: argparse.Namespace) -> None:
"""Do pre-build validation."""
if os.getenv("SUDO_USER") and os.geteuid() == 0:
emit.progress(
"Running with 'sudo' may cause permission errors and is discouraged.",
permanent=True,
)
# Give the user a bit of time to process this before proceeding.
time.sleep(1)

if (
not parsed_args.launchpad_accept_public_upload
and (
not parsed_args.project
or not self._services.remote_build.is_project_private()
)
and not confirm_with_user(_CONFIRMATION_PROMPT, default=False)
):
raise errors.RemoteBuildError(
"Remote build needs explicit acknowledgement that data sent to build servers "
"is public.",
details=(
"In non-interactive runs, please use the option "
"`--launchpad-accept-public-upload`."
),
reportable=False,
retcode=77,
)

# pylint: disable=too-many-statements
def _run(self, parsed_args: argparse.Namespace, **kwargs: Any) -> int | None:
Expand All @@ -122,31 +155,15 @@ def _run(self, parsed_args: argparse.Namespace, **kwargs: Any) -> int | None:
:raises AcceptPublicUploadError: If the user does not agree to upload data.
"""
if os.getenv("SUDO_USER") and os.geteuid() == 0:
emit.progress(
"Running with 'sudo' may cause permission errors and is discouraged.",
permanent=True,
)
# Give the user a bit of time to process this before proceeding.
time.sleep(1)
if parsed_args.project:
self._services.remote_build.set_project(parsed_args.project)

self._validate(parsed_args)
emit.progress(
"remote-build is experimental and is subject to change. Use with caution.",
permanent=True,
)

if not parsed_args.launchpad_accept_public_upload and not confirm_with_user(
_CONFIRMATION_PROMPT, default=False
):
emit.progress(
"Remote build needs explicit acknowledgement that data sent to build servers is "
"public.\n"
"In non-interactive runs, please use the option "
"`--launchpad-accept-public-upload`.",
permanent=True,
)
return 77

builder = self._services.remote_build
project = cast(models.Project, self._services.project)
config = cast(dict[str, Any], self.config)
Expand All @@ -158,10 +175,8 @@ def _run(self, parsed_args: argparse.Namespace, **kwargs: Any) -> int | None:

emit.trace(f"Project directory: {project_dir}")

build_planner = self._app.BuildPlannerClass.unmarshal(project.marshal())
full_build_plan = build_planner.get_build_plan()
possible_build_plan = filter_plan(
full_build_plan,
self._app.BuildPlannerClass.unmarshal(project.marshal()).get_build_plan(),
platform=parsed_args.platform,
build_for=parsed_args.build_for,
host_arch=None,
Expand All @@ -179,22 +194,16 @@ def _run(self, parsed_args: argparse.Namespace, **kwargs: Any) -> int | None:
return 78 # Configuration error

if parsed_args.build_for and not architectures:
if parsed_args.build_for in SUPPORTED_ARCHS:
# allow the user to build for a single architecture
# if the snapcraft.yaml not defined the platforms
architectures = [parsed_args.build_for]
else:
emit.progress(
f"build-for '{parsed_args.build_for}' is not supported.",
permanent=True,
if parsed_args.build_for not in SUPPORTED_ARCHS:
raise errors.RemoteBuildError(
f"build-for '{parsed_args.build_for}' is not supported.", retcode=78
)
return 78 # Configuration error
# Allow the user to build for a single architecture if snapcraft.yaml
# doesn't define architectures.
architectures = [parsed_args.build_for]

emit.debug(f"Architectures to build: {architectures}")

if not architectures:
architectures = None

if parsed_args.launchpad_timeout:
emit.debug(f"Setting timeout to {parsed_args.launchpad_timeout} seconds")
builder.set_timeout(parsed_args.launchpad_timeout)
Expand All @@ -208,14 +217,16 @@ def _run(self, parsed_args: argparse.Namespace, **kwargs: Any) -> int | None:
"Starting new build. It may take a while to upload large projects."
)
try:
builds = builder.start_builds(project_dir, architectures=architectures)
builds = builder.start_builds(
project_dir, architectures=architectures or None
)
except RemoteBuildError:
emit.progress("Starting build failed.", permanent=True)
emit.progress("Cleaning up")
builder.cleanup()
raise
except lazr.restfulclient.errors.Conflict:
emit.progress("Remote repository is already existing.", permanent=True)
emit.progress("Remote repository already exists.", permanent=True)
emit.progress("Cleaning up")
builder.cleanup()
return 75
Expand All @@ -226,13 +237,10 @@ def _run(self, parsed_args: argparse.Namespace, **kwargs: Any) -> int | None:
if confirm_with_user("Cancel builds?", default=True):
emit.progress("Cancelling builds.")
builder.cancel_builds()
emit.progress("Cleaning up")
builder.cleanup()
returncode = 0
else:
if returncode != 75: # TimeoutError
emit.progress("Cleaning up")
builder.cleanup()
if returncode != 75: # TimeoutError
emit.progress("Cleaning up")
builder.cleanup()
return returncode

def _monitor_and_complete(
Expand Down
6 changes: 5 additions & 1 deletion snapcraft/meta/component_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@


class ComponentMetadata(BaseMetadata):
"""The component.yaml model."""
"""The component.yaml model.
Component hooks are not included in the component's metadata.
Instead, they are included in the snap's metadata.
"""

component: str
type: str
Expand Down
1 change: 1 addition & 0 deletions snapcraft/meta/snap_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ class ComponentMetadata(SnapcraftMetadata): # type: ignore # (pydantic plugin i
summary: SummaryStr
description: str
type: str
hooks: dict[str, models.Hook] | None

@override
class Config(BaseMetadata.Config):
Expand Down
1 change: 1 addition & 0 deletions snapcraft/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ class Component(models.CraftBaseModel):
description: str
type: Literal["test"]
version: Optional[VersionStr] # type: ignore[assignment]
hooks: dict[str, Hook] | None

@pydantic.validator("version")
@classmethod
Expand Down
21 changes: 0 additions & 21 deletions snapcraft/services/remotebuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Snapcraft Lifecycle Service."""

from collections.abc import Collection
from typing import Any

from craft_application import launchpad
from craft_application.services import remotebuild
from overrides import override


class RemoteBuild(remotebuild.RemoteBuildService):
"""Snapcraft remote build service."""

RecipeClass = launchpad.models.SnapRecipe

@override
def _new_recipe(
self,
name: str,
repository: launchpad.models.GitRepository,
architectures: Collection[str] | None = None,
**_: Any, # noqa: ANN401
) -> launchpad.models.Recipe:
"""Create a new recipe."""
return launchpad.models.SnapRecipe.new(
self.lp,
name,
self.lp.username,
architectures=architectures,
project=self._lp_project.name,
git_ref=repository.git_https_url,
)
25 changes: 25 additions & 0 deletions tests/spread/core22/components/expected-snap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: hello-components
version: '1.0'
summary: Build a snap with components
description: Build a snap with components
architectures:
- amd64
base: core22
apps:
hello:
command: bin/hello
confinement: strict
grade: devel
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
components:
share:
summary: Hello World
description: Hello World
type: test
hooks:
install:
plugs:
- home
- network
3 changes: 3 additions & 0 deletions tests/spread/core22/components/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ components:
summary: Hello World
description: Hello World
version: "1.0"
hooks:
install:
plugs: ["home", "network"]

parts:
hello:
Expand Down
10 changes: 8 additions & 2 deletions tests/spread/core22/components/task.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ restore: |
execute: |
snapcraft pack
# assert contents of default partition
# assert snap contents
unsquashfs -dest "snap-contents" "hello-components_1.0_amd64.snap"
if [ ! -e "snap-contents/bin/hello" ]; then
echo "Expected 'bin/hello' in snap contents"
exit 1
fi
# assert snap metadata
if ! diff -u snap-contents/meta/snap.yaml expected-snap.yaml; then
echo "Metadata for the snap is incorrect."
exit 1
fi
# assert component was packed
component_file="hello-components+share_1.0.comp"
if [ ! -e "${component_file}" ]; then
Expand All @@ -38,7 +44,7 @@ execute: |
fi
# assert contents of component metadata
if ! diff component-contents/meta/component.yaml expected-component.yaml; then
if ! diff -u component-contents/meta/component.yaml expected-component.yaml; then
echo "Metadata for the share component is incorrect."
exit 1
fi
25 changes: 25 additions & 0 deletions tests/spread/core24/components/expected-snap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: hello-components
version: '1.0'
summary: Build a snap with components
description: Build a snap with components
architectures:
- amd64
base: core24
apps:
hello:
command: bin/hello
confinement: strict
grade: devel
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
components:
share:
summary: Hello World
description: Hello World
type: test
hooks:
install:
plugs:
- home
- network
3 changes: 3 additions & 0 deletions tests/spread/core24/components/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ components:
summary: Hello World
description: Hello World
version: "1.0"
hooks:
install:
plugs: ["home", "network"]

parts:
hello:
Expand Down
10 changes: 8 additions & 2 deletions tests/spread/core24/components/task.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ restore: |
execute: |
snapcraft pack
# assert contents of default partition
# assert snap contents
unsquashfs -dest "snap-contents" "hello-components_1.0_amd64.snap"
if [ ! -e "snap-contents/bin/hello" ]; then
echo "Expected 'bin/hello' in snap contents"
exit 1
fi
# assert snap metadata
if ! diff -u snap-contents/meta/snap.yaml expected-snap.yaml; then
echo "Metadata for the snap is incorrect."
exit 1
fi
# assert component was packed
component_file="hello-components+share_1.0.comp"
if [ ! -e "${component_file}" ]; then
Expand All @@ -38,7 +44,7 @@ execute: |
fi
# assert contents of component metadata
if ! diff component-contents/meta/component.yaml expected-component.yaml; then
if ! diff -u component-contents/meta/component.yaml expected-component.yaml; then
echo "Metadata for the share component is incorrect."
exit 1
fi
Loading

0 comments on commit a19d949

Please sign in to comment.