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
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()
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))
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
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
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
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))
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)
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()
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
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)), )
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, )
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")
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)), )
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)), )
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
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]
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
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()
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))), )
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
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}")
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"
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()
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"
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))
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()
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()