From 926ff407745f5d1716dd4be4c7fdd697c54a13a1 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 24 Mar 2026 16:47:16 -0700 Subject: [PATCH] boot-utils: Switch to ruff for Python formatting We started using ruff for linting a while ago. Since then, it has grown a formatting option, which is quite fast. While it is a little less flexible than YAPF, we don't currently customize the behavior aside from some exemptions. Switch to ruff for formatting. Most of the changes end up making the code a little more readable, at the expense of some extra lines. Switch to the generic fmt comments instead of the yapf specific ones. Use the option to preserve our quoting style, which uses single quotes for string literals and double quotes for f-string or raw strings. Signed-off-by: Nathan Chancellor --- boot-qemu.py | 225 ++++++++++++++++++------------------------- boot-uml.py | 9 +- buildroot/rebuild.py | 75 +++++++++------ ruff.toml | 3 + utils.py | 45 ++++----- 5 files changed, 169 insertions(+), 188 deletions(-) diff --git a/boot-qemu.py b/boot-qemu.py index 40044e0..7e91ba5 100755 --- a/boot-qemu.py +++ b/boot-qemu.py @@ -38,7 +38,6 @@ class QEMURunner: - def __init__(self): # Properties that can be adjusted by the user or class @@ -72,7 +71,7 @@ def __init__(self): self._qemu_args = [ '-display', 'none', '-nodefaults', - ] # yapf: disable + ] # fmt: off self._qemu_path = None def _find_dtb(self): @@ -106,14 +105,14 @@ def _get_default_smp_value(self): # * /../../../.config (if the image is in arch/*/boot/) # * /config (if the image is in a TuxMake folder) possible_locations = ['.config', '../../../.config', 'config'] - configuration = utils.find_first_file(self.kernel_dir, - possible_locations, - required=False) + configuration = utils.find_first_file( + self.kernel_dir, possible_locations, required=False + ) config_nr_cpus = 8 # sensible default based on treewide defaults, if configuration: conf_txt = configuration.read_text(encoding='utf-8') - if (match := re.search(r'CONFIG_NR_CPUS=(\d+)', conf_txt)): + if match := re.search(r'CONFIG_NR_CPUS=(\d+)', conf_txt): config_nr_cpus = int(match.groups()[0]) # Use the minimum of the number of usable processers for the script or @@ -126,42 +125,38 @@ def _get_kernel_ver_tuple(self, decomp_prog): raise RuntimeError('No kernel set?') utils.check_cmd(decomp_prog) - if decomp_prog in ('gzip', ): + if decomp_prog in ('gzip',): decomp_cmd = [decomp_prog, '-c', '-d', self.kernel] else: - raise RuntimeError( - f"Unsupported decompression program ('{decomp_prog}')?") + raise RuntimeError(f"Unsupported decompression program ('{decomp_prog}')?") decomp = subprocess.run(decomp_cmd, capture_output=True, check=True) utils.check_cmd('strings') - strings = subprocess.run('strings', - capture_output=True, - check=True, - input=decomp.stdout) - strings_stdout = strings.stdout.decode(encoding='utf-8', - errors='ignore') - - if not (match := re.search(r'^Linux version (\d+\.\d+\.\d+)', - strings_stdout, - flags=re.M)): - raise RuntimeError( - f"Could not find Linux version in {self.kernel}?") + strings = subprocess.run( + 'strings', capture_output=True, check=True, input=decomp.stdout + ) + strings_stdout = strings.stdout.decode(encoding='utf-8', errors='ignore') + + if not ( + match := re.search( + r'^Linux version (\d+\.\d+\.\d+)', strings_stdout, flags=re.M + ) + ): + raise RuntimeError(f"Could not find Linux version in {self.kernel}?") return tuple(int(x) for x in match.groups()[0].split('.')) def _get_qemu_ver_string(self): if not self._qemu_path: raise RuntimeError('No path to QEMU set?') - qemu_ver = subprocess.run([self._qemu_path, '--version'], - capture_output=True, - check=True, - text=True) + qemu_ver = subprocess.run( + [self._qemu_path, '--version'], capture_output=True, check=True, text=True + ) return qemu_ver.stdout.splitlines()[0] def _get_qemu_ver_tuple(self): qemu_ver_string = self._get_qemu_ver_string() - if not (match := re.search(r'version (\d+\.\d+.\d+)', - qemu_ver_string)): + if not (match := re.search(r'version (\d+\.\d+.\d+)', qemu_ver_string)): raise RuntimeError('Could not find QEMU version?') return tuple(int(x) for x in match.groups()[0].split('.')) @@ -173,9 +168,9 @@ def _prepare_initrd(self): return self.initrd if not self._initrd_arch: raise RuntimeError('No initrd architecture specified?') - return utils.prepare_initrd(self._initrd_arch, - gh_json_file=self.gh_json_file, - modules=self.modules) + return utils.prepare_initrd( + self._initrd_arch, gh_json_file=self.gh_json_file, modules=self.modules + ) def _run_fg(self): # Pretty print and run QEMU command @@ -190,8 +185,7 @@ def _run_fg(self): qemu_cmd += [self._qemu_path, *self._qemu_args] - print(f"$ {' '.join(shlex.quote(str(elem)) for elem in qemu_cmd)}", - flush=True) + print(f"$ {' '.join(shlex.quote(str(elem)) for elem in qemu_cmd)}", flush=True) try: subprocess.run(qemu_cmd, check=True) except subprocess.CalledProcessError as err: @@ -215,9 +209,7 @@ def _run_gdb(self): ] while True: - lsof = subprocess.run(['lsof', '-i:1234'], - capture_output=True, - check=False) + lsof = subprocess.run(['lsof', '-i:1234'], capture_output=True, check=False) if lsof.returncode == 0: utils.die('Port 1234 is already in use, is QEMU running?') @@ -234,8 +226,9 @@ def _run_gdb(self): # pylint: disable-next=unexpected-keyword-arg with subprocess.Popen(qemu_cmd, **popen_kwargs) as qemu_proc: utils.green(f"Starting {self.gdb_bin}...") - with subprocess.Popen(gdb_cmd) as gdb_proc, \ - contextlib.suppress(KeyboardInterrupt): + with subprocess.Popen(gdb_cmd) as gdb_proc, contextlib.suppress( + KeyboardInterrupt + ): gdb_proc.wait() utils.red('Killing QEMU...') @@ -253,8 +246,7 @@ def _set_kernel_vars(self): return if not self.kernel_dir: - raise RuntimeError( - 'No kernel image or kernel build folder specified?') + raise RuntimeError('No kernel image or kernel build folder specified?') if not self._default_kernel_path: raise RuntimeError('No default kernel path specified?') @@ -262,8 +254,7 @@ def _set_kernel_vars(self): Path(self._default_kernel_path), # default (kbuild) Path(self._default_kernel_path.name), # tuxmake } - self.kernel = utils.find_first_file(self.kernel_dir, - possible_kernel_locations) + self.kernel = utils.find_first_file(self.kernel_dir, possible_kernel_locations) def _set_qemu_path(self): if self._qemu_path: @@ -272,8 +263,7 @@ def _set_qemu_path(self): raise RuntimeError('No QEMU architecture set?') qemu_bin = f"qemu-system-{self._qemu_arch}" if not (qemu_path := shutil.which(qemu_bin)): - raise RuntimeError( - f'{qemu_bin} could not be found on your system?') + raise RuntimeError(f'{qemu_bin} could not be found on your system?') self._qemu_path = Path(qemu_path) def run(self): @@ -290,7 +280,7 @@ def run(self): '-drive', f"if=pflash,format=raw,file={self._efi_vars}", '-object', 'rng-random,filename=/dev/urandom,id=rng0', '-device', 'virtio-rng-pci', - ] # yapf: disable + ] # fmt: off # Kernel options if self.interactive or self.gdb: @@ -330,7 +320,6 @@ def run(self): class ARMEFIQEMURunner(QEMURunner): - def _setup_efi(self, possible_locations): # Sizing the images to 64M is recommended by "Prepare the firmware" section at # https://mirrors.edge.kernel.org/pub/linux/kernel/people/will/docs/qemu/qemu-arm64-howto.html @@ -340,8 +329,7 @@ def _setup_efi(self, possible_locations): aavmf = utils.find_first_file(usr_share, possible_locations) - self._efi_img = Path(utils.BOOT_UTILS, 'images', self._initrd_arch, - 'efi.img') + self._efi_img = Path(utils.BOOT_UTILS, 'images', self._initrd_arch, 'efi.img') # This file is in /usr/share, so it must be copied in order to be # modified. shutil.copyfile(aavmf, self._efi_img) @@ -355,7 +343,6 @@ def _setup_efi(self, possible_locations): class ARMQEMURunner(QEMURunner): - def __init__(self): super().__init__() @@ -371,7 +358,6 @@ def run(self): class ARMV5QEMURunner(ARMQEMURunner): - def __init__(self): super().__init__() @@ -379,24 +365,21 @@ def __init__(self): self.memory = '512m' self._dtbs = [ - 'aspeed/aspeed-bmc-opp-palmetto.dtb', 'aspeed-bmc-opp-palmetto.dtb' + 'aspeed/aspeed-bmc-opp-palmetto.dtb', + 'aspeed-bmc-opp-palmetto.dtb', ] self._machine = 'palmetto-bmc' class ARMV6QEMURunner(ARMQEMURunner): - def __init__(self): super().__init__() - self._dtbs = [ - 'aspeed/aspeed-bmc-opp-romulus.dtb', 'aspeed-bmc-opp-romulus.dtb' - ] + self._dtbs = ['aspeed/aspeed-bmc-opp-romulus.dtb', 'aspeed-bmc-opp-romulus.dtb'] self._machine = 'romulus-bmc' class ARMV7QEMURunner(ARMQEMURunner, ARMEFIQEMURunner): - def __init__(self): super().__init__() @@ -414,9 +397,10 @@ def _can_use_kvm(self): # 32-bit EL1 is not supported on all cores so support for it must be # explicitly queried via the KVM_CHECK_EXTENSION ioctl(). try: - subprocess.run(Path(utils.BOOT_UTILS, 'utils', - 'aarch64_32_bit_el1_supported'), - check=True) + subprocess.run( + Path(utils.BOOT_UTILS, 'utils', 'aarch64_32_bit_el1_supported'), + check=True, + ) except subprocess.CalledProcessError: return False @@ -437,14 +421,12 @@ def run(self): class ARM64QEMURunner(ARMEFIQEMURunner): - def __init__(self): super().__init__() self.cmdline += ['console=ttyAMA0', 'earlycon'] self.supports_efi = True - self.use_kvm = platform.machine() == 'aarch64' and \ - self._have_dev_kvm_access() + self.use_kvm = platform.machine() == 'aarch64' and self._have_dev_kvm_access() self._default_kernel_path = Path('arch/arm64/boot/Image.gz') self._initrd_arch = 'arm64' @@ -498,7 +480,6 @@ def run(self): class ARM64BEQEMURunner(ARM64QEMURunner): - def __init__(self): super().__init__() @@ -508,7 +489,6 @@ def __init__(self): class LoongArchQEMURunner(QEMURunner): - def __init__(self): super().__init__() @@ -516,13 +496,11 @@ def __init__(self): self._default_kernel_path = Path('arch/loongarch/boot/vmlinuz.efi') self._initrd_arch = 'loongarch' - bios = Path(utils.BOOT_UTILS, 'images', self._initrd_arch, - 'QEMU_EFI.fd') + bios = Path(utils.BOOT_UTILS, 'images', self._initrd_arch, 'QEMU_EFI.fd') if not bios.exists(): bios.parent.mkdir(exist_ok=True, parents=True) firmware_url = f"https://github.com/loongson/Firmware/raw/main/LoongArchVirtMachine/{bios.name}" - utils.green( - f"Downloading LoongArch firmware from {firmware_url}...") + utils.green(f"Downloading LoongArch firmware from {firmware_url}...") curl_cmd = ['curl', '-LSs', '-o', bios, firmware_url] subprocess.run(curl_cmd, check=True) @@ -532,13 +510,12 @@ def __init__(self): '-cpu', 'la464', '-bios', bios, '-no-reboot', - ] # yapf: disable + ] # fmt: off self.memory = '2G' self.smp = 2 class M68KQEMURunner(QEMURunner): - def __init__(self): super().__init__() @@ -549,11 +526,10 @@ def __init__(self): '-cpu', 'm68040', '-M', 'q800', '-no-reboot', - ] # yapf: disable + ] # fmt: off class MIPSQEMURunner(QEMURunner): - def __init__(self): super().__init__() @@ -563,7 +539,6 @@ def __init__(self): class MIPSELQEMURunner(MIPSQEMURunner): - def __init__(self): super().__init__() @@ -571,7 +546,6 @@ def __init__(self): class PowerPC32QEMURunner(QEMURunner): - def __init__(self): super().__init__() @@ -590,7 +564,6 @@ def run(self): class PowerPC32MacQEMURunner(PowerPC32QEMURunner): - def __init__(self): super().__init__() @@ -599,7 +572,6 @@ def __init__(self): class PowerPC64QEMURunner(QEMURunner): - def __init__(self): super().__init__() @@ -609,11 +581,10 @@ def __init__(self): '-cpu', 'power8', '-machine', 'pseries', '-vga', 'none', - ] # yapf: disable + ] # fmt: off class PowerPC64LEQEMURunner(QEMURunner): - def __init__(self): super().__init__() @@ -625,11 +596,10 @@ def __init__(self): '-device', 'ipmi-bmc-sim,id=bmc0', '-device', 'isa-ipmi-bt,bmc=bmc0,irq=10', '-machine', 'powernv', - ] # yapf: disable + ] # fmt: off class RISCVQEMURunner(QEMURunner): - def __init__(self): super().__init__() @@ -649,7 +619,6 @@ def __init__(self): class S390QEMURunner(QEMURunner): - def __init__(self): super().__init__() @@ -660,7 +629,6 @@ def __init__(self): class Sparc64QEMURunner(QEMURunner): - def __init__(self): super().__init__() @@ -671,13 +639,11 @@ def __init__(self): class X86QEMURunner(QEMURunner): - def __init__(self): super().__init__() self.cmdline += ['console=ttyS0', 'earlycon=uart8250,io,0x3f8'] - self.use_kvm = platform.machine() == 'x86_64' and \ - self._have_dev_kvm_access() + self.use_kvm = platform.machine() == 'x86_64' and self._have_dev_kvm_access() self._default_kernel_path = Path('arch/x86/boot/bzImage') self._initrd_arch = 'x86' @@ -695,7 +661,6 @@ def run(self): class X8664QEMURunner(X86QEMURunner): - def __init__(self): super().__init__() @@ -721,8 +686,9 @@ def run(self): Path('OVMF/OVMF_VARS.fd'), # Debian and Ubuntu ] ovmf_vars = utils.find_first_file(usr_share, ovmf_vars_locations) - self._efi_vars = Path(utils.BOOT_UTILS, 'images', - self._initrd_arch, ovmf_vars.name) + self._efi_vars = Path( + utils.BOOT_UTILS, 'images', self._initrd_arch, ovmf_vars.name + ) # This file is in /usr/share, so it must be copied in order to be # modified. shutil.copyfile(ovmf_vars, self._efi_vars) @@ -746,20 +712,20 @@ def guess_arch(kernel_arg): # # Note: 'required=False' just to provide our own exception. vmlinux_locations = ['vmlinux', '../../../vmlinux'] - if not (vmlinux := utils.find_first_file( - kernel_dir, vmlinux_locations, required=False)): + if not ( + vmlinux := utils.find_first_file(kernel_dir, vmlinux_locations, required=False) + ): raise RuntimeError( - 'Architecture was not provided and vmlinux could not be found!') + 'Architecture was not provided and vmlinux could not be found!' + ) if not (file := shutil.which('file')): - raise RuntimeError( - "Architecture was not provided and 'file' is not installed!") + raise RuntimeError("Architecture was not provided and 'file' is not installed!") # Get output of file - file_out = subprocess.run([file, vmlinux], - capture_output=True, - check=True, - text=True).stdout.strip() + file_out = subprocess.run( + [file, vmlinux], capture_output=True, check=True, text=True + ).stdout.strip() # Unfortunately, 'file' is not terribly precise when it comes to # microarchitecture or architecture revisions. As such, there are certain @@ -785,7 +751,7 @@ def guess_arch(kernel_arg): 'ELF 64-bit MSB executable, SPARC V9': 'sparc64', 'ELF 32-bit LSB executable, Intel 80386': 'x86', 'ELF 64-bit LSB executable, x86-64': 'x86_64', - } # yapf: disable + } # fmt: off for string, value in file_rosetta.items(): if string in file_out: if value == 'ambiguous': @@ -806,73 +772,73 @@ def parse_arguments(): '-a', '--architecture', choices=SUPPORTED_ARCHES, - help= - "The architecture to boot. If omitted, value will be guessed based on 'vmlinux' if available. Possible values are: %(choices)s", - metavar='ARCH') - parser.add_argument('--efi', - action='store_true', - help='Boot kernel via UEFI (x86_64 only)') + help="The architecture to boot. If omitted, value will be guessed based on 'vmlinux' if available. Possible values are: %(choices)s", + metavar='ARCH', + ) + parser.add_argument( + '--efi', action='store_true', help='Boot kernel via UEFI (x86_64 only)' + ) parser.add_argument( '-g', '--gdb', action='store_true', - help="Start QEMU with '-s -S' then launch gdb on 'vmlinux'") + help="Start QEMU with '-s -S' then launch gdb on 'vmlinux'", + ) parser.add_argument( '--gdb-bin', default='gdb-multiarch', - help='gdb binary to use for debugging (default: gdb-multiarch)') + help='gdb binary to use for debugging (default: gdb-multiarch)', + ) parser.add_argument( '--gh-json-file', - help= - 'Use file for downloading rootfs images, instead of querying GitHub API directly' + help='Use file for downloading rootfs images, instead of querying GitHub API directly', ) parser.add_argument( '-I', '--initrd', - help= - 'Initial ramdisk to use (default: Download ramdisk from ClangBuiltLinux/boot-utils releases)' + help='Initial ramdisk to use (default: Download ramdisk from ClangBuiltLinux/boot-utils releases)', ) parser.add_argument( '-k', '--kernel-location', required=True, - help='Absolute or relative path to kernel image or build folder.') - parser.add_argument('--append', - help='Append items to kernel cmdline', - nargs='+') + help='Absolute or relative path to kernel image or build folder.', + ) + parser.add_argument('--append', help='Append items to kernel cmdline', nargs='+') parser.add_argument( '--no-kvm', action='store_true', - help='Do not use KVM for accelration even when supported.') + help='Do not use KVM for accelration even when supported.', + ) parser.add_argument( '-i', '--interactive', '--shell', action='store_true', - help='Instead of immediately shutting down machine, spawn a shell.') + help='Instead of immediately shutting down machine, spawn a shell.', + ) parser.add_argument( '-m', '--memory', - help= - "Value for '-m' QEMU option (default: generally '512m', depends on machine)", + help="Value for '-m' QEMU option (default: generally '512m', depends on machine)", ) parser.add_argument( '-M', '--modules', - help= - 'Path to .cpio generated with the Linux kernel\'s "modules-cpio-pkg" target' + help='Path to .cpio generated with the Linux kernel\'s "modules-cpio-pkg" target', ) parser.add_argument( '-s', '--smp', type=int, - help= - 'Number of processors for virtual machine (default: only KVM machines will use multiple vCPUs.)', + help='Number of processors for virtual machine (default: only KVM machines will use multiple vCPUs.)', + ) + parser.add_argument( + '-t', + '--timeout', + default='3m', + help="Value to pass to 'timeout' (default: '3m')", ) - parser.add_argument('-t', - '--timeout', - default='3m', - help="Value to pass to 'timeout' (default: '3m')") return parser.parse_args() @@ -882,7 +848,8 @@ def parse_arguments(): if not (kernel_location := Path(args.kernel_location).resolve()).exists(): raise FileNotFoundError( - f"Supplied kernel location ('{kernel_location}') does not exist!") + f"Supplied kernel location ('{kernel_location}') does not exist!" + ) if not (arch := args.architecture): arch = guess_arch(kernel_location) @@ -938,8 +905,7 @@ def parse_arguments(): if args.initrd: if not (initrd := Path(args.initrd).resolve()).exists(): - raise FileNotFoundError( - f"Supplied initrd ('{initrd}') does not exist?") + raise FileNotFoundError(f"Supplied initrd ('{initrd}') does not exist?") runner.initrd = initrd if args.memory: @@ -948,7 +914,8 @@ def parse_arguments(): if args.modules: if not (modules := Path(args.modules).resolve()).exists(): raise FileNotFoundError( - f"Supplied modules .cpio ('{modules}') does not exist?") + f"Supplied modules .cpio ('{modules}') does not exist?" + ) if not args.memory: utils.yellow( 'Memory not specified, the default may be too small for modules...' diff --git a/boot-uml.py b/boot-uml.py index 61ecadd..c2fe476 100755 --- a/boot-uml.py +++ b/boot-uml.py @@ -20,23 +20,20 @@ def parse_arguments(): parser.add_argument( '-g', '--gh-json-file', - help= - 'Use file for downloading rootfs images, instead of querying GitHub API directly' + help='Use file for downloading rootfs images, instead of querying GitHub API directly', ) parser.add_argument( "-i", "--interactive", action="store_true", - help= - "Instead of immediately shutting down upon successful boot, pass 'init=/bin/sh' to the UML executable to allow interacting with UML via a shell." + help="Instead of immediately shutting down upon successful boot, pass 'init=/bin/sh' to the UML executable to allow interacting with UML via a shell.", ) parser.add_argument( "-k", "--kernel-location", required=True, type=str, - help= - "Path to UML executable ('linux') or kernel build folder to search for executable in. Can be an absolute or relative path." + help="Path to UML executable ('linux') or kernel build folder to search for executable in. Can be an absolute or relative path.", ) return parser.parse_args() diff --git a/buildroot/rebuild.py b/buildroot/rebuild.py index ebe4a45..073bf03 100755 --- a/buildroot/rebuild.py +++ b/buildroot/rebuild.py @@ -25,8 +25,7 @@ 'x86', 'x86_64', ] -RELEASE_TAG = datetime.datetime.now( - tz=datetime.timezone.utc).strftime('%Y%m%d-%H%M%S') +RELEASE_TAG = datetime.datetime.now(tz=datetime.timezone.utc).strftime('%Y%m%d-%H%M%S') ROOT_FOLDER = Path(__file__).resolve().parent OUT_FOLDER = Path(ROOT_FOLDER, 'out') SRC_FOLDER = Path(ROOT_FOLDER, 'src') @@ -65,11 +64,14 @@ def build_image(architecture, edit_config, savedefconfig): for image in images: if not image.exists(): - raise FileNotFoundError( - f"{image} could not be found! Did the build error?") + raise FileNotFoundError(f"{image} could not be found! Did the build error?") zstd_cmd = [ - 'zstd', '-f', '-19', '-o', - Path(OUT_FOLDER, f"{architecture}-{image.name}.zst"), image + 'zstd', + '-f', + '-19', + '-o', + Path(OUT_FOLDER, f"{architecture}-{image.name}.zst"), + image, ] subprocess.run(zstd_cmd, check=True) @@ -82,24 +84,30 @@ def download_and_extract_buildroot(): tarball = Path(ROOT_FOLDER, f"buildroot-{BUILDROOT_VERSION}.tar.gz") if not tarball.exists(): curl_cmd = [ - 'curl', '-LSs', '-o', tarball, - f"https://buildroot.org/downloads/{tarball.name}" + 'curl', + '-LSs', + '-o', + tarball, + f"https://buildroot.org/downloads/{tarball.name}", ] subprocess.run(curl_cmd, check=True) sha256_cmd = ['sha256sum', '--quiet', '-c', f"{tarball.name}.sha256"] subprocess.run(sha256_cmd, check=True, cwd=ROOT_FOLDER) - tar_cmd = [ - 'tar', '-C', SRC_FOLDER, '--strip-components=1', '-axf', tarball - ] + tar_cmd = ['tar', '-C', SRC_FOLDER, '--strip-components=1', '-axf', tarball] subprocess.run(tar_cmd, check=True) - if (patches := list(ROOT_FOLDER.glob('*.patch'))): + if patches := list(ROOT_FOLDER.glob('*.patch')): for patch in patches: patch_cmd = [ - 'patch', '--directory', SRC_FOLDER, '--input', patch, - '--strip', '1' + 'patch', + '--directory', + SRC_FOLDER, + '--input', + patch, + '--strip', + '1', ] try: subprocess.run(patch_cmd, check=True) @@ -116,8 +124,14 @@ def release_images(): ) gh_cmd = [ - 'gh', '-R', 'ClangBuiltLinux/boot-utils', 'release', 'create', - '--generate-notes', RELEASE_TAG, *list(OUT_FOLDER.iterdir()) + 'gh', + '-R', + 'ClangBuiltLinux/boot-utils', + 'release', + 'create', + '--generate-notes', + RELEASE_TAG, + *list(OUT_FOLDER.iterdir()), ] subprocess.run(gh_cmd, check=True) @@ -130,23 +144,27 @@ def parse_arguments(): '--architectures', choices=[*SUPPORTED_ARCHES, 'all'], default=SUPPORTED_ARCHES, - help= - 'The architectures to build images for. Defaults to all supported architectures.', - nargs='+') + help='The architectures to build images for. Defaults to all supported architectures.', + nargs='+', + ) parser.add_argument( '-e', '--edit-config', action='store_true', - help='Edit configuration file and run savedefconfig on result') + help='Edit configuration file and run savedefconfig on result', + ) parser.add_argument( '-r', '--release', action='store_true', - help=f"Create a release on GitHub (tag: {RELEASE_TAG})") - parser.add_argument('-s', - '--savedefconfig', - action='store_true', - help='Run savedefconfig after configuration stage') + help=f"Create a release on GitHub (tag: {RELEASE_TAG})", + ) + parser.add_argument( + '-s', + '--savedefconfig', + action='store_true', + help='Run savedefconfig after configuration stage', + ) return parser.parse_args() @@ -155,10 +173,11 @@ def parse_arguments(): args = parse_arguments() if not shutil.which('zstd'): - raise RuntimeError( - 'zstd could not be found on your system, please install it!') + raise RuntimeError('zstd could not be found on your system, please install it!') - architectures = SUPPORTED_ARCHES if 'all' in args.architectures else args.architectures + architectures = ( + SUPPORTED_ARCHES if 'all' in args.architectures else args.architectures + ) download_and_extract_buildroot() for arch in architectures: diff --git a/ruff.toml b/ruff.toml index 1dca1ef..f1f4f3b 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,5 +1,8 @@ target-version = 'py38' +[format] +quote-style = 'preserve' + # https://docs.astral.sh/ruff/rules/ [lint] select = [ diff --git a/utils.py b/utils.py index b3b9bcf..a8e5edb 100755 --- a/utils.py +++ b/utils.py @@ -20,8 +20,9 @@ def check_cmd(cmd): cmd (str): External command name or path. """ if not shutil.which(cmd): - die(f"The external command '{cmd}' is needed but it could not be found in PATH, please install it!" - ) + die( + f"The external command '{cmd}' is needed but it could not be found in PATH, please install it!" + ) def die(string): @@ -53,9 +54,7 @@ def download_initrd(gh_json, local_dest): for asset in assets: if asset['name'] == remote_file: - curl_cmd = [ - 'curl', '-LSs', '-o', local_dest, asset['browser_download_url'] - ] + curl_cmd = ['curl', '-LSs', '-o', local_dest, asset['browser_download_url']] subprocess.run(curl_cmd, check=True) # Update the '.release' file in the same folder as the download @@ -119,8 +118,9 @@ def get_full_kernel_path(kernel_location, image, arch=None): # Otherwise, it is in the architecture's boot directory else: if not arch: - die(f"Kernel image ('{image}') is in the arch/ directory but 'arch' was not provided!" - ) + die( + f"Kernel image ('{image}') is in the arch/ directory but 'arch' was not provided!" + ) kernel = kernel_location.joinpath("arch", arch, "boot", image) if not kernel.exists(): @@ -151,13 +151,13 @@ def get_gh_json(endpoint): curl_cmd.append(endpoint) try: - curl_out = subprocess.run(curl_cmd, - capture_output=True, - check=True, - text=True).stdout + curl_out = subprocess.run( + curl_cmd, capture_output=True, check=True, text=True + ).stdout except subprocess.CalledProcessError as err: raise RuntimeError( - f"Failed to query GitHub API at {endpoint}: {err.stderr}") from err + f"Failed to query GitHub API at {endpoint}: {err.stderr}" + ) from err return json.loads(curl_out) @@ -172,10 +172,7 @@ def green(string): print(f"\n\033[01;32m{string}\033[0m", flush=True) -def prepare_initrd(architecture, - rootfs_format='cpio', - gh_json_file=None, - modules=None): +def prepare_initrd(architecture, rootfs_format='cpio', gh_json_file=None, modules=None): """ Returns a decompressed initial ramdisk. @@ -183,8 +180,7 @@ def prepare_initrd(architecture, architecture (str): Architecture to download image for. rootfs_format (str): Initrd format ('cpio' or 'ext4') """ - src = Path(BOOT_UTILS, 'images', architecture, - f"rootfs.{rootfs_format}.zst") + src = Path(BOOT_UTILS, 'images', architecture, f"rootfs.{rootfs_format}.zst") src.parent.mkdir(exist_ok=True, parents=True) # If the user supplied a GitHub release JSON file, we do not need to bother @@ -205,7 +201,8 @@ def prepare_initrd(architecture, # that we are up to date. if (remaining := gh_json_rl['resources']['core']['remaining']) > 0: gh_json_rel = get_gh_json( - f"https://api.github.com/repos/{REPO}/releases/latest") + f"https://api.github.com/repos/{REPO}/releases/latest" + ) elif not src.exists(): limit = gh_json_rl['resources']['core']['limit'] raise RuntimeError( @@ -240,12 +237,10 @@ def prepare_initrd(architecture, f"{modules} does not have cpio magic bytes, was it generated with the 'modules-cpio-pkg' target?" ) - (new_dst := - dst.parent.joinpath('rootfs-modules.cpio')).unlink(missing_ok=True) - with subprocess.Popen(['cat', dst, modules], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) as proc, new_dst.open( - 'xb') as dst_file: + (new_dst := dst.parent.joinpath('rootfs-modules.cpio')).unlink(missing_ok=True) + with subprocess.Popen( + ['cat', dst, modules], stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ) as proc, new_dst.open('xb') as dst_file: dst_file.write(proc.stdout.read()) dst = new_dst