Esempio n. 1
0
def test_accepted_artifacts(caplog_warning, project):
    assets_dir = pathlib.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()

    conduct_project_sanity_check(project)

    assert len(caplog_warning.records) == 0
Esempio n. 2
0
def cleanbuild(remote, **kwargs):
    """Create a snap using a clean environment managed by a build provider.

    \b
    Examples:
        snapcraft cleanbuild

    The cleanbuild command requires a properly setup lxd environment that
    can connect to external networks. Refer to the "Ubuntu Desktop and
    Ubuntu Server" section on
    https://linuxcontainers.org/lxd/getting-started-cli
    to get started.

    If using a remote, a prior setup is required which is described on:
    https://linuxcontainers.org/lxd/getting-started-cli/#multiple-hosts
    """
    # cleanbuild is a special snow flake, while all the other commands
    # would work with the host as the build_provider it makes little
    # sense in this scenario.
    if sys.platform == "darwin":
        default_provider = "multipass"
    else:
        default_provider = "lxd"

    build_environment = env.BuilderEnvironmentConfig(default=default_provider)
    project = get_project(
        is_managed=build_environment.is_managed_host, **kwargs
    )

    conduct_project_sanity_check(project)

    snap_filename = lifecycle.cleanbuild(
        project=project, echoer=echo, remote=remote, build_environment=build_environment
    )
    echo.info("Retrieved {!r}".format(snap_filename))
Esempio n. 3
0
def cleanbuild():
    """Create a snap using a clean environment managed by a build provider.

    \b
    Examples:
        snapcraft cleanbuild

    The cleanbuild command requires a properly setup lxd environment that
    can connect to external networks. Refer to the "Ubuntu Desktop and
    Ubuntu Server" section on
    https://linuxcontainers.org/lxd/getting-started-cli
    to get started.

    If using a remote, a prior setup is required which is described on:
    https://linuxcontainers.org/lxd/getting-started-cli/#multiple-host

    This command is no longer available when using the base keyword."""
    # We can only end up here with an invalid yaml
    project = get_project()
    conduct_project_sanity_check(project)

    # if we got this far, the environment must be broken
    raise errors.SnapcraftEnvironmentError(
        "The cleanbuild command is no longer supported when using the base keyword."
    )
Esempio n. 4
0
def test_core_unsupported(project):
    project.info.base = "core"

    with pytest.raises(errors.UnsupportedBaseError) as exc_info:
        conduct_project_sanity_check(project)

    assert exc_info.value.base == "core"
Esempio n. 5
0
def _execute(  # noqa: C901
        step: steps.Step,
        parts: str,
        pack_project: bool = False,
        output: str = None,
        shell: bool = False,
        shell_after: bool = False,
        destructive_mode: bool = False,
        **kwargs) -> "Project":
    # fmt: on
    provider = "host" if destructive_mode else None
    build_environment = env.BuilderEnvironmentConfig(force_provider=provider)
    project = get_project(is_managed_host=build_environment.is_managed_host,
                          **kwargs)

    conduct_project_sanity_check(project)

    if build_environment.is_managed_host or build_environment.is_host:
        project_config = project_loader.load_config(project)
        lifecycle.execute(step, project_config, parts)
        if pack_project:
            _pack(project.prime_dir, output=output)
    else:
        build_provider_class = build_providers.get_provider_for(
            build_environment.provider)
        echo.info("Launching a VM.")
        with build_provider_class(project=project, echoer=echo) as instance:
            instance.mount_project()
            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)
                elif pack_project:
                    instance.pack_project(output=output)
                else:
                    instance.execute_step(step)
            except Exception:
                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
Esempio n. 6
0
 def run_check(self):
     snapcraft_yaml = fixture_setup.SnapcraftYaml(
         os.path.dirname(self.snap_asset_dir))
     snapcraft_yaml.update_part("fake", dict(plugin="nil"))
     self.useFixture(snapcraft_yaml)
     project = snapcraft.project.Project(
         is_managed_host=self.is_managed_host,
         snapcraft_yaml_file_path=snapcraft_yaml.snapcraft_yaml_file_path,
     )
     conduct_project_sanity_check(project)
