Пример #1
0
def test_get_snap_project_no_base(snapcraft_yaml, new_dir):
    with pytest.raises(errors.ProjectValidationError) as raised:
        Project.unmarshal(snapcraft_yaml(base=None))

    assert str(raised.value) == (
        "Bad snapcraft.yaml content:\n"
        "- Snap base must be declared when type is not base, kernel or snapd")
Пример #2
0
def _update_project_variables(project: Project, project_vars: Dict[str, str]):
    """Update project fields with values set during lifecycle processing."""
    try:
        if project_vars["version"]:
            project.version = project_vars["version"]
        if project_vars["grade"]:
            project.grade = project_vars["grade"]  # type: ignore
    except pydantic.ValidationError as err:
        _raise_formatted_validation_error(err)
        raise errors.SnapcraftError(f"error setting variable: {err}")
Пример #3
0
def update_project_metadata(
    project: Project,
    *,
    project_vars: Dict[str, str],
    metadata_list: List[ExtractedMetadata],
    assets_dir: Path,
    prime_dir: Path,
) -> None:
    """Set project fields using corresponding adopted entries.

    Fields are validated on assignment by pydantic.

    :param project: The project to update.
    :param project_vars: The variables updated during lifecycle execution.
    :param metadata_list: List containing parsed information from metadata files.

    :raises SnapcraftError: If project update failed.
    """
    _update_project_variables(project, project_vars)

    for metadata in metadata_list:
        # Data specified in the project yaml has precedence over extracted data
        if metadata.title and not project.title:
            project.title = metadata.title

        if metadata.summary and not project.summary:
            project.summary = metadata.summary

        if metadata.description and not project.description:
            project.description = metadata.description

        if metadata.version and not project.version:
            project.version = metadata.version

        if metadata.grade and not project.grade:
            project.grade = metadata.grade  # type: ignore

        emit.debug(f"project icon: {project.icon!r}")
        emit.debug(f"metadata icon: {metadata.icon!r}")

        if not project.icon:
            _update_project_icon(project,
                                 metadata=metadata,
                                 assets_dir=assets_dir)

        _update_project_app_desktop_file(project,
                                         metadata=metadata,
                                         assets_dir=assets_dir,
                                         prime_dir=prime_dir)

    # Fields that must not end empty
    for field in MANDATORY_ADOPTABLE_FIELDS:
        if not getattr(project, field):
            raise errors.SnapcraftError(
                f"Field {field!r} was not adopted from metadata")
Пример #4
0
 def run(self, parsed_args):
     snap_project = get_snap_project()
     yaml_data = process_yaml(snap_project.project_file)
     expanded_yaml_data = extensions.apply_extensions(
         yaml_data,
         arch=get_host_architecture(),
         target_arch=get_host_architecture(),
     )
     Project.unmarshal(expanded_yaml_data)
     emit.message(
         yaml.safe_dump(expanded_yaml_data, indent=4, sort_keys=False))
Пример #5
0
def test_lifecycle_clean_part_names(snapcraft_yaml, project_vars, new_dir, mocker):
    """Clean project inside provider if called with part names."""
    project = Project.unmarshal(snapcraft_yaml(base="core22"))
    run_in_provider_mock = mocker.patch("snapcraft.parts.lifecycle._run_in_provider")

    parts_lifecycle._run_command(
        "clean",
        project=project,
        parse_info={},
        assets_dir=Path(),
        start_time=datetime.now(),
        parallel_build_count=8,
        parsed_args=argparse.Namespace(
            directory=None,
            output=None,
            destructive_mode=False,
            use_lxd=False,
            parts=["part1"],
        ),
    )

    assert run_in_provider_mock.mock_calls == [
        call(
            project,
            "clean",
            argparse.Namespace(
                directory=None,
                output=None,
                destructive_mode=False,
                use_lxd=False,
                parts=["part1"],
            ),
        )
    ]
