Example #1
0
def pack(directory, output=None):
    mksquashfs_path = file_utils.get_tool_path("mksquashfs")

    snap = _snap_data_from_dir(directory)
    # Verify that the snap command is available and use it to
    # validate the layout.
    # The snap command will most likely be found as it lives in
    # core and the snapcraft snap lives on top of it (on the side
    # rather).
    if os.path.exists(_SNAP_PATH):
        _run_snap_pack_verification(directory=directory)
    elif snap.get("license"):
        logger.warning(
            "Could not find {!r}, validation of the license string will only "
            "take place once pushed to the store.".format(_SNAP_PATH))

    output_snap_name = output or common.format_snap_name(snap)
    # If a .snap-build exists at this point, when we are about to override
    # the snap blob, it is stale. We rename it so user have a chance to
    # recover accidentally lost assertions.
    snap_build = output_snap_name + "-build"
    if os.path.isfile(snap_build):
        _new = "{}.{}".format(snap_build, int(time.time()))
        logger.warning("Renaming stale build assertion to {}".format(_new))
        os.rename(snap_build, _new)

    _run_mksquashfs(
        mksquashfs_path,
        directory=directory,
        snap_name=snap["name"],
        snap_type=snap["type"],
        output_snap_name=output_snap_name,
    )

    return output_snap_name
Example #2
0
def _get_icon_from_snap_file(snap_path):
    icon_file = None
    with tempfile.TemporaryDirectory() as temp_dir:
        unsquashfs_path = get_tool_path("unsquashfs")
        try:
            output = subprocess.check_output(
                [
                    unsquashfs_path,
                    "-d",
                    os.path.join(temp_dir, "squashfs-root"),
                    snap_path,
                    "-e",
                    "meta/gui",
                ]
            )
        except subprocess.CalledProcessError:
            raise SnapDataExtractionError(os.path.basename(snap_path))
        logger.debug("Output extracting icon from snap: %s", output)
        for extension in ("png", "svg"):
            icon_name = "icon.{}".format(extension)
            icon_path = os.path.join(temp_dir, "squashfs-root", "meta/gui", icon_name)
            if os.path.exists(icon_path):
                icon_file = open(icon_path, "rb")
                break
        try:
            yield icon_file
        finally:
            if icon_file is not None:
                icon_file.close()
Example #3
0
def clear_execstack(*, elf_files: FrozenSet[elf.ElfFile]) -> None:
    """Clears the execstack for the relevant elf_files

    param elf.ElfFile elf_files: the full list of elf files to analyze
                                 and clear the execstack if present.
    """
    execstack_path = file_utils.get_tool_path("execstack")
    elf_files_with_execstack = [e for e in elf_files if e.execstack_set]

    if elf_files_with_execstack:
        formatted_items = [
            "- {}".format(e.path) for e in elf_files_with_execstack
        ]
        logger.warning(
            "The execstacks are going to be cleared for the following "
            "files:\n{}\n"
            "To disable this behavior set "
            "`build-attributes: [keep-execstack]` "
            "for the part.".format("\n".join(formatted_items)))

    for elf_file in elf_files_with_execstack:
        try:
            subprocess.check_call(
                [execstack_path, "--clear-execstack", elf_file.path])
        except subprocess.CalledProcessError:
            logger.warning("Failed to clear execstack for {!r}".format(
                elf_file.path))
Example #4
0
def pack(directory, output=None):
    mksquashfs_path = file_utils.get_tool_path('mksquashfs')

    # Check for our prerequesite external command early
    repo.check_for_command(mksquashfs_path)

    snap = _snap_data_from_dir(directory)
    output_snap_name = output or common.format_snap_name(snap)

    # If a .snap-build exists at this point, when we are about to override
    # the snap blob, it is stale. We rename it so user have a chance to
    # recover accidentally lost assertions.
    snap_build = output_snap_name + '-build'
    if os.path.isfile(snap_build):
        _new = '{}.{}'.format(snap_build, int(time.time()))
        logger.warning('Renaming stale build assertion to {}'.format(_new))
        os.rename(snap_build, _new)

    _run_mksquashfs(mksquashfs_path,
                    directory=directory,
                    snap_name=snap['name'],
                    snap_type=snap['type'],
                    output_snap_name=output_snap_name)

    return output_snap_name
