예제 #1
0
    def test_pull_is_dirty_if_target_arch_changes(
        self,
        mock_install_build_snaps,
        mock_install_build_packages,
        mock_enable_cross_compilation,
    ):
        # Set the option to error on dirty/outdated steps
        with snapcraft_legacy.config.CLIConfig() as cli_config:
            cli_config.set_outdated_step_action(
                snapcraft_legacy.config.OutdatedStepAction.ERROR)

        mock_install_build_packages.return_value = []
        project_config = self.make_snapcraft_project(
            textwrap.dedent("""\
                parts:
                  part1:
                    plugin: nil
                """))

        project = Project(
            snapcraft_yaml_file_path=self.snapcraft_yaml_file_path,
            target_deb_arch="amd64",
        )
        project_config = project_loader.load_config(project)
        # Pull it with amd64
        lifecycle.execute(steps.PULL, project_config)

        # Reset logging since we only care about the following
        self.fake_logger = fixtures.FakeLogger(level=logging.INFO)
        self.useFixture(self.fake_logger)

        project = Project(
            snapcraft_yaml_file_path=self.snapcraft_yaml_file_path,
            target_deb_arch="armhf",
        )
        project_config = project_loader.load_config(project)
        # Pull it again with armhf. Should catch that the part needs to be
        # re-pulled due to the change in target architecture and raise an
        # error.
        raised = self.assertRaises(errors.StepOutdatedError, lifecycle.execute,
                                   steps.PULL, project_config)

        self.assertThat(self.fake_logger.output,
                        Contains("Setting target machine to 'armhf'"))

        self.assertThat(raised.step, Equals(steps.PULL))
        self.assertThat(raised.part, Equals("part1"))
        self.assertThat(
            raised.report,
            Equals("The 'deb_arch' project option appears to have changed.\n"),
        )
예제 #2
0
def clean(project: "Project", parts, step=None):
    # step defaults to None because that's how it comes from docopt when it's
    # not set.
    if not step:
        step = steps.PULL

    if not parts and step == steps.PULL:
        _cleanup_common_directories_for_step(step, project)
        return

    config = project_loader.load_config(project)

    if not parts and step <= steps.PRIME:
        # If we've been asked to clean stage or prime without being given
        # specific parts, just blow away those directories instead of
        # doing it per part (it would just be a waste of time).
        _cleanup_common_directories_for_step(step, project, parts=config.all_parts)

        # No need to continue if that's all that was required
        if step >= steps.STAGE:
            return

    if parts:
        config.parts.validate(parts)
    else:
        parts = [part.name for part in config.all_parts]

    staged_state = config.get_project_state(steps.STAGE)
    primed_state = config.get_project_state(steps.PRIME)

    _clean_parts(parts, step, config, staged_state, primed_state)

    _cleanup_common_directories(config, project)
예제 #3
0
def get_project_config(snapcraft_yaml_content):
    snapcraft_yaml_path = pathlib.Path("snapcraft.yaml")
    with snapcraft_yaml_path.open("w") as snapcraft_yaml_file:
        print(snapcraft_yaml_content, file=snapcraft_yaml_file)

    project = Project(snapcraft_yaml_file_path=snapcraft_yaml_path.as_posix())
    return project_loader.load_config(project)
예제 #4
0
 def make_snapcraft_project(self, snapcraft_yaml, project_kwargs=None):
     snapcraft_yaml_file_path = self.make_snapcraft_yaml(snapcraft_yaml)
     if project_kwargs is None:
         project_kwargs = dict()
     project = _Project(snapcraft_yaml_file_path=snapcraft_yaml_file_path,
                        **project_kwargs)
     return project_loader.load_config(project)
예제 #5
0
    def make_snapcraft_project(self, parts):
        snapcraft_yaml = fixture_setup.SnapcraftYaml(self.path)
        snapcraft_yaml.update_part("part1", dict(plugin="nil"))
        for part_name, part in parts:
            snapcraft_yaml.update_part(part_name, part)
        self.useFixture(snapcraft_yaml)

        project = Project(
            snapcraft_yaml_file_path=snapcraft_yaml.snapcraft_yaml_file_path)
        return project_loader.load_config(project)