Пример #6
0
def test_accepted_artifacts(new_dir, emitter, snapcraft_yaml):
    project = Project.unmarshal(snapcraft_yaml)
    assets_dir = Path("snap")

    file_assets = [
        ".snapcraft/state",
        "gui/icon.png",
        "gui/other-icon.png",
        "plugins/plugin1.py",
        "plugins/data-file",
        "hooks/configure",
        "hooks/new-hook",
        "keys/key1.asc",
        "keys/key2.asc",
        "local/file",
        "local/dir/file",
    ]

    for file_asset in file_assets:
        asset_path = assets_dir / file_asset
        asset_path.parent.mkdir(parents=True, exist_ok=True)
        asset_path.touch()

    run_project_checks(project, assets_dir=Path("snap"))

    assert emitter.interactions == []
Пример #7
0
def test_update_project_metadata_desktop_no_apps(project_yaml_data, new_dir):
    yaml_data = project_yaml_data(
        {
            "version": "1.0",
            "adopt-info": "part",
            "parts": {},
        }
    )
    project = Project(**yaml_data)
    metadata = ExtractedMetadata(
        common_id="test.id",
        desktop_file_paths=["metadata/foo.desktop", "metadata/bar.desktop"],
    )

    # create desktop file
    Path("metadata").mkdir()
    Path("metadata/foo.desktop").touch()
    Path("metadata/bar.desktop").touch()

    prj_vars = {"version": "", "grade": "stable"}

    update_project_metadata(
        project,
        project_vars=prj_vars,
        metadata_list=[metadata],
        assets_dir=new_dir / "assets",
        prime_dir=new_dir,
    )

    assert project.apps is None
Пример #8
0
def test_lifecycle_debug_shell(snapcraft_yaml, cmd, new_dir, mocker):
    """Adoptable fields shouldn't be empty after adoption."""
    mocker.patch("craft_parts.executor.Executor.execute",
                 side_effect=Exception)
    mock_shell = mocker.patch("subprocess.run")
    project = Project.unmarshal(snapcraft_yaml(base="core22"))

    with pytest.raises(errors.PartsLifecycleError):
        parts_lifecycle._run_command(
            cmd,
            project=project,
            parse_info={},
            assets_dir=Path(),
            start_time=datetime.now(),
            parallel_build_count=8,
            parsed_args=argparse.Namespace(
                directory=None,
                output=None,
                debug=True,
                destructive_mode=True,
                shell=False,
                shell_after=False,
                use_lxd=False,
                parts=["part1"],
            ),
        )

    assert mock_shell.mock_calls == [call(["bash"], check=False, cwd=None)]
Пример #9
0
def test_lifecycle_run_command_clean(snapcraft_yaml, project_vars, new_dir,
                                     mocker):
    """Clean provider project when called without parts."""
    project = Project.unmarshal(snapcraft_yaml(base="core22"))
    clean_mock = mocker.patch(
        "snapcraft.providers.LXDProvider.clean_project_environments",
        return_value=["instance-name"],
    )

    parts_lifecycle._run_command(
        "clean",
        project=project,
        parse_info={},
        assets_dir=Path(),
        start_time=datetime.now(),
        parallel_build_count=8,
        parsed_args=argparse.Namespace(
            directory=None,
            output=None,
            destructive_mode=False,
            use_lxd=False,
            parts=None,
        ),
    )

    assert clean_mock.mock_calls == [
        call(
            project_name="mytest",
            project_path=new_dir,
            build_on=get_host_architecture(),
            build_for=get_host_architecture(),
        )
    ]
Пример #10
0
def test_update_project_metadata_icon(
    project_yaml_data,
    project_entries,
    icon_exists,
    asset_exists,
    expected_icon,
    new_dir,
):
    yaml_data = project_yaml_data(
        {"version": "1.0", "adopt-info": "part", "parts": {}, **project_entries}
    )
    project = Project(**yaml_data)
    metadata = ExtractedMetadata(icon="metadata_icon.png")

    # create icon file
    if icon_exists:
        Path("metadata_icon.png").touch()

    # create icon file in assets dir
    if asset_exists:
        Path("assets/gui").mkdir(parents=True)
        Path("assets/gui/icon.svg").touch()

    prj_vars = {"version": "", "grade": "stable"}

    update_project_metadata(
        project,
        project_vars=prj_vars,
        metadata_list=[metadata],
        assets_dir=new_dir / "assets",
        prime_dir=new_dir,
    )

    assert project.icon == expected_icon
