def __call__( self, location: Location, system_context: SystemContext, *args: typing.Any, **kwargs: typing.Any, ) -> None: """Execute command.""" h2( f'Running tests for system "{system_context.system_name}"', verbosity=2, ) env = _environment(system_context) for test in _find_tests(system_context): trace(f"{system_context.system_name}::Running test {test}...") test_result = run( test, system_context.system_name, env=env, returncode=None, work_directory=system_context.fs_directory, ) if test_result.returncode == 0: success( f'{system_context.system_name}::Test "{test}"', verbosity=3, ) else: report_completed_process(msg, test_result) fail(f'{system_context.system_name}::Test "{test}"')
def run( *args: str, work_directory: str = "", check: bool = True, env: typing.Any = os.environ, ## What is a better type for this? ) -> subprocess.CompletedProcess: env["LC_ALL"] = "en_US.UTF-8" cwd = work_directory or None trace('Running: "{}"...'.format('" "'.join(args))) result = subprocess.run( args, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False, cwd=cwd, ) if result.returncode != 0: debug( f'Command returned with exit code {result.returncode}:\nSTDOUT:\n{result.stdout.decode("utf-8")}\nSTDERR:\n{result.stderr.decode("utf-8")}.' ) if result.returncode == 2 and check: raise subprocess.CalledProcessError( returncode=result.returncode, cmd=args, output=result.stdout, stderr=result.stderr, ) return result
def execute_with_system_mounted(to_execute: typing.Callable[[str, str], int], *, image_file: str, tmp_dir: str) -> int: assert os.path.isfile(image_file) with disk.NbdDevice(image_file, disk_format="raw", read_only=True) as device: verbose("Mounting EFI...") device.wait_for_device_node(partition=1) with mount.Mount( device.device(1), os.path.join(tmp_dir, "EFI"), fs_type="vfat", options="ro", ) as efi: verbose("Mounting root filesystem...") with mount.Mount( device.device(2), os.path.join(tmp_dir, "root"), fs_type="squashfs", options="ro", ) as root: trace(f'Executing with EFI "{efi}" and root "{root}".') result = to_execute(efi, root) return result
def copy_efi_partition(*, image_file: str, efi_device, tempdir: str, kernel_only: bool = True): verbose('Copying EFI configuration out of image file.') with disk.NbdDevice(image_file, disk_format='raw') \ as internal_device: internal_device.wait_for_device_node(partition=1) with mount.Mount(internal_device.device(1), os.path.join(tempdir, '_efi')) \ as int_efi: with mount.Mount(efi_device, os.path.join(tempdir, 'efi'), fs_type='vfat') \ as efi: if kernel_only: img_dir = os.path.join(int_efi, 'EFI', 'Linux') efi_dir = os.path.join(efi, 'EFI', 'Linux') assert os.path.isdir(img_dir) if not os.path.isdir(efi_dir): os.makedirs(efi_dir) for f in [f for f in os.listdir(img_dir) if os.path.isfile(os.path.join(img_dir, f))]: trace('Copying EFI kernel {}.'.format(f)) copyfile(os.path.join(img_dir, f), os.path.join(efi_dir, f)) else: trace('Copying EFI folder into system.') copy_tree(int_efi, efi)
def _create_complete_kernel( self, location: Location, system_context: SystemContext, cmdline: str, *, kernel_file: str, efi_key: str, efi_cert: str, ): self._create_efi_kernel( location, system_context, cmdline, kernel_file=kernel_file, ) if efi_key and efi_cert: debug("Signing EFI kernel.") location.set_description("Sign EFI kernel") self._execute( location.next_line(), system_context, "sign_efi_binary", kernel_file, key=efi_key, cert=efi_cert, outside=True, keep_unsigned=False, ) trace(f"Validating existence of {kernel_file}.") assert os.path.isfile(kernel_file)
def run(*args, work_directory: str = "", check: bool = True, env: typing.Dict[str, str] = os.environ) -> subprocess.CompletedProcess: env["LC_ALL"] = "en_US.UTF-8" cwd = work_directory or None trace('Running borg: "{}"...'.format('" "'.join(args))) result = subprocess.run(args, env=env, capture_output=True, check=False, cwd=cwd) if result.returncode != 0: debug("Borg returned with exit code {}:\nSTDOUT:\n{}\nSTDERR:\n{}.". format(result.returncode, result.stdout, result.stderr)) if result.returncode == 2 and check: raise subprocess.CalledProcessError( returncode=result.returncode, cmd=args, output=result.stdout, stderr=result.stderr, ) return result
def _install_sysroot_setup_support(staging_area: str) -> typing.List[str]: write_file( os.path.join(staging_area, "usr/lib/systemd/system/initrd-sysroot-setup.service"), textwrap.dedent("""\ [Unit] Description=Set up root fs in /sysroot DefaultDependencies=no ConditionPathExists=/sysroot/usr/lib/boot/root-fs.tar Requires=sysroot.mount After=sysroot.mount systemd-volatile-root.service Before=initrd-root-fs.target shutdown.target Conflicts=shutdown.target AssertPathExists=/etc/initrd-release [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/tar -C /sysroot -xf /sysroot/usr/lib/boot/root-fs.tar """).encode("utf-8"), mode=0o644, ) trace("Wrote initrd-sysroot-setup.service") symlink( os.path.join( staging_area, "usr/lib/systemd/system/initrd.target.wants/initrd-sysroot-setup.service", ), "../initrd-sysroot-setup.service", ) return []
def _install_volatile_support( staging_area: str, system_context: SystemContext) -> typing.List[str]: shutil.copyfile( system_context.file_name( "/usr/lib/systemd/system/systemd-volatile-root.service"), os.path.join(staging_area, "usr/lib/systemd/system/systemd-volatile-root.service"), ) trace("Installed systemd-volatile-root.service") symlink( os.path.join( staging_area, "usr/lib/systemd/system/initrd.target.wants/systemd-volatile-root.service", ), "../systemd-volatile-root.service", ) # Installing binaries is not a good idea in general, as dependencies are not handled! # These binaries are probably safe: systemd binaries tend to have few dependencies and those # that are included are most likely already in the image due to other systemd binaries! shutil.copyfile( system_context.file_name("/usr/lib/systemd/systemd-volatile-root"), os.path.join(staging_area, "usr/lib/systemd/systemd-volatile-root"), ) os.chmod( os.path.join(staging_area, "usr/lib/systemd/systemd-volatile-root"), 0o755) trace("Installed systemd-volatile-root binary.") return []
def _copy_efi(src: str, dest: str) -> int: try: efi_path = os.path.join(dest, "EFI") os.makedirs(efi_path, exist_ok=True) trace("Copying bootloader.") efi_src_path = os.path.join(src, "EFI") dirs = [ d for d in os.listdir(efi_src_path) if os.path.isdir(os.path.join(efi_src_path, d)) ] for d in dirs: dest = os.path.join(efi_path, d) trace(f"Copying {os.path.join(efi_src_path, d)} to {dest}") copytree( os.path.join(efi_src_path, d), dest, dirs_exist_ok=True, ) copytree( os.path.join(src, "loader"), os.path.join(dest, "loader"), dirs_exist_ok=True, ) except Exception as e: debug(f"Failed to install EFI: {e}.") return 1 else: debug("Successfully installed EFI") return 0
def __call__( self, location: Location, system_context: SystemContext, *args: typing.Any, **kwargs: typing.Any, ) -> None: """Execute command.""" user = args[0] keyfile = args[1] info(f"Adding ssh key to {user}'s authorized_keys file.") data = UserHelper.user_data(user, root_directory=system_context.fs_directory) if data is None: raise GenerateError( f'"{self.name}" could not find user "{user}".', location=location, ) trace(f"{user} mapping: UID {data.uid}, GID {data.gid}, home: {data.home}.") self._check_or_create_directory( location, system_context, data.home, mode=0o750, user=data.uid, group=data.gid, ) ssh_directory = os.path.join(data.home, ".ssh") self._check_or_create_directory( location, system_context, ssh_directory, mode=0o700, user=data.uid, group=data.gid, ) key = read_file(system_context, keyfile, outside=True).decode("utf-8") authorized_file = os.path.join(ssh_directory, "authorized_keys") line = "" options = kwargs.get("options", "") if options: line = options + " " + key + "\n" else: line += key + "\n" self._execute( location.next_line(), system_context, "append", authorized_file, line, force=True, ) chown(system_context, data.uid, data.gid, authorized_file) chmod(system_context, 0o600, authorized_file)
def _setup_btrfs(mount_point: str): trace('Creating subvolumes.') run('btrfs', 'subvol', 'create', '@btrfs', work_directory=mount_point) run('btrfs', 'subvol', 'create', '@home', work_directory=mount_point) run('btrfs', 'subvol', 'create', '@var', work_directory=mount_point) run('btrfs', 'subvol', 'create', '.images', work_directory=mount_point)
def main(*command_args: str) -> int: known_install_targets: typing.List[InstallTarget] = [ ContainerFilesystemInstallTarget(), CopyInstallTarget(), ImagePartitionInstallTarget(), MountInstallTarget(), PartitionInstallTarget(), QemuImageInstallTarget(), QemuInstallTarget(), TarballInstallTarget(), ] parse_result = _parse_commandline(*command_args, install_targets=known_install_targets) # Set up printing: pr = Printer.instance() pr.set_verbosity(parse_result.verbose) pr.show_verbosity_level() trace(f"Arguments parsed from command line: {parse_result}.") install_target = next(x for x in known_install_targets if x.name == parse_result.subcommand) assert install_target debug(f"Install target {install_target.name} found.") with TemporaryDirectory(prefix=f"fs_{install_target.name}") as tmp_dir: trace(f"Using temporary directory: {tmp_dir}.") image_dir = os.path.join(tmp_dir, "borg") os.makedirs(image_dir) with BorgMount( image_dir, system_name=parse_result.system_name, repository=parse_result.repository, version=parse_result.system_version, ) as image_file: trace(f"Mounted borg directory with image file: {image_file}.") debug( f"Running install target with parse_args={parse_result}, tmp_dir={tmp_dir} and image_file={image_file}." ) result = install_target( parse_result=parse_result, tmp_dir=tmp_dir, image_file=image_file, ) debug(f"Install target done: return code: {result}.") trace("Starting cleanup.") trace(f"Done, leaving with return code {result}.") return result
def _copy_efi(src: str, dest: str, *, include_bootloader: bool = False, overwrite: bool = False) -> int: try: efi_path = os.path.join(dest, "EFI") os.makedirs(efi_path, exist_ok=True) linux_src_path = os.path.join(src, "EFI/Linux") kernels = [ f for f in os.listdir(linux_src_path) if os.path.isfile(os.path.join(linux_src_path, f)) ] kernels_str = '", "'.join(kernels) debug(f'Found kernel(s): "{kernels_str}".') assert len(kernels) == 1 kernel = kernels[0] _copy_file( os.path.join(linux_src_path, kernel), os.path.join(dest, "EFI/Linux"), overwrite=overwrite, ) if include_bootloader: trace("Copying bootloader.") efi_src_path = os.path.join(src, "EFI") dirs = [ d for d in os.listdir(efi_src_path) if d != "Linux" and os.path.isdir(os.path.join(efi_src_path, d)) ] for d in dirs: trace(f"Copying {os.path.join(efi_src_path, d)} to {efi_path}") copytree(os.path.join(efi_src_path, d), efi_path, dirs_exist_ok=True) copytree( os.path.join(src, "loader"), os.path.join(dest, "loader"), dirs_exist_ok=True, ) except Exception as e: debug(f"Failed to install EFI: {e}.") return 1 else: debug("Successfully installed EFI") return 0
def _get_initrd_parts(location: Location, path: str) -> typing.List[str]: initrd_parts: typing.List[str] = [] for f in glob(os.path.join(path, "*")): if os.path.isfile(f): initrd_parts.append(f) if not initrd_parts: raise GenerateError( f'No initrd-parts found in directory "{path}".', location=location ) initrd_parts.sort() for ip in initrd_parts: trace(f" Adding into initrd: {ip} ...") return initrd_parts
def _module_dependencies( module_path: str, dependencies: typing.Dict[str, typing.List[str]]) -> typing.Set[str]: assert module_path trace(f"Finding dependencies for: {module_path}.") result: typing.Set[str] = set() result.add(module_path) for d in dependencies[module_path]: result = result.union(_module_dependencies(d, dependencies)) trace(f" => {result}.") return result
def __call__(self, location: Location, system_context: SystemContext, *args: typing.Any, **kwargs: typing.Any) -> None: """Execute command.""" user = args[0] keyfile = args[1] info('Adding ssh key to {}\'s authorized_keys file.'.format(user)) data = UserHelper.user_data(user, root_directory=system_context.fs_directory) if data is None: raise GenerateError('"{}" could not find user "{}".'.format( self.name, user), location=location) trace('{} mapping: UID {}, GID {}, home: {}.'.format( user, data.uid, data.gid, data.home)) self._check_or_create_directory(location, system_context, data.home, mode=0o750, user=data.uid, group=data.gid) ssh_directory = os.path.join(data.home, '.ssh') self._check_or_create_directory(location, system_context, ssh_directory, mode=0o700, user=data.uid, group=data.gid) key = read_file(system_context, keyfile, outside=True).decode('utf-8') authorized_file = os.path.join(ssh_directory, 'authorized_keys') line = '' options = kwargs.get('options', '') if options: line = options + ' ' + key + '\n' else: line += key + '\n' self._execute(location.next_line(), system_context, 'append', authorized_file, line, force=True) chown(system_context, data.uid, data.gid, authorized_file) chmod(system_context, 0o600, authorized_file)
def __call__(self, location: Location, system_context: SystemContext, *args: typing.Any, **kwargs: typing.Any) -> None: """Execute command.""" old_base = system_context.file_name("/etc/systemd/system") + "/" new_base = system_context.file_name("/usr/lib/systemd/system") + "/" trace("walking:", old_base) for root, _dirs, files in os.walk(old_base): for f in files: full_path = os.path.join(root, f) trace("Checking", full_path) if os.path.islink(full_path): trace("Moving link", full_path) _move_symlink(location, system_context, old_base, new_base, full_path) else: trace("Moving file", full_path) _move_file(location, old_base, new_base, full_path) self._execute( location.next_line(), system_context, "remove", "/etc/systemd/system/*", recursive=True, force=True, )
def __call__( self, location: Location, system_context: SystemContext, *args: typing.Any, **kwargs: typing.Any, ) -> None: """Execute command.""" to_sign = args[0] keep_unsigned = kwargs.get("keep_unsigned", False) if not kwargs.get("outside", False): to_sign = system_context.file_name(to_sign) systems_directory = system_context.systems_definition_directory key = os.path.join(systems_directory, kwargs.get("key", "config/efi/sign.key")) cert = os.path.join(systems_directory, kwargs.get("cert", "config/efi/sign.crt")) info( f"Signing EFI binary {to_sign} using key {key} and cert {cert} (keep unsigned: {keep_unsigned})." ) signed = to_sign + ".signed" assert os.path.isfile(key) assert os.path.isfile(cert) assert os.path.isfile(to_sign) assert not os.path.exists(signed) run( self._binary(Binaries.SBSIGN), "--key", key, "--cert", cert, "--output", signed, to_sign, ) if keep_unsigned: assert os.path.isfile(to_sign) assert os.path.isfile(signed) else: trace(f"Moving {signed} to {to_sign}.") os.remove(to_sign) os.rename(signed, to_sign) assert os.path.isfile(to_sign)
def _kernel_module_map(module_dir: str) -> typing.Dict[str, str]: known_modules: typing.Dict[str, str] = {} for root, _, files in os.walk(module_dir): for f in files: if "modules." in f: continue module_name = _strip_extensions(f).replace("_", "-") module_path = os.path.relpath(os.path.join(root, f), module_dir) assert module_name not in known_modules trace( f'Found "{module_name}" at "{os.path.join(root, f)}" ({module_path})' ) known_modules[module_name] = module_path return known_modules
def _copy_modules( system_context: SystemContext, modules: typing.List[str], modules_dir: str, etc_dir: str, *, kernel_version: str, ): src_top = os.path.join(system_context.file_name("/usr/lib/modules"), kernel_version) target_top = os.path.join(modules_dir, kernel_version) known_modules = _kernel_module_map(src_top) to_load: typing.List[str] = [] to_install: typing.Set[str] = set() debug(f'Installing modules from "{src_top}" into "{target_top}"') for module in modules: m = module.replace("_", "-") if m not in known_modules: info(f"Module {m} not found. Was it built into the kernel?") continue p = known_modules[m] if p not in to_install: to_install.add(p) to_load.append(m) _write_modules_load_file(etc_dir, to_load) if not to_install: return # Install dependencies: dependencies = _parse_module_dependencies(src_top) to_test = to_install for t in to_test: to_install = to_install.union(_module_dependencies(t, dependencies)) for i in to_install: os.makedirs(os.path.dirname(os.path.join(target_top, i)), exist_ok=True) trace(f"Copying module {i}.") trace( f' "{os.path.join(src_top, i)}" => "{os.path.join(target_top, i)}".' ) shutil.copy2(os.path.join(src_top, i), os.path.join(target_top, i))
def _find_tests(system_context: SystemContext) -> typing.Generator[str, None, None]: """Find tests to run.""" tests_directory = system_context.system_tests_directory debug('Searching for tests in "{}".'.format(tests_directory)) for f in sorted(os.listdir(tests_directory)): test = os.path.join(tests_directory, f) if not os.path.isfile(test): trace('"{}": Not a file, skipping.'.format(test)) continue if not os.access(test, os.X_OK): trace('"{}": Not executable, skipping.'.format(test)) continue info('Found test: "{}"'.format(test)) yield test
def _install_etc_shadow(staging_area: str, system_context: SystemContext) -> typing.List[str]: shadow_file = system_context.file_name("/etc/shadow.initramfs") if os.path.exists(shadow_file): os.makedirs(os.path.join(staging_area, "etc"), exist_ok=True) shutil.copyfile( shadow_file, os.path.join( staging_area, "etc/shadow", ), ) os.chmod(os.path.join(staging_area, "etc/shadow"), 0o600) trace("Installed /etc/shadow.initramfs as /etc/shadow into initrd.") return []
def create_qemu_image( image_path: str, *, image_size: int, image_format: str = "qcow2", system_image_file: str, tmp_dir: str, ) -> str: trace(f"Creating image file {image_path}.") with disk.NbdDevice.new_image_file(image_path, image_size, disk_format=image_format) as device: _create_hdd_image(device) debug("mounting data partition for further setup.") with mount.Mount( device.device(3), os.path.join(tmp_dir, "data"), fs_type="btrfs", options="subvolid=0", fallback_cwd=os.getcwd(), ) as data_dir: _setup_btrfs(data_dir) trace("Copying image file") copyfile( system_image_file, os.path.join(data_dir, ".images", os.path.basename(system_image_file)), ) with mount.Mount( device.device(1), os.path.join(tmp_dir, "efi_dest"), options="defaults", fs_type="vfat", ) as efi_dest_mnt: tool.execute_with_system_mounted( lambda e, _: _copy_efi( e, efi_dest_mnt, ), image_file=system_image_file, tmp_dir=tmp_dir, ) return image_path
def _move_symlink( location: Location, system_context: SystemContext, old_base: str, new_base: str, link: str, ): """Move a symlink.""" root_directory = system_context.fs_directory + "/" link_target = os.readlink(link) # normalize to /usr/lib... if link_target.startswith("/lib/"): link_target = f"/usr{link_target}" (output_link, output_link_target) = _map_host_link(root_directory, old_base, new_base, link, link_target) trace( f"Moving link {link}->{link_target}: {output_link} to {output_link_target}" ) os.makedirs(os.path.dirname(output_link), mode=0o755, exist_ok=True) if not os.path.isdir(os.path.dirname(output_link)): raise GenerateError( f'"{output_link}" is no directory when trying to move "{link}" into /usr.', location=location, ) if os.path.exists(output_link): if not os.path.islink(output_link): raise GenerateError( f'"{output_link}" exists and is not a link when trying to move "{link}" into /usr.', location=location, ) else: old_link_target = os.readlink(output_link) if old_link_target != output_link_target: raise GenerateError( f'"{link}" exists but points to "{old_link_target}" when "{output_link_target}" was expected.', location=location, ) else: os.unlink(link) return # Already correct else: os.symlink(output_link_target, output_link) os.unlink(link)
def create_qemu_image(image_path: str, *, image_size: str, image_format: str = "qcow2", system_name: str, system_version: str = "", repository: str, tempdir: str) -> str: trace("Creating image file {}.".format(image_path)) with disk.NbdDevice.new_image_file(image_path, image_size, disk_format=image_format) as device: _create_hdd_image(device) debug("mounting data partition for further setup.") with mount.Mount( device.device(3), os.path.join(tempdir, "data"), fs_type="btrfs", options="subvolid=0", fallback_cwd=os.getcwd(), ) as data_dir: _setup_btrfs(data_dir) extract_location = os.path.join(data_dir, ".images") verbose("Extracting system image to {}.".format(extract_location)) extracted_version = tool.write_image( system_name, extract_location, repository=repository, version=system_version, ) extracted_image = os.path.join(data_dir, ".images", "clrm_{}".format(extracted_version)) assert os.path.isfile(extracted_image) tool.copy_efi_partition( image_file=extracted_image, efi_device=device.device(1), tempdir=tempdir, kernel_only=False, ) return image_path
def _install_lvm_support(staging_area: str, vg: typing.Optional[str], image_name: str) -> typing.List[str]: if not vg: return [] device_name = f"dev-{vg}-{image_name}" write_file( os.path.join( staging_area, "usr/lib/systemd/system/initrd-find-root-lv-partitions.service", ), textwrap.dedent(f"""\ [Unit] Description=Find partitions in root LV DefaultDependencies=no ConditionPathExists=/dev/{vg}/{image_name} After={device_name}.device Before=shutdown.target BindsTo={device_name}.device Requisite={device_name}.device Conflicts=shutdown.target [Service] WorkingDirectory=/ Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/partprobe /dev/{vg}/{image_name} [Install] WantedBy={device_name}.device """).encode("utf-8"), mode=0o644, ) trace("Wrote initrd-find-root-lv-partitions.service") symlink( os.path.join( staging_area, f"usr/lib/systemd/system/dev-{vg}-{image_name}.device.wants/initrd-find-root-lv-partitions.service", ), "../initrd-find-root-lv-partitions.service", ) return []
def _install_shadow_file(staging_area: str, system_context: SystemContext): for shadow_file in ( system_context.file_name("/etc/shadow.initramfs"), system_context.file_name( "/usr/share/defaults/etc/shadow.initramfs"), ): if os.path.exists(shadow_file): os.makedirs(os.path.join(staging_area, "etc"), exist_ok=True) shutil.copyfile( shadow_file, os.path.join( staging_area, "etc/shadow", ), ) os.chmod(os.path.join(staging_area, "etc/shadow"), 0o600) os.remove(shadow_file) trace( "Installed /etc/shadow.initramfs as /etc/shadow into initrd.")
def _move_symlink(location, system_context, old_base, new_base, link): """Move a symlink.""" root_directory = system_context.fs_directory + '/' link_target = os.readlink(link) # normalize to /usr/lib... if link_target.startswith('/lib/'): link_target = '/usr{}'.format(link_target) (output_link, output_link_target) \ = _map_host_link(root_directory, old_base, new_base, link, link_target) trace('Moving link {}->{}: {} to {}' .format(link, link_target, output_link, output_link_target)) os.makedirs(os.path.dirname(output_link), mode=0o755, exist_ok=True) if not os.path.isdir(os.path.dirname(output_link)): raise GenerateError('"{}" is no directory when trying to move ' '"{}" into /usr.'.format(output_link, link), location=location) if os.path.exists(output_link): if not os.path.islink(output_link): raise GenerateError('"{}" exists and is not a link when ' 'trying to move "{}" into /usr.' .format(output_link, link), location=location) else: old_link_target = os.readlink(output_link) if old_link_target != output_link_target: raise GenerateError('"{}" exists but points to "{}" ' 'when "{}" was expected.' .format(link, old_link_target, output_link_target), location=location) else: os.unlink(link) return # Already correct else: os.symlink(output_link_target, output_link) os.unlink(link)
def find_archive(system_name: str, *, repository: str, version: str = '') \ -> typing.Tuple[str, str]: borg_list = run_borg('list', repository) archive_to_use = '' for line in borg_list.stdout.decode('utf-8').split('\n'): if not line.startswith(system_name): continue trace('Borg list: {}.'.format(line)) versioned_system_name = line.split(' ')[0] assert versioned_system_name[len(system_name)] == '-' current_version = versioned_system_name[len(system_name) + 1:] if version: if current_version == version: archive_to_use = versioned_system_name break else: if not archive_to_use or versioned_system_name > archive_to_use: archive_to_use = versioned_system_name return archive_to_use, archive_to_use[len(system_name) + 1:]
def find_archive(system_name: str, *, repository: str, version: str = "") -> typing.Tuple[str, str]: borg_list = run_borg("list", repository) archive_to_use = "" for line in borg_list.stdout.decode("utf-8").split("\n"): if not line.startswith(system_name): continue trace(f"Borg list: {line}.") versioned_system_name = line.split(" ")[0] assert versioned_system_name[len(system_name)] == "-" current_version = versioned_system_name[len(system_name) + 1:] if version: if current_version == version: archive_to_use = versioned_system_name break else: if not archive_to_use or versioned_system_name > archive_to_use: archive_to_use = versioned_system_name return archive_to_use, archive_to_use[len(system_name) + 1:]