11#!/usr/bin/env python3
22# pylint: disable=invalid-name
33
4+ from __future__ import annotations
5+
46import contextlib
57import os
68import platform
1012import subprocess
1113import sys
1214from argparse import ArgumentParser
13- from collections .abc import Sequence
1415from pathlib import Path
15- from typing import Any , Union
16+ from typing import TYPE_CHECKING , Any
1617
1718import utils
1819
20+ if TYPE_CHECKING :
21+ from collections .abc import Sequence
22+
1923SUPPORTED_ARCHES = [
2024 'arm' ,
2125 'arm32_v5' ,
@@ -70,17 +74,19 @@ def __init__(self) -> None:
7074 self ._initrd_arch : str = ''
7175 self ._kvm_cpu : list [str ] = ['host' ]
7276 self ._qemu_arch : str = ''
73- self ._qemu_args : list [Union [ Path , str ] ] = [
77+ self ._qemu_args : list [Path | str ] = [
7478 '-display' , 'none' ,
7579 '-nodefaults' ,
7680 ] # fmt: off
7781 self ._qemu_path : Path = utils .UNINIT_PATH
7882
7983 def _find_dtb (self ) -> Path :
8084 if not self ._dtbs :
81- raise RuntimeError ('No dtbs set?' )
85+ msg = 'No dtbs set?'
86+ raise RuntimeError (msg )
8287 if self .kernel == utils .UNINIT_PATH :
83- raise RuntimeError ('Cannot locate dtb without kernel' )
88+ msg = 'Cannot locate dtb without kernel'
89+ raise RuntimeError (msg )
8490
8591 # If we are in a boot folder, look for them in the dts folder in it.
8692 # Otherwise, assume there is a 'dtbs' folder in the same folder as the
@@ -90,13 +96,13 @@ def _find_dtb(self) -> Path:
9096 if (dtb := Path (self .kernel .parent , dtb_dir , dtb_loc )).exists ():
9197 return dtb
9298
93- raise FileNotFoundError (
94- f"dtb is required for booting but it could not be found at expected locations ('{ self ._dtbs } ')"
95- )
99+ msg = f"dtb is required for booting but it could not be found at expected locations ('{ self ._dtbs } ')"
100+ raise FileNotFoundError (msg )
96101
97102 def _get_default_smp_value (self ) -> int :
98103 if self .kernel_dir == utils .UNINIT_PATH :
99- raise RuntimeError ('No kernel build folder specified?' )
104+ msg = 'No kernel build folder specified?'
105+ raise RuntimeError (msg )
100106
101107 # If kernel_dir is the kernel source, the configuration will be at
102108 # <kernel_dir>/.config
@@ -118,18 +124,21 @@ def _get_default_smp_value(self) -> int:
118124 # Use the minimum of the number of usable processers for the script or
119125 # CONFIG_NR_CPUS.
120126 if not (usable_cpus := os .cpu_count ()):
121- raise RuntimeError ('Could not determine number of CPUs?' )
127+ msg = 'Could not determine number of CPUs?'
128+ raise RuntimeError (msg )
122129 return min (usable_cpus , config_nr_cpus )
123130
124131 def _get_kernel_ver_tuple (self , decomp_prog : str ) -> tuple [int , ...]:
125132 if self .kernel == utils .UNINIT_PATH :
126- raise RuntimeError ('No kernel set?' )
133+ msg = 'No kernel set?'
134+ raise RuntimeError (msg )
127135
128136 utils .check_cmd (decomp_prog )
129137 if decomp_prog == 'gzip' :
130138 decomp_cmd = [decomp_prog , '-c' , '-d' , self .kernel ]
131139 else :
132- raise RuntimeError (f"Unsupported decompression program ('{ decomp_prog } ')?" )
140+ msg = f"Unsupported decompression program ('{ decomp_prog } ')?"
141+ raise RuntimeError (msg )
133142 decomp = subprocess .run (decomp_cmd , capture_output = True , check = True )
134143
135144 utils .check_cmd ('strings' )
@@ -141,13 +150,15 @@ def _get_kernel_ver_tuple(self, decomp_prog: str) -> tuple[int, ...]:
141150 r'^Linux version (\d+\.\d+\.\d+)' , strings_stdout , flags = re .MULTILINE
142151 )
143152 ):
144- raise RuntimeError (f"Could not find Linux version in { self .kernel } ?" )
153+ msg = f"Could not find Linux version in { self .kernel } ?"
154+ raise RuntimeError (msg )
145155
146156 return tuple (int (x ) for x in match .groups ()[0 ].split ('.' ))
147157
148158 def _get_qemu_ver_string (self ) -> str :
149159 if self ._qemu_path == utils .UNINIT_PATH :
150- raise RuntimeError ('No path to QEMU set?' )
160+ msg = 'No path to QEMU set?'
161+ raise RuntimeError (msg )
151162 qemu_ver = subprocess .run (
152163 [self ._qemu_path , '--version' ], capture_output = True , check = True , text = True
153164 )
@@ -156,17 +167,20 @@ def _get_qemu_ver_string(self) -> str:
156167 def _get_qemu_ver_tuple (self ) -> tuple [int , ...]:
157168 qemu_ver_string = self ._get_qemu_ver_string ()
158169 if not (match := re .search (r'version (\d+\.\d+.\d+)' , qemu_ver_string )):
159- raise RuntimeError ('Could not find QEMU version?' )
170+ msg = 'Could not find QEMU version?'
171+ raise RuntimeError (msg )
160172 return tuple (int (x ) for x in match .groups ()[0 ].split ('.' ))
161173
162- def _have_dev_kvm_access (self ) -> bool :
174+ @staticmethod
175+ def _have_dev_kvm_access () -> bool :
163176 return os .access ('/dev/kvm' , os .R_OK | os .W_OK )
164177
165178 def _prepare_initrd (self ) -> Path :
166179 if self .initrd != utils .UNINIT_PATH :
167180 return self .initrd
168181 if not self ._initrd_arch :
169- raise RuntimeError ('No initrd architecture specified?' )
182+ msg = 'No initrd architecture specified?'
183+ raise RuntimeError (msg )
170184 return utils .prepare_initrd (
171185 self ._initrd_arch , gh_json_file = self .gh_json_file , modules = self .modules
172186 )
@@ -247,9 +261,11 @@ def _set_kernel_vars(self) -> None:
247261 return
248262
249263 if self .kernel_dir == utils .UNINIT_PATH :
250- raise RuntimeError ('No kernel image or kernel build folder specified?' )
264+ msg = 'No kernel image or kernel build folder specified?'
265+ raise RuntimeError (msg )
251266 if self ._default_kernel_path == utils .UNINIT_PATH :
252- raise RuntimeError ('No default kernel path specified?' )
267+ msg = 'No default kernel path specified?'
268+ raise RuntimeError (msg )
253269
254270 possible_kernel_locations = {
255271 Path (self ._default_kernel_path ), # default (kbuild)
@@ -261,10 +277,12 @@ def _set_qemu_path(self) -> None:
261277 if self ._qemu_path != utils .UNINIT_PATH :
262278 return # already found and set
263279 if not self ._qemu_arch :
264- raise RuntimeError ('No QEMU architecture set?' )
280+ msg = 'No QEMU architecture set?'
281+ raise RuntimeError (msg )
265282 qemu_bin = f"qemu-system-{ self ._qemu_arch } "
266283 if not (qemu_path := shutil .which (qemu_bin )):
267- raise RuntimeError (f'{ qemu_bin } could not be found on your system?' )
284+ msg = f'{ qemu_bin } could not be found on your system?'
285+ raise RuntimeError (msg )
268286 self ._qemu_path = Path (qemu_path )
269287
270288 def run (self ) -> None :
@@ -321,7 +339,7 @@ def run(self) -> None:
321339
322340
323341class ARMEFIQEMURunner (QEMURunner ):
324- def _setup_efi (self , possible_locations : Sequence [Union [ Path , str ] ]) -> None :
342+ def _setup_efi (self , possible_locations : Sequence [Path | str ]) -> None :
325343 # Sizing the images to 64M is recommended by "Prepare the firmware" section at
326344 # https://mirrors.edge.kernel.org/pub/linux/kernel/people/will/docs/qemu/qemu-arm64-howto.html
327345 efi_img_size = 64 * 1024 * 1024 # 64M
@@ -716,10 +734,12 @@ def guess_arch(kernel_arg: Path) -> str:
716734 # Note: 'required=False' just to provide our own exception.
717735 vmlinux_locations = ['vmlinux' , '../../../vmlinux' ]
718736 if not (vmlinux := utils .find_first_file (kernel_dir , vmlinux_locations , required = False )):
719- raise RuntimeError ('Architecture was not provided and vmlinux could not be found!' )
737+ msg = 'Architecture was not provided and vmlinux could not be found!'
738+ raise RuntimeError (msg )
720739
721740 if not (file := shutil .which ('file' )):
722- raise RuntimeError ("Architecture was not provided and 'file' is not installed!" )
741+ msg = "Architecture was not provided and 'file' is not installed!"
742+ raise RuntimeError (msg )
723743
724744 # Get output of file
725745 file_out = subprocess .run (
@@ -754,14 +774,12 @@ def guess_arch(kernel_arg: Path) -> str:
754774 for string , value in file_rosetta .items ():
755775 if string in file_out :
756776 if value == 'ambiguous' :
757- raise RuntimeError (
758- f"'{ string } ' found in '{ file_out } ' but the architecture is ambiguous, please explicitly specify it via '-a'!"
759- )
777+ msg = f"'{ string } ' found in '{ file_out } ' but the architecture is ambiguous, please explicitly specify it via '-a'!"
778+ raise RuntimeError (msg )
760779 return value
761780
762- raise RuntimeError (
763- f"Architecture could not be deduced from '{ file_out } ', please explicitly specify it via '-a' or add support for it to guess_arch()!"
764- )
781+ msg = f"Architecture could not be deduced from '{ file_out } ', please explicitly specify it via '-a' or add support for it to guess_arch()!"
782+ raise RuntimeError (msg )
765783
766784
767785def parse_arguments ():
@@ -840,11 +858,12 @@ def parse_arguments():
840858 return parser .parse_args ()
841859
842860
843- if __name__ == '__main__' :
861+ def main () :
844862 args = parse_arguments ()
845863
846864 if not (kernel_location := Path (args .kernel_location ).resolve ()).exists ():
847- raise FileNotFoundError (f"Supplied kernel location ('{ kernel_location } ') does not exist!" )
865+ msg = f"Supplied kernel location ('{ kernel_location } ') does not exist!"
866+ raise FileNotFoundError (msg )
848867
849868 if not (arch := args .architecture ):
850869 arch = guess_arch (kernel_location )
@@ -874,8 +893,9 @@ def parse_arguments():
874893
875894 if kernel_location .is_file ():
876895 if args .gdb and kernel_location .name != 'vmlinux' :
896+ msg = 'Debugging with gdb requires a kernel build folder to locate vmlinux'
877897 raise RuntimeError (
878- 'Debugging with gdb requires a kernel build folder to locate vmlinux' ,
898+ msg ,
879899 )
880900 runner .kernel = kernel_location
881901 else :
@@ -898,15 +918,17 @@ def parse_arguments():
898918
899919 if args .initrd :
900920 if not (initrd := Path (args .initrd ).resolve ()).exists ():
901- raise FileNotFoundError (f"Supplied initrd ('{ initrd } ') does not exist?" )
921+ msg = f"Supplied initrd ('{ initrd } ') does not exist?"
922+ raise FileNotFoundError (msg )
902923 runner .initrd = initrd
903924
904925 if args .memory :
905926 runner .memory = args .memory
906927
907928 if args .modules :
908929 if not (modules := Path (args .modules ).resolve ()).exists ():
909- raise FileNotFoundError (f"Supplied modules .cpio ('{ modules } ') does not exist?" )
930+ msg = f"Supplied modules .cpio ('{ modules } ') does not exist?"
931+ raise FileNotFoundError (msg )
910932 if not args .memory :
911933 utils .yellow ('Memory not specified, the default may be too small for modules...' )
912934 runner .modules = modules
@@ -921,3 +943,7 @@ def parse_arguments():
921943 runner .timeout = args .timeout
922944
923945 runner .run ()
946+
947+
948+ if __name__ == '__main__' :
949+ main ()
0 commit comments