Пример #11
0
def test_update_project_metadata_fields(
    appstream_file, project_entries, expected, new_dir
):
    yaml_data = {
        "name": "my-project",
        "base": "core22",
        "confinement": "strict",
        "adopt-info": "part",
        "parts": {},
        **project_entries,
    }
    project = Project(**yaml_data)
    metadata = ExtractedMetadata(
        version="4.5.6",
        summary="metadata summary",
        description="metadata description",
        title="metadata title",
        grade="devel",
    )
    prj_vars = {"version": "", "grade": ""}

    update_project_metadata(
        project,
        project_vars=prj_vars,
        metadata_list=[metadata],
        assets_dir=new_dir,
        prime_dir=new_dir,
    )

    assert project.version == expected["version"]
    assert project.summary == expected["summary"]
    assert project.description == expected["description"]
    assert project.title == expected["title"]
    assert project.grade == expected["grade"]
Пример #12
0
def test_lifecycle_clean_managed(snapcraft_yaml, project_vars, new_dir,
                                 mocker):
    project = Project.unmarshal(snapcraft_yaml(base="core22"))
    run_in_provider_mock = mocker.patch(
        "snapcraft.parts.lifecycle._run_in_provider")
    clean_mock = mocker.patch("snapcraft.parts.PartsLifecycle.clean")
    mocker.patch("snapcraft.utils.is_managed_mode", return_value=True)
    mocker.patch(
        "snapcraft.utils.get_managed_environment_home_path",
        return_value=new_dir / "home",
    )

    parts_lifecycle._run_command(
        "clean",
        project=project,
        parse_info={},
        assets_dir=Path(),
        start_time=datetime.now(),
        parallel_build_count=8,
        parsed_args=argparse.Namespace(
            directory=None,
            output=None,
            destructive_mode=False,
            use_lxd=False,
            parts=["part1"],
        ),
    )

    assert run_in_provider_mock.mock_calls == []
    assert clean_mock.mock_calls == [call(part_names=["part1"])]
Пример #13
0
def test_icon(new_dir):
    content = dedent("""\
            name: project-name
            base: core22
            version: "1.0"
            summary: sanity checks
            description: sanity checks
            grade: stable
            confinement: strict
            icon: foo.png

            parts:
              nil:
                plugin: nil
            """)

    yaml_data = yaml.safe_load(content)
    project = Project.unmarshal(yaml_data)

    # Test without icon raises error
    with pytest.raises(errors.SnapcraftError) as raised:
        run_project_checks(project, assets_dir=Path("snap"))

    assert str(raised.value) == "Specified icon 'foo.png' does not exist."

    # Test with icon passes.
    (new_dir / "foo.png").touch()
    run_project_checks(project, assets_dir=Path("snap"))