Example #5
0
def pack(directory, output=None):
    mksquashfs_path = file_utils.get_tool_path("mksquashfs")

    # Check for our prerequesite external command early
    repo.check_for_command(mksquashfs_path)

    snap = _snap_data_from_dir(directory)
    output_snap_name = output or common.format_snap_name(snap)

    # If a .snap-build exists at this point, when we are about to override
    # the snap blob, it is stale. We rename it so user have a chance to
    # recover accidentally lost assertions.
    snap_build = output_snap_name + "-build"
    if os.path.isfile(snap_build):
        _new = "{}.{}".format(snap_build, int(time.time()))
        logger.warning("Renaming stale build assertion to {}".format(_new))
        os.rename(snap_build, _new)

    _run_mksquashfs(
        mksquashfs_path,
        directory=directory,
        snap_name=snap["name"],
        snap_type=snap["type"],
        output_snap_name=output_snap_name,
    )

    return output_snap_name
Example #6
0
def pack(directory, output=None):
    mksquashfs_path = file_utils.get_tool_path("mksquashfs")

    snap = _snap_data_from_dir(directory)
    _run_snap_pack_verification(directory=directory)

    output_snap_name = output or common.format_snap_name(snap)
    # If a .snap-build exists at this point, when we are about to override
    # the snap blob, it is stale. We rename it so user have a chance to
    # recover accidentally lost assertions.
    snap_build = output_snap_name + "-build"
    if os.path.isfile(snap_build):
        _new = "{}.{}".format(snap_build, int(time.time()))
        logger.warning("Renaming stale build assertion to {}".format(_new))
        os.rename(snap_build, _new)

    _run_mksquashfs(
        mksquashfs_path,
        directory=directory,
        snap_name=snap["name"],
        snap_type=snap["type"],
        output_snap_name=output_snap_name,
    )

    return output_snap_name
Example #7
0
def clear_execstack(*, elf_files: FrozenSet[elf.ElfFile]) -> None:
    """Clears the execstack for the relevant elf_files

    param elf.ElfFile elf_files: the full list of elf files to analyze
                                 and clear the execstack if present.
    """
    execstack_path = file_utils.get_tool_path('execstack')
    elf_files_with_execstack = [e for e in elf_files if e.execstack_set]

    if elf_files_with_execstack:
        formatted_items = [
            '- {}'.format(e.path) for e in elf_files_with_execstack
        ]
        logger.warning(
            'The execstacks are going to be cleared for the following '
            'files:\n{}\n'
            'To disable this behavior set '
            '`build-properties: [keep-execstack]` '
            'for the part.'.format('\n'.join(formatted_items)))

    for elf_file in elf_files_with_execstack:
        try:
            subprocess.check_call(
                [execstack_path, '--clear-execstack', elf_file.path])
        except subprocess.CalledProcessError:
            logger.warning('Failed to clear execstack for {!r}'.format(
                elf_file.path))
Example #8
0
 def __init__(self, *, source_path, target_path):
     delta_format = 'xdelta3'
     delta_tool_path = file_utils.get_tool_path('xdelta3')
     super().__init__(source_path=source_path,
                      target_path=target_path,
                      delta_file_extname='xdelta3',
                      delta_format=delta_format,
                      delta_tool_path=delta_tool_path)
Example #9
0
    def test_get_tool_from_docker_snap_path(
        self, monkeypatch, in_snap, tool_path, fake_exists
    ):
        abs_tool_path = pathlib.Path("/snap/snapcraft/current") / tool_path
        fake_exists.paths = [abs_tool_path]
        monkeypatch.setattr(common, "is_process_container", lambda: True)

        assert file_utils.get_tool_path("tool-command") == abs_tool_path.as_posix()