예제 #6
0
def get_project_config(snapcraft_yaml_content, target_deb_arch=None):
    snapcraft_yaml_path = pathlib.Path("Snapcraft.yaml")
    with snapcraft_yaml_path.open("w") as snapcraft_yaml_file:
        print(snapcraft_yaml_content, file=snapcraft_yaml_file)

    snapcraft_project = project.Project(
        snapcraft_yaml_file_path=snapcraft_yaml_path.as_posix(),
        target_deb_arch=target_deb_arch,
    )
    return load_config(snapcraft_project)
예제 #7
0
    def make_snapcraft_project(self, apps):
        snapcraft_yaml = fixture_setup.SnapcraftYaml(self.path)
        snapcraft_yaml.update_part("part1", dict(plugin="nil"))
        for app_name, app in apps:
            snapcraft_yaml.update_app(app_name, app)
        self.useFixture(snapcraft_yaml)

        p = project.Project(
            snapcraft_yaml_file_path=snapcraft_yaml.snapcraft_yaml_file_path)
        return load_config(p)
예제 #8
0
    def _get_snap_packaging(self, **yaml_args):
        if "parts" not in yaml_args:
            yaml_args["parts"] = dict(part1=dict(plugin="nil"))

        snapcraft_yaml = fixture_setup.SnapcraftYaml(self.path, **yaml_args)
        self.useFixture(snapcraft_yaml)

        project = Project(
            snapcraft_yaml_file_path=snapcraft_yaml.snapcraft_yaml_file_path)
        config = load_config(project)

        return _SnapPackaging(project_config=config, extracted_metadata=None)
예제 #9
0
    def test_non_prime_and_no_version(self):
        snapcraft_yaml = fixture_setup.SnapcraftYaml(self.path, version=None)
        snapcraft_yaml.data["adopt-info"] = "test-part"
        snapcraft_yaml.update_part(
            "test-part",
            {
                "plugin": "nil",
                "override-build": "snapcraftctl set-version 1.0"
            },
        )
        self.useFixture(snapcraft_yaml)

        project = Project(
            snapcraft_yaml_file_path=snapcraft_yaml.snapcraft_yaml_file_path)
        project_config = project_loader.load_config(project)

        # This should not fail
        lifecycle.execute(steps.PULL, project_config)
예제 #10
0
    def make_snapcraft_project(self, parts, snap_type=""):
        yaml = textwrap.dedent("""\
            name: test
            base: core18
            version: "1.0"
            summary: test
            description: test
            confinement: strict
            grade: stable
            {type}

            {parts}
            """)

        self.snapcraft_yaml_file_path = self.make_snapcraft_yaml(
            yaml.format(parts=parts, type=snap_type))
        project = snapcraft_legacy.project.Project(
            snapcraft_yaml_file_path=self.snapcraft_yaml_file_path)
        return project_loader.load_config(project)
예제 #11
0
def _execute(  # noqa: C901
    step: steps.Step,
    parts: Sequence[str],
    pack_project: bool = False,
    output: Optional[str] = None,
    shell: bool = False,
    shell_after: bool = False,
    setup_prime_try: bool = False,
    ua_token: Optional[str] = None,
    **kwargs,
) -> "Project":
    # Cleanup any previous errors.
    _clean_provider_error()

    build_provider = get_build_provider(**kwargs)
    build_provider_flags = get_build_provider_flags(
        build_provider, ua_token=ua_token, **kwargs
    )
    apply_host_provider_flags(build_provider_flags)

    is_managed_host = build_provider == "managed-host"

    # Temporary fix to ignore target_arch.
    if kwargs.get("target_arch") is not None and build_provider in ["multipass", "lxd"]:
        echo.warning(
            "Ignoring '--target-arch' flag.  This flag requires --destructive-mode and is unsupported with Multipass and LXD build providers."
        )
        kwargs.pop("target_arch")

    project = get_project(is_managed_host=is_managed_host, **kwargs)
    conduct_project_sanity_check(project, **kwargs)

    project_path = pathlib.Path(project._project_dir)
    if project_path.name in ["build-aux", "snap"]:
        echo.warning(
            f"Snapcraft is running in directory {project_path.name!r}.  If this is the snap assets directory, please run snapcraft from {project_path.parent}."
        )

    if build_provider in ["host", "managed-host"]:
        with ua_manager.ua_manager(ua_token):
            project_config = project_loader.load_config(project)
            lifecycle.execute(step, project_config, parts)
            if pack_project:
                _pack(
                    project.prime_dir,
                    compression=project._snap_meta.compression,
                    output=output,
                )
    else:
        build_provider_class = build_providers.get_provider_for(build_provider)
        try:
            build_provider_class.ensure_provider()
        except build_providers.errors.ProviderNotFound as provider_error:
            if provider_error.prompt_installable:
                if echo.is_tty_connected() and echo.confirm(
                    "Support for {!r} needs to be set up. "
                    "Would you like to do it now?".format(provider_error.provider)
                ):
                    build_provider_class.setup_provider(echoer=echo)
                else:
                    raise provider_error
            else:
                raise provider_error

        with build_provider_class(
            project=project, echoer=echo, build_provider_flags=build_provider_flags
        ) as instance:
            try:
                if shell:
                    # shell means we want to do everything right up to the previous
                    # step and then go into a shell instead of the requested step.
                    # the "snap" target is a special snowflake that has not made its
                    # way to be a proper step.
                    previous_step = None
                    if pack_project:
                        previous_step = steps.PRIME
                    elif step > steps.PULL:
                        previous_step = step.previous_step()
                    # steps.PULL is the first step, so we would directly shell into it.
                    if previous_step:
                        instance.execute_step(previous_step, part_names=parts)
                elif pack_project:
                    instance.pack_project(output=output)
                elif setup_prime_try:
                    instance.expose_prime()
                    instance.execute_step(step, part_names=parts)
                else:
                    instance.execute_step(step, part_names=parts)
            except Exception:
                _retrieve_provider_error(instance)
                if project.debug:
                    instance.shell()
                else:
                    echo.warning(
                        "Run the same command again with --debug to shell into the environment "
                        "if you wish to introspect this failure."
                    )
                    raise
            else:
                if shell or shell_after:
                    instance.shell()
    return project