Пример #14
0
def _run_in_provider(project: Project, command_name: str,
                     parsed_args: "argparse.Namespace") -> None:
    """Pack image in provider instance."""
    emit.debug("Checking build provider availability")
    provider_name = "lxd" if parsed_args.use_lxd else None
    provider = providers.get_provider(provider_name)
    provider.ensure_provider_is_available()

    cmd = ["snapcraft", command_name]

    if hasattr(parsed_args, "parts"):
        cmd.extend(parsed_args.parts)

    if getattr(parsed_args, "output", None):
        cmd.extend(["--output", parsed_args.output])

    if emit.get_mode() == EmitterMode.VERBOSE:
        cmd.append("--verbose")
    elif emit.get_mode() == EmitterMode.QUIET:
        cmd.append("--quiet")
    elif emit.get_mode() == EmitterMode.DEBUG:
        cmd.append("--verbosity=debug")
    elif emit.get_mode() == EmitterMode.TRACE:
        cmd.append("--verbosity=trace")

    if parsed_args.debug:
        cmd.append("--debug")
    if getattr(parsed_args, "shell", False):
        cmd.append("--shell")
    if getattr(parsed_args, "shell_after", False):
        cmd.append("--shell-after")

    if getattr(parsed_args, "enable_manifest", False):
        cmd.append("--enable-manifest")
    build_information = getattr(parsed_args, "manifest_build_information",
                                None)
    if build_information:
        cmd.append("--manifest-build-information")
        cmd.append(build_information)

    output_dir = utils.get_managed_environment_project_path()

    emit.progress("Launching instance...")
    with provider.launched_environment(
            project_name=project.name,
            project_path=Path().absolute(),
            base=project.get_effective_base(),
            bind_ssh=parsed_args.bind_ssh,
            build_on=get_host_architecture(),
            build_for=get_host_architecture(),
    ) as instance:
        try:
            with emit.pause():
                instance.execute_run(cmd, check=True, cwd=output_dir)
            capture_logs_from_instance(instance)
        except subprocess.CalledProcessError as err:
            capture_logs_from_instance(instance)
            raise providers.ProviderError(
                f"Failed to execute {command_name} in instance.") from err
Пример #15
0
def _clean_provider(project: Project,
                    parsed_args: "argparse.Namespace") -> None:
    """Clean the provider environment.

    :param project: The project to clean.
    """
    emit.debug("Clean build provider")
    provider_name = "lxd" if parsed_args.use_lxd else None
    provider = providers.get_provider(provider_name)

    instance_names = provider.clean_project_environments(
        project_name=project.name,
        project_path=Path().absolute(),
        build_on=project.get_build_on(),
        build_for=project.get_build_for(),
    )
    if instance_names:
        emit.message(f"Removed instance: {', '.join(instance_names)}")
    else:
        emit.message("No instances to remove")
Пример #16
0
def test_unexpected_things(new_dir, emitter, snapcraft_yaml):
    project = Project.unmarshal(snapcraft_yaml)
    assets_dir = Path("snap")

    file_assets = [
        "dir1/foo",
        "dir1/keys/key1.asc",
        "dir1/keys/key2.asc",
        "dir1/local/dir/file",
        "dir1/local/file",
        "dir1/plugins/data-file",
        "dir1/plugins/plugin1.py",
        "dir2/foo",
        "dir2/hooks/configure",
        "dir2/hooks/new-hook",
        "gui/icon.jpg",
    ]

    for file_asset in file_assets:
        asset_path = assets_dir / file_asset
        asset_path.parent.mkdir(parents=True, exist_ok=True)
        asset_path.touch()

    run_project_checks(project, assets_dir=Path("snap"))
    assert emitter.assert_progress(
        "The 'snap' directory is meant specifically for snapcraft, but it contains\n"
        "the following non-snapcraft-related paths:\n"
        "- dir1\n"
        "- dir1/foo\n"
        "- dir1/keys\n"
        "- dir1/keys/key1.asc\n"
        "- dir1/keys/key2.asc\n"
        "- dir1/local\n"
        "- dir1/local/dir\n"
        "- dir1/local/dir/file\n"
        "- dir1/local/file\n"
        "- dir1/plugins\n"
        "- dir1/plugins/data-file\n"
        "- dir1/plugins/plugin1.py\n"
        "- dir2\n"
        "- dir2/foo\n"
        "- dir2/hooks\n"
        "- dir2/hooks/configure\n"
        "- dir2/hooks/new-hook\n"
        "- gui/icon.jpg\n"
        "\n"
        "This is unsupported and may cause unexpected behavior. If you must store\n"
        "these files within the 'snap' directory, move them to 'snap/local'\n"
        "which is ignored by snapcraft.",
        permanent=True,
    )