Example #10
0
def setup(*, base: str, snap_arch: str, size: str, image_path: str) -> None:
    """Setup a build image for base and snap_arch of size at image_path.

    Example usage:
    >>> from snapcraft.internal.build_providers import _images
    >>> _images.setup(base="core18", snap_arch="amd64", size="10G",
                      image_path="images/core18.qcow2")

    :param str base: the base of the build image to setup.
    :param str snap_arch: the architecture of the base for the build image.
    :param str size: the size of the disk for the build image.
    :param str image_path: the path to create the build image.
    :raises errors.BuildImageForBaseMissing:
        if there is no build image defined for the requested base or snap
        architecture.
    :raises errors.BuildImageRequestError:
        upon a network related issue that prevents download of the build image.
    :raises errors.BuildImageChecksumError:
        if the resulting downloaded build image does not match the expected
        checksum.
    :raises errors.BuildImageSetupError:
        if a build image cannot be created due to tooling or other system
        issues (e.g.; space issues).
    """
    try:
        image = _get_build_images(base)[snap_arch]
    except KeyError as key_error:
        raise errors.BuildImageForBaseMissing(
            base=base, snap_arch=snap_arch
        ) from key_error

    cached_file = image.get()

    if os.path.dirname(image_path):
        os.makedirs(os.path.dirname(image_path), exist_ok=True)
    qemu_img_cmd = get_tool_path("qemu-img")
    # qemu-img parameters:
    # -q: quiet.
    # -f: first image format.
    # -b: backing file.
    try:
        subprocess.check_call(
            [
                qemu_img_cmd,
                "create",
                "-q",
                "-f",
                "qcow2",
                "-b",
                cached_file,
                image_path,
                size,
            ]
        )
    except subprocess.CalledProcessError as process_error:
        raise errors.BuildImageSetupError(
            exit_code=process_error.returncode
        ) from process_error
Example #11
0
    def test_get_tool_from_snapcraft_snap_path(self):
        self.useFixture(fixture_setup.FakeSnapcraftIsASnap())

        snap_root = os.path.join(os.path.sep, "snap", "snapcraft", "current")
        self._patch(snap_root)

        self.assertThat(
            file_utils.get_tool_path("tool-command"),
            Equals(os.path.join(snap_root, self.tool_path)),
        )
Example #12
0
 def __init__(self, *, source_path, target_path):
     delta_format = "xdelta3"
     delta_tool_path = file_utils.get_tool_path("xdelta3")
     super().__init__(
         source_path=source_path,
         target_path=target_path,
         delta_file_extname="xdelta3",
         delta_format=delta_format,
         delta_tool_path=delta_tool_path,
     )
Example #13
0
 def __init__(self, *, source_path, target_path):
     delta_format = "xdelta3"
     delta_tool_path = file_utils.get_tool_path("xdelta3")
     super().__init__(
         source_path=source_path,
         target_path=target_path,
         delta_file_extname="xdelta3",
         delta_format=delta_format,
         delta_tool_path=delta_tool_path,
     )
Example #14
0
    def __init__(
        self, *, dynamic_linker: str, root_path: str, preferred_patchelf_path=None
    ) -> None:
        """Create a Patcher instance.

        :param str dynamic_linker: the path to the dynamic linker to set the
                                   elf file to.
        :param str root_path: the base path for the snap to determine
                              if use of $ORIGIN is possible.
        :param str preferred_patchelf_path: patch the necessary elf_files with
                                        this patchelf.
        """
        self._dynamic_linker = dynamic_linker
        self._root_path = root_path

        if preferred_patchelf_path:
            self._patchelf_cmd = preferred_patchelf_path
        else:
            self._patchelf_cmd = file_utils.get_tool_path("patchelf")

        self._strip_cmd = file_utils.get_tool_path("strip")
Example #15
0
    def __init__(
        self, *, dynamic_linker: str, root_path: str, preferred_patchelf_path=None
    ) -> None:
        """Create a Patcher instance.

        :param str dynamic_linker: the path to the dynamic linker to set the
                                   elf file to.
        :param str root_path: the base path for the snap to determine
                              if use of $ORIGIN is possible.
        :param str preferred_patchelf_path: patch the necessary elf_files with
                                        this patchelf.
        """
        self._dynamic_linker = dynamic_linker
        self._root_path = root_path

        if preferred_patchelf_path:
            self._patchelf_cmd = preferred_patchelf_path
        else:
            self._patchelf_cmd = file_utils.get_tool_path("patchelf")

        self._strip_cmd = file_utils.get_tool_path("strip")
Example #16
0
    def test_get_tool_from_docker_snap_path(self):
        self.useFixture(fixture_setup.FakeSnapcraftIsASnap())

        snap_root = os.path.join(os.path.sep, "snap", "snapcraft", "current")
        self._patch(snap_root)

        with mock.patch("snapcraft.internal.common.is_docker_instance",
                        return_value=True):
            self.assertThat(
                file_utils.get_tool_path("tool-command"),
                Equals(os.path.join(snap_root, self.tool_path)),
            )
Example #17
0
    def test_get_tool_from_host_path(self):
        self._patch(os.path.sep)

        patcher = mock.patch("shutil.which",
                             return_value=os.path.join(os.path.sep,
                                                       self.tool_path))
        patcher.start()
        self.addCleanup(patcher.stop)

        self.assertThat(
            file_utils.get_tool_path("tool-command"),
            Equals(os.path.join(os.path.sep, self.tool_path)),
        )