Esempio n. 7
0
def cleanbuild():
    """This command is no longer available when using the base keyword."""
    # We can only end up here with an invalid yaml
    project = get_project()
    conduct_project_sanity_check(project)

    # if we got this far, the environment must be broken
    raise errors.SnapcraftEnvironmentError(
        "The cleanbuild command is no longer supported when using the base keyword."
    )
Esempio n. 8
0
def test_unexpected_things(caplog_warning, project):
    assets_dir = pathlib.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()

    conduct_project_sanity_check(project)
    assert caplog_warning.records[0].message == (
        "The 'snap' directory is meant specifically for snapcraft, but it "
        "contains the following non-snapcraft-related paths, which is "
        "unsupported and will cause unexpected behavior:\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"
        "If you must store these files within the 'snap' directory, move them "
        "to 'snap/local', which is ignored by snapcraft.")
Esempio n. 9
0
def test_icon(tmp_work_path):
    snapcraft_yaml_path = tmp_work_path / "snap/snapcraft.yaml"
    snapcraft_yaml_path.parent.mkdir(parents=True)
    with snapcraft_yaml_path.open("w") as snapcraft_file:
        print(
            dedent("""\
            name: project-name
            base: core18
            version: "1.0"
            summary: sanity checks
            description: sanity checks
            grade: stable
            confinement: strict
            icon: foo.png

            parts:
              nil:
                plugin: nil
            """),
            file=snapcraft_file,
        )

    project = Project(
        is_managed_host=False,
        snapcraft_yaml_file_path=snapcraft_yaml_path.as_posix(),
    )

    # Test without icon raises error
    with pytest.raises(
            snapcraft.internal.errors.SnapcraftEnvironmentError) as exc_info:
        conduct_project_sanity_check(project)

    assert exc_info.value.get_brief(
    ) == "Specified icon 'foo.png' does not exist."

    # Test with icon passes.
    (tmp_work_path / "foo.png").touch()
    conduct_project_sanity_check(project)
Esempio n. 10
0
def _execute(  # noqa: C901
        step: steps.Step,
        parts: str,
        pack_project: bool = False,
        output: str = None,
        shell: bool = False,
        shell_after: bool = False,
        destructive_mode: bool = False,
        **kwargs) -> "Project":
    _clean_provider_error()
    provider = "host" if destructive_mode else None
    build_environment = env.BuilderEnvironmentConfig(force_provider=provider)
    project = get_project(is_managed_host=build_environment.is_managed_host,
                          **kwargs)

    echo.wrapped("Using {!r}: Project assets will be "
                 "searched for from the {!r} directory.".format(
                     project.info.snapcraft_yaml_file_path,
                     os.path.relpath(project._get_snapcraft_assets_dir(),
                                     project._project_dir),
                 ))

    conduct_project_sanity_check(project)

    if build_environment.is_managed_host or build_environment.is_host:
        project_config = project_loader.load_config(project)
        lifecycle.execute(step, project_config, parts)
        if pack_project:
            _pack(project.prime_dir, output=output)
    else:
        build_provider_class = build_providers.get_provider_for(
            build_environment.provider)
        try:
            build_provider_class.ensure_provider()
        except build_providers.errors.ProviderNotFound as provider_error:
            if provider_error.prompt_installable:
                click.echo(str(provider_error))
                if click.confirm("Would you like to install it now?"):
                    build_provider_class.setup_provider(echoer=echo)
                else:
                    raise provider_error
            else:
                raise provider_error

        echo.info("Launching a VM.")
        with build_provider_class(project=project, echoer=echo) as instance:
            instance.mount_project()
            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)
                elif pack_project:
                    instance.pack_project(output=output)
                else:
                    instance.execute_step(step)
            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
Esempio n. 11
0
def _execute(  # noqa: C901
    step: steps.Step,
    parts: str,
    pack_project: bool = False,
    output: Optional[str] = None,
    shell: bool = False,
    shell_after: bool = False,
    setup_prime_try: bool = False,
    **kwargs,
) -> "Project":
    # Cleanup any previous errors.
    _clean_provider_error()

    build_provider = get_build_provider(**kwargs)
    build_provider_flags = get_build_provider_flags(build_provider, **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"]:
        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)
                elif pack_project:
                    instance.pack_project(output=output)
                elif setup_prime_try:
                    instance.expose_prime()
                    instance.execute_step(step)
                else:
                    instance.execute_step(step)
            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