Пример #17
0
def test_lifecycle_pack_managed(cmd, snapcraft_yaml, project_vars, new_dir,
                                mocker):
    project = Project.unmarshal(snapcraft_yaml(base="core22"))
    run_in_provider_mock = mocker.patch(
        "snapcraft.parts.lifecycle._run_in_provider")
    run_mock = mocker.patch("snapcraft.parts.PartsLifecycle.run")
    pack_mock = mocker.patch("snapcraft.pack.pack_snap")
    mocker.patch("snapcraft.meta.snap_yaml.write")
    mocker.patch("snapcraft.utils.is_managed_mode", return_value=True)
    mocker.patch(
        "snapcraft.utils.get_managed_environment_home_path",
        return_value=new_dir / "home",
    )

    parts_lifecycle._run_command(
        cmd,
        project=project,
        parse_info={},
        assets_dir=Path(),
        start_time=datetime.now(),
        parallel_build_count=8,
        parsed_args=argparse.Namespace(
            directory=None,
            output=None,
            debug=False,
            bind_ssh=False,
            enable_manifest=False,
            manifest_image_information=None,
            destructive_mode=False,
            shell=False,
            shell_after=False,
            use_lxd=False,
            parts=[],
        ),
    )

    assert run_in_provider_mock.mock_calls == []
    assert run_mock.mock_calls == [
        call("prime", debug=False, shell=False, shell_after=False)
    ]
    assert pack_mock.mock_calls[:1] == [
        call(
            new_dir / "home/prime",
            output=None,
            compression="xz",
            name="mytest",
            version="0.1",
            target_arch=get_host_architecture(),
        )
    ]
Пример #18
0
    def test_setup_assets_remote_icon(self, desktop_file, yaml_data, new_dir):
        # create primed tree (no icon)
        desktop_file("prime/test.desktop")

        # define project
        # pylint: disable=line-too-long
        project = Project.unmarshal(
            yaml_data(
                {
                    "adopt-info": "part",
                    "icon":
                    "https://dashboard.snapcraft.io/site_media/appmedia/2018/04/Snapcraft-logo-bird.png",
                    "apps": {
                        "app1": {
                            "command": "test.sh",
                            "common-id": "my-test",
                            "desktop": "test.desktop",
                        },
                    },
                }, ))
        # pylint: enable=line-too-long

        setup_assets(
            project,
            assets_dir=Path("snap"),
            project_dir=Path.cwd(),
            prime_dir=Path("prime"),
        )

        # desktop file should be in meta/gui and named after app
        desktop_path = Path("prime/meta/gui/app1.desktop")
        assert desktop_path.is_file()

        # desktop file content should make icon relative to ${SNAP}
        content = desktop_path.read_text()
        assert content == textwrap.dedent("""\
            [Desktop Entry]
            Name=appstream-desktop
            Exec=test-project.app1
            Type=Application
            Icon=${SNAP}/meta/gui/icon.png

            """)

        # icon was downloaded
        icon_path = Path("prime/meta/gui/icon.png")
        assert icon_path.is_file()
        assert icon_path.stat().st_size > 0
Пример #19
0
def run(command_name: str, parsed_args: "argparse.Namespace") -> None:
    """Run the parts lifecycle.

    :raises SnapcraftError: if the step name is invalid, or the project
        yaml file cannot be loaded.
    :raises LegacyFallback: if the project's base is not core22.
    """
    emit.debug(f"command: {command_name}, arguments: {parsed_args}")

    snap_project = get_snap_project()
    yaml_data = process_yaml(snap_project.project_file)
    start_time = datetime.now()
    build_plan = get_build_plan(yaml_data, parsed_args)

    if parsed_args.provider:
        raise errors.SnapcraftError("Option --provider is not supported.")

    # Register our own plugins and callbacks
    plugins.register()
    callbacks.register_prologue(_set_global_environment)
    callbacks.register_pre_step(_set_step_environment)

    build_count = utils.get_parallel_build_count()

    for build_on, build_for in build_plan:
        emit.verbose(f"Running on {build_on} for {build_for}")
        yaml_data_for_arch = apply_yaml(yaml_data, build_on, build_for)
        parse_info = _extract_parse_info(yaml_data_for_arch)
        _expand_environment(
            yaml_data_for_arch,
            parallel_build_count=build_count,
            target_arch=build_for,
        )
        project = Project.unmarshal(yaml_data_for_arch)

        try:
            _run_command(
                command_name,
                project=project,
                parse_info=parse_info,
                parallel_build_count=build_count,
                assets_dir=snap_project.assets_dir,
                start_time=start_time,
                parsed_args=parsed_args,
            )
        except PermissionError as err:
            raise errors.FilePermissionError(err.filename, reason=err.strerror)