예제 #12
0
    def setUp(self):
        super().setUp()

        self.useFixture(fixtures.FakeLogger(level=logging.ERROR))

        temp_cwd = fixture_setup.TempCWD()
        self.useFixture(temp_cwd)

        snapcraft_yaml = fixture_setup.SnapcraftYaml(
            temp_cwd.path,
            base="core18",
            parts={"test-part": {
                "plugin": "nil"
            }})
        self.useFixture(snapcraft_yaml)

        project = Project(
            snapcraft_yaml_file_path=snapcraft_yaml.snapcraft_yaml_file_path)

        self.global_state_filepath = project._get_global_state_file_path()

        self.project_config = project_loader.load_config(project)

        self.useFixture(
            fixtures.MockPatchObject(self.project_config,
                                     "get_build_snaps",
                                     return_value={"core18"}))

        self.useFixture(
            fixtures.MockPatch(
                "snapcraft_legacy.internal.lifecycle._runner._Executor.run"))

        self.useFixture(
            fixtures.MockPatch(
                "snapcraft_legacy.internal.repo.snaps.install_snaps"))

        # Avoid unnecessary calls to info.
        channel_map = []
        for arch in ("amd64", "i386", "s390x", "arm64", "armhf", "ppc64el"):
            channel_map.append({
                "channel": {
                    "architecture": arch,
                    "name": "stable",
                    "released-at": "2019-10-15T13:54:06.800280+00:00",
                    "risk": "stable",
                    "track": "latest",
                },
                "confinement": "strict",
                "download": {
                    "deltas": [],
                    "sha3-384":
                    "64d232d6bfa65be14d7f8d84e952d4e372e12021e2c3dbaf70cf2af5e78bf51c4baf9c9107dd6db815064636b781bda6",
                    "size":
                    57151488,
                    "url":
                    "https://api.snapcraft.io/api/v1/snaps/download/CSO04Jhav2yK0uz97cr0ipQRyqg0qQL6_1223.snap",
                },
                "revision": 1223,
            })
        info = {
            "channel-map": channel_map,
            "default-track": None,
            "name": "core18",
            "snap": {
                "name": "core18",
                "publisher": {
                    "display-name": "Canonical",
                    "id": "canonical",
                    "username": "******",
                    "validation": "verified",
                },
                "snap-id": "CSO04Jhav2yK0uz97cr0ipQRyqg0qQL6",
            },
            "snap-id": "CSO04Jhav2yK0uz97cr0ipQRyqg0qQL6",
        }
        self.fake_storeapi_get_info = fixtures.MockPatch(
            "snapcraft_legacy.storeapi._snap_api.SnapAPI.get_info",
            return_value=SnapInfo(info),
        )
        self.useFixture(self.fake_storeapi_get_info)