Esempio n. 12
0
def _execute(  # noqa: C901
    step: steps.Step,
    parts: str,
    pack_project: bool = False,
    output: Optional[str] = None,
    shell: bool = False,
    shell_after: bool = False,
    setup_prime_try: bool = False,
    **kwargs,
) -> "Project":
    # Cleanup any previous errors.
    _clean_provider_error()

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

    is_managed_host = build_provider == "managed-host"

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

    if build_provider in ["host", "managed-host"]:
        project_config = project_loader.load_config(project)
        lifecycle.execute(step, project_config, parts)
        if pack_project:
            _pack(project.prime_dir, 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 that 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:
            instance.mount_project()
            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)
                elif pack_project:
                    instance.pack_project(output=output)
                elif setup_prime_try:
                    instance.expose_prime()
                    instance.execute_step(step)
                else:
                    instance.execute_step(step)
            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
Esempio n. 13
0
def _execute(  # noqa: C901
    step: steps.Step,
    parts: str,
    pack_project: bool = False,
    output: str = None,
    shell: bool = False,
    shell_after: bool = False,
    **kwargs
) -> "Project":
    # fmt: on
    if sys.platform == "darwin":
        default_provider = "multipass"
    else:
        default_provider = "host"

    build_environment = env.BuilderEnvironmentConfig(default=default_provider)
    project = get_project(is_managed_host=build_environment.is_managed_host, **kwargs)

    conduct_project_sanity_check(project)

    #  When we are ready to pull the trigger we will trigger this when
    # project.info.base is set
    if build_environment.is_multipass:
        build_provider_class = build_providers.get_provider_for(
            build_environment.provider
        )
        echo.info("Launching a VM.")
        with build_provider_class(project=project, echoer=echo) as instance:
            instance.mount_project()
            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)
                elif pack_project:
                    instance.pack_project(output=output)
                else:
                    instance.execute_step(step)
            except Exception:
                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()
    elif build_environment.is_managed_host or build_environment.is_host:
        project_config = project_loader.load_config(project)
        lifecycle.execute(step, project_config, parts)
        if pack_project:
            _pack(project.prime_dir, output=output)
    else:
        # containerbuild takes a snapcraft command name, not a step
        lifecycle.containerbuild(command=step.name, project=project, args=parts)
        if pack_project:
            _pack(project.prime_dir, output=output)
    return project
Esempio n. 14
0
 def run_check(self):
     project = snapcraft.project.Project(
         is_managed_host=self.is_managed_host)
     conduct_project_sanity_check(project)
Esempio n. 15
0
def test_no_snap_dir(caplog_warning, project):
    conduct_project_sanity_check(project)
    assert len(caplog_warning.records) == 0
Esempio n. 16
0
def _execute(  # noqa: C901
        step: steps.Step,
        parts: str,
        pack_project: bool = False,
        output: str = None,
        shell: bool = False,
        shell_after: bool = False,
        destructive_mode: bool = False,
        **kwargs) -> "Project":
    # fmt: on
    _clean_provider_error()
    provider = "host" if destructive_mode else None
    build_environment = env.BuilderEnvironmentConfig(force_provider=provider)
    try:
        conduct_build_environment_sanity_check(build_environment.provider)
    except MultipassMissingInstallableError as e:
        click.echo("You need multipass installed to build snaps "
                   "(https://github.com/CanonicalLtd/multipass).")
        if click.confirm("Would you like to install it now?"):
            _install_multipass()
        else:
            raise errors.SnapcraftEnvironmentError(
                "multipass is required to continue.") from e

    project = get_project(is_managed_host=build_environment.is_managed_host,
                          **kwargs)

    conduct_project_sanity_check(project)

    if build_environment.is_managed_host or build_environment.is_host:
        project_config = project_loader.load_config(project)
        lifecycle.execute(step, project_config, parts)
        if pack_project:
            _pack(project.prime_dir, output=output)
    else:
        build_provider_class = build_providers.get_provider_for(
            build_environment.provider)
        echo.info("Launching a VM.")
        with build_provider_class(project=project, echoer=echo) as instance:
            instance.mount_project()
            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)
                elif pack_project:
                    instance.pack_project(output=output)
                else:
                    instance.execute_step(step)
            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