Пример #20
0
def test_snapcraft_yaml_load(new_dir, snapcraft_yaml, filename, mocker):
    """Snapcraft.yaml should be parsed as a valid yaml file."""
    yaml_data = snapcraft_yaml(base="core22", filename=filename)
    run_command_mock = mocker.patch("snapcraft.parts.lifecycle._run_command")
    mocker.patch("snapcraft.utils.get_parallel_build_count", return_value=5)

    parts_lifecycle.run(
        "pull",
        argparse.Namespace(
            parts=["part1"],
            destructive_mode=True,
            use_lxd=False,
            provider=None,
            enable_manifest=False,
            manifest_image_information=None,
            bind_ssh=False,
            build_for=None,
        ),
    )

    project = Project.unmarshal(yaml_data)

    if filename == "build-aux/snap/snapcraft.yaml":
        assets_dir = Path("build-aux/snap")
    else:
        assets_dir = Path("snap")

    assert run_command_mock.mock_calls == [
        call(
            "pull",
            project=project,
            parse_info={},
            assets_dir=assets_dir,
            parallel_build_count=5,
            start_time=mocker.ANY,
            parsed_args=argparse.Namespace(
                parts=["part1"],
                destructive_mode=True,
                use_lxd=False,
                provider=None,
                enable_manifest=False,
                manifest_image_information=None,
                bind_ssh=False,
                build_for=None,
            ),
        ),
    ]
Пример #21
0
def test_update_project_metadata_multiple_apps(project_yaml_data, new_dir):
    yaml_data = project_yaml_data(
        {
            "version": "1.0",
            "adopt-info": "part",
            "parts": {},
            "apps": {
                "foo": {
                    "command": "foo",
                    "common-id": "foo.id",
                },
                "bar": {
                    "command": "bar",
                    "common-id": "bar.id",
                },
            },
        }
    )
    project = Project(**yaml_data)
    metadata1 = ExtractedMetadata(
        common_id="foo.id",
        desktop_file_paths=["metadata/foo.desktop"],
    )
    metadata2 = ExtractedMetadata(
        common_id="bar.id",
        desktop_file_paths=["metadata/bar.desktop"],
    )

    # create desktop files
    Path("metadata").mkdir()
    Path("metadata/foo.desktop").touch()
    Path("metadata/bar.desktop").touch()

    prj_vars = {"version": "", "grade": "stable"}

    update_project_metadata(
        project,
        project_vars=prj_vars,
        metadata_list=[metadata1, metadata2],
        assets_dir=new_dir / "assets",
        prime_dir=new_dir,
    )

    assert project.apps is not None
    assert project.apps["foo"].desktop == "metadata/foo.desktop"
    assert project.apps["bar"].desktop == "metadata/bar.desktop"
Пример #22
0
def test_lifecycle_metadata_empty(field, snapcraft_yaml, new_dir):
    """Adoptable fields shouldn't be empty after adoption."""
    yaml_data = snapcraft_yaml(base="core22")
    yaml_data.pop(field)
    yaml_data["adopt-info"] = "part"
    project = Project.unmarshal(yaml_data)

    with pytest.raises(errors.SnapcraftError) as raised:
        update_project_metadata(
            project,
            project_vars={"version": "", "grade": ""},
            metadata_list=[],
            assets_dir=new_dir,
            prime_dir=new_dir,
        )

    assert str(raised.value) == f"Field {field!r} was not adopted from metadata"
Пример #23
0
def test_lifecycle_pack_metadata_error(cmd, snapcraft_yaml, new_dir, mocker):
    project = Project.unmarshal(snapcraft_yaml(base="core22"))
    run_mock = mocker.patch("snapcraft.parts.PartsLifecycle.run")
    mocker.patch("snapcraft.utils.is_managed_mode", return_value=True)
    mocker.patch(
        "snapcraft.utils.get_managed_environment_home_path",
        return_value=new_dir / "home",
    )
    mocker.patch(
        "snapcraft.parts.PartsLifecycle.project_vars",
        new_callable=PropertyMock,
        return_value={
            "version": "0.1",
            "grade": "invalid"
        },  # invalid value
    )
    pack_mock = mocker.patch("snapcraft.pack.pack_snap")
    mocker.patch("snapcraft.meta.snap_yaml.write")

    with pytest.raises(errors.SnapcraftError) as raised:
        parts_lifecycle._run_command(
            cmd,
            project=project,
            assets_dir=Path(),
            start_time=datetime.now(),
            parse_info={},
            parallel_build_count=8,
            parsed_args=argparse.Namespace(
                directory=None,
                output=None,
                debug=False,
                destructive_mode=False,
                shell=False,
                shell_after=False,
                use_lxd=False,
                parts=[],
            ),
        )

    assert str(raised.value) == (
        "error setting grade: unexpected value; permitted: 'stable', 'devel'")
    assert run_mock.mock_calls == [
        call("prime", debug=False, shell=False, shell_after=False)
    ]
    assert pack_mock.mock_calls == []
Пример #24
0
def test_lifecycle_adopt_project_vars(snapcraft_yaml, new_dir):
    """Adoptable fields shouldn't be empty after adoption."""
    yaml_data = snapcraft_yaml(base="core22")
    yaml_data.pop("version")
    yaml_data.pop("grade")
    yaml_data["adopt-info"] = "part"
    project = Project.unmarshal(yaml_data)

    update_project_metadata(
        project,
        project_vars={"version": "42", "grade": "devel"},
        metadata_list=[],
        assets_dir=new_dir,
        prime_dir=new_dir,
    )

    assert project.version == "42"
    assert project.grade == "devel"
Пример #25
0
def test_gadget_missing(yaml_data, new_dir):
    project = Project.unmarshal(
        yaml_data({
            "type": "gadget",
            "version": "1.0",
            "summary": "summary",
            "description": "description",
        }))

    with pytest.raises(errors.SnapcraftError) as raised:
        setup_assets(
            project,
            assets_dir=Path("snap"),
            project_dir=Path.cwd(),
            prime_dir=Path("prime"),
        )

    assert str(raised.value) == "gadget.yaml is required for gadget snaps"
Пример #26
0
    def test_setup_assets_no_apps(self, desktop_file, yaml_data, new_dir):
        desktop_file("prime/test.desktop")
        Path("prime/usr/share/icons").mkdir(parents=True)
        Path("prime/usr/share/icons/icon.svg").touch()
        Path("snap/gui").mkdir()

        # define project
        project = Project.unmarshal(yaml_data({"adopt-info": "part"}))

        # setting up assets does not crash
        setup_assets(
            project,
            assets_dir=Path("snap"),
            project_dir=Path.cwd(),
            prime_dir=Path("prime"),
        )

        assert os.listdir("prime/meta/gui") == []