Example #18
0
def _get_data_from_snap_file(snap_path):
    with tempfile.TemporaryDirectory() as temp_dir:
        unsquashfs_path = get_tool_path('unsquashfs')
        output = subprocess.check_output([
            unsquashfs_path, '-d',
            os.path.join(temp_dir, 'squashfs-root'), snap_path, '-e',
            os.path.join('meta', 'snap.yaml')
        ])
        logger.debug(output)
        with open(os.path.join(temp_dir, 'squashfs-root', 'meta',
                               'snap.yaml')) as yaml_file:
            snap_yaml = yaml.load(yaml_file)
    return snap_yaml
Example #19
0
 def _get_snap_deb_arch(self, snap_filename):
     with tempfile.TemporaryDirectory() as temp_dir:
         unsquashfs_path = file_utils.get_tool_path('unsquashfs')
         output = subprocess.check_output(
             [unsquashfs_path, '-d',
              os.path.join(temp_dir, 'squashfs-root'),
              snap_filename, '-e', os.path.join('meta', 'snap.yaml')])
         logger.debug(output)
         with open(os.path.join(
                 temp_dir, 'squashfs-root', 'meta', 'snap.yaml')
         ) as yaml_file:
             snap_yaml = yaml.load(yaml_file)
     # XXX: add multiarch support later
     return snap_yaml['architectures'][0]
Example #20
0
def _get_data_from_snap_file(snap_path):
    with tempfile.TemporaryDirectory() as temp_dir:
        unsquashfs_path = get_tool_path("unsquashfs")
        output = subprocess.check_output([
            unsquashfs_path,
            "-d",
            os.path.join(temp_dir, "squashfs-root"),
            snap_path,
            "-e",
            os.path.join("meta", "snap.yaml"),
        ])
        logger.debug(output)
        with open(os.path.join(temp_dir, "squashfs-root", "meta",
                               "snap.yaml")) as yaml_file:
            snap_yaml = yaml_utils.load(yaml_file)
    return snap_yaml
Example #21
0
    def __init__(
        self,
        *,
        source_path: str,
        target_path: str,
        delta_tool: str,
        delta_format: str,
        delta_file_extname: str = "delta"
    ) -> None:
        self.source_path = source_path
        self.target_path = target_path
        self.delta_format = delta_format
        self.delta_file_extname = delta_file_extname
        self.delta_tool_path = file_utils.get_tool_path(delta_tool)

        # some pre-checks
        self._check_properties()
        self._check_file_existence()
Example #22
0
    def test_get_tool_from_docker_deb_path(self):
        self._patch(os.path.sep)

        patcher = mock.patch(
            "shutil.which",
            return_value=os.path.join(os.path.sep, "bin",
                                      os.path.basename(self.tool_path)),
        )
        patcher.start()
        self.addCleanup(patcher.stop)

        with mock.patch("snapcraft.internal.common.is_docker_instance",
                        return_value=True):
            self.assertThat(
                file_utils.get_tool_path("tool-command"),
                Equals(
                    os.path.join(os.path.sep, "bin",
                                 os.path.basename(self.tool_path))),
            )
Example #23
0
def _get_data_from_snap_file(snap_path):
    with tempfile.TemporaryDirectory() as temp_dir:
        unsquashfs_path = get_tool_path("unsquashfs")
        try:
            output = subprocess.check_output([
                unsquashfs_path,
                "-d",
                os.path.join(temp_dir, "squashfs-root"),
                snap_path,
                "-e",
                os.path.join("meta", "snap.yaml"),
            ])
        except subprocess.CalledProcessError:
            raise SnapDataExtractionError(os.path.basename(snap_path))
        logger.debug(output)
        with open(os.path.join(temp_dir, "squashfs-root", "meta",
                               "snap.yaml")) as yaml_file:
            snap_yaml = yaml_utils.load(yaml_file)
    return snap_yaml
Example #24
0
def _pack(directory: str,
          *,
          compression: Optional[str] = None,
          output: Optional[str]) -> None:
    snap_path = file_utils.get_tool_path("snap")

    command = [snap_path, "pack"]
    # When None, just use snap pack's default settings.
    if compression is not None:
        if compression != "xz":
            echo.warning(
                f"EXPERIMENTAL: Setting the squash FS compression to {compression!r}."
            )
        command.extend(["--compression", compression])
    if output is not None:
        command.extend(["--filename", output])
    command.append(directory)

    snap_filename = _run_pack(command)
    echo.info(f"Snapped {snap_filename}")
Example #25
0
 def _get_snap_deb_arch(self, snap_filename):
     with tempfile.TemporaryDirectory() as temp_dir:
         unsquashfs_path = file_utils.get_tool_path("unsquashfs")
         output = subprocess.check_output([
             unsquashfs_path,
             "-d",
             os.path.join(temp_dir, "squashfs-root"),
             snap_filename,
             "-e",
             # cygwin unsquashfs uses unix paths.
             Path("meta", "snap.yaml").as_posix(),
         ])
         logger.debug(output)
         with open(
                 os.path.join(temp_dir, "squashfs-root", "meta",
                              "snap.yaml")) as yaml_file:
             snap_yaml = yaml_utils.load(yaml_file)
     # XXX: add multiarch support later
     try:
         return snap_yaml["architectures"][0]
     except KeyError:
         return "all"
Example #26
0
def _get_icon_from_snap_file(snap_path):
    icon_file = None
    with tempfile.TemporaryDirectory() as temp_dir:
        unsquashfs_path = get_tool_path('unsquashfs')
        output = subprocess.check_output([
            unsquashfs_path, '-d',
            os.path.join(temp_dir, 'squashfs-root'), snap_path, '-e',
            'meta/gui'
        ])
        logger.debug("Output extracting icon from snap: %s", output)
        for extension in ('png', 'svg'):
            icon_name = 'icon.{}'.format(extension)
            icon_path = os.path.join(temp_dir, 'squashfs-root', 'meta/gui',
                                     icon_name)
            if os.path.exists(icon_path):
                icon_file = open(icon_path, 'rb')
                break
        try:
            yield icon_file
        finally:
            if icon_file is not None:
                icon_file.close()
Example #27
0
 def _get_snap_deb_arch(self, snap_filename):
     with tempfile.TemporaryDirectory() as temp_dir:
         unsquashfs_path = file_utils.get_tool_path("unsquashfs")
         output = subprocess.check_output(
             [
                 unsquashfs_path,
                 "-d",
                 os.path.join(temp_dir, "squashfs-root"),
                 snap_filename,
                 "-e",
                 os.path.join("meta", "snap.yaml"),
             ]
         )
         logger.debug(output)
         with open(
             os.path.join(temp_dir, "squashfs-root", "meta", "snap.yaml")
         ) as yaml_file:
             snap_yaml = yaml.safe_load(yaml_file)
     # XXX: add multiarch support later
     try:
         return snap_yaml["architectures"][0]
     except KeyError:
         return "all"
Example #28
0
def clear_execstack(*, elf_files: FrozenSet[elf.ElfFile]) -> None:
    """Clears the execstack for the relevant elf_files

    param elf.ElfFile elf_files: the full list of elf files to analyze
                                 and clear the execstack if present.
    """
    execstack_path = file_utils.get_tool_path("execstack")
    elf_files_with_execstack = [e for e in elf_files if e.execstack_set]

    if elf_files_with_execstack:
        formatted_items = ["- {}".format(e.path) for e in elf_files_with_execstack]
        logger.warning(
            "The execstacks are going to be cleared for the following "
            "files:\n{}\n"
            "To disable this behavior set "
            "`build-attributes: [keep-execstack]` "
            "for the part.".format("\n".join(formatted_items))
        )

    for elf_file in elf_files_with_execstack:
        try:
            subprocess.check_call([execstack_path, "--clear-execstack", elf_file.path])
        except subprocess.CalledProcessError:
            logger.warning("Failed to clear execstack for {!r}".format(elf_file.path))
Example #29
0
    def test_get_tool_from_snapcraft_snap_path(self, in_snap, tool_path, fake_exists):
        abs_tool_path = pathlib.Path("/snap/snapcraft/current") / tool_path
        fake_exists.paths = [abs_tool_path]

        assert file_utils.get_tool_path("tool-command") == abs_tool_path.as_posix()
Example #30
0
    def test_get_tool_from_host_path(self, monkeypatch, tool_path, fake_exists):
        abs_tool_path = pathlib.Path("/") / tool_path
        fake_exists.paths = [abs_tool_path]
        monkeypatch.setattr(shutil, "which", lambda x: abs_tool_path.as_posix())

        assert file_utils.get_tool_path("tool-command") == abs_tool_path.as_posix()