Пример #27
0
    def test_setup_assets_icon_in_assets_dir(self, desktop_file, yaml_data,
                                             new_dir):
        desktop_file("prime/test.desktop")
        Path("snap/gui").mkdir(parents=True)
        Path("snap/gui/icon.svg").touch()

        # define project
        project = Project.unmarshal(
            yaml_data(
                {
                    "adopt-info": "part",
                    "apps": {
                        "app1": {
                            "command": "test.sh",
                            "common-id": "my-test",
                            "desktop": "test.desktop",
                        },
                    },
                }, ))

        setup_assets(
            project,
            assets_dir=Path("snap"),
            project_dir=Path.cwd(),
            prime_dir=Path("prime"),
        )

        # desktop file should be in meta/gui and named after app
        desktop_path = Path("prime/meta/gui/app1.desktop")
        assert desktop_path.is_file()

        # desktop file content should make icon relative to ${SNAP}
        content = desktop_path.read_text()
        assert content == textwrap.dedent("""\
            [Desktop Entry]
            Name=appstream-desktop
            Exec=test-project.app1
            Type=Application
            Icon=${SNAP}/snap/gui/icon.svg

            """)

        # icon file exists
        Path("prime/snap/gui/icon.svg").is_file()
Пример #28
0
def test_gadget(yaml_data, gadget_yaml_file, new_dir):
    project = Project.unmarshal(
        yaml_data({
            "type": "gadget",
            "version": "1.0",
            "summary": "summary",
            "description": "description",
        }))

    setup_assets(
        project,
        assets_dir=Path("snap"),
        project_dir=Path.cwd(),
        prime_dir=Path("prime"),
    )

    # gadget file should be in meta/
    gadget_path = Path("prime/meta/gadget.yaml")
    assert gadget_path.is_file()
Пример #29
0
def test_lifecycle_shell_after(snapcraft_yaml, cmd, new_dir, mocker):
    """Adoptable fields shouldn't be empty after adoption."""
    last_step = None

    def _fake_execute(_, action: Action, **kwargs):  # pylint: disable=unused-argument
        nonlocal last_step
        last_step = action.step

    mocker.patch("craft_parts.executor.Executor.execute", new=_fake_execute)
    mock_shell = mocker.patch("subprocess.run")
    project = Project.unmarshal(snapcraft_yaml(base="core22"))

    parts_lifecycle._run_command(
        cmd,
        project=project,
        parse_info={},
        assets_dir=Path(),
        start_time=datetime.now(),
        parallel_build_count=8,
        parsed_args=argparse.Namespace(
            directory=None,
            output=None,
            debug=False,
            destructive_mode=True,
            shell=False,
            shell_after=True,
            use_lxd=False,
            parts=["part1"],
        ),
    )

    expected_last_step = Step.PULL
    if cmd == "build":
        expected_last_step = Step.BUILD
    if cmd == "stage":
        expected_last_step = Step.STAGE
    if cmd == "prime":
        expected_last_step = Step.PRIME

    assert last_step == expected_last_step
    assert mock_shell.mock_calls == [call(["bash"], check=False, cwd=None)]
Пример #30
0
def test_update_project_metadata(project_yaml_data, appstream_file, new_dir):
    project = Project.unmarshal(project_yaml_data({"adopt-info": "part"}))
    metadata = ExtractedMetadata(
        common_id="common.id",
        title="title",
        summary="summary",
        description="description",
        version="1.2.3",
        icon="assets/icon.png",
        desktop_file_paths=["assets/file.desktop"],
    )
    assets_dir = Path("assets")
    prime_dir = Path("prime")

    # set up project apps
    project.apps = {
        "app1": _project_app({"command": "bin/app1"}),
        "app2": _project_app({"command": "bin/app2", "common_id": "other.id"}),
        "app3": _project_app({"command": "bin/app3", "common_id": "common.id"}),
    }

    prime_dir.mkdir()
    (prime_dir / "assets").mkdir()
    (prime_dir / "assets/icon.png").touch()
    (prime_dir / "assets/file.desktop").touch()

    prj_vars = {"version": "0.1", "grade": "stable"}
    update_project_metadata(
        project,
        project_vars=prj_vars,
        metadata_list=[metadata],
        assets_dir=assets_dir,
        prime_dir=prime_dir,
    )

    assert project.title == "title"
    assert project.summary == "summary"  # already set in project
    assert project.description == "description"  # already set in project
    assert project.version == "0.1"  # already set in project
    assert project.icon == "assets/icon.png"
    assert project.apps["app3"].desktop == "assets/file.desktop"