added bootloader/ESP detection using efibootmgr

This commit is contained in:
Florian Schroegendorfer 2024-06-07 00:01:57 +02:00
parent ed26f89aef
commit 41398abdcf
Signed by: root
GPG Key ID: 17625E28D4D6E339
8 changed files with 161 additions and 160 deletions

View File

@ -45,7 +45,10 @@ class Kernel:
modules = pathlib.Path("/lib/modules") modules = pathlib.Path("/lib/modules")
# EFI system partition # EFI system partition
esp = pathlib.Path("/boot/EFI/Gentoo") esp = pathlib.Path("/boot")
# EFI bootloader (stub kernel)
boot = esp / "EFI/Gentoo/bootx64.efi"
def __init__ (self, src): def __init__ (self, src):
"""Construct a Kernel based on a given source path.""" """Construct a Kernel based on a given source path."""
@ -58,8 +61,7 @@ class Kernel:
raise ValueError(f"illegal source: {src}") from e raise ValueError(f"illegal source: {src}") from e
self.config = self.src / ".config" self.config = self.src / ".config"
self.bzImage = self.src / "arch/x86_64/boot/bzImage" self.bzImage = self.src / "arch/x86_64/boot/bzImage"
self.bootx64 = self.esp / "bootx64.efi" self.bkp = self.boot.parent / f"gentoo-{self.version.base_version}.efi"
self.efi = self.esp / f"gentoo-{self.version.base_version}.efi"
self.modules = self.modules / f"{self.version.base_version}-gentoo" self.modules = self.modules / f"{self.version.base_version}-gentoo"
def __eq__ (self, other): def __eq__ (self, other):
@ -75,14 +77,14 @@ class Kernel:
f"* config = {self.config}\n" f"* config = {self.config}\n"
f"* bzImage = {self.bzImage}\n" f"* bzImage = {self.bzImage}\n"
f"* modules = {self.modules}\n" f"* modules = {self.modules}\n"
f"* efi = {self.efi}\n" f"* bkp = {self.bkp}\n"
) )
@classmethod @classmethod
def list (cls, descending=True): def list (cls, descending=True):
"""Get an descending list of available kernels.""" """Get an descending list of available kernels."""
return list(sorted( return list(sorted(
( Kernel(src) for src in cls.src.glob("linux-*") ), (Kernel(src) for src in cls.src.glob("linux-*")),
key=lambda k: k.version, key=lambda k: k.version,
reverse=descending reverse=descending
)) ))
@ -112,11 +114,6 @@ def cli (f):
@functools.wraps(f) @functools.wraps(f)
def handler (argv=sys.argv[1:]): def handler (argv=sys.argv[1:]):
try: try:
# dirty hack: set custom esp before mounting
try:
i = argv.index("-e")
Kernel.esp = pathlib.Path(argv[i + 1])
except ValueError: pass
r = f(argv) r = f(argv)
return 0 if r is None else r return 0 if r is None else r
except Exception as e: except Exception as e:
@ -124,30 +121,64 @@ def cli (f):
sys.exit(1) sys.exit(1)
return handler return handler
def mount (f): def efi (f):
"""Decorator ensuring a given path is mounted.""" """Decorator locating and mounting the ESP through efivars."""
@functools.wraps(f) @functools.wraps(f)
def mounter (*args, **kwargs): def locator (*args, **kwargs):
mounted = False mounted = False
esp = Kernel.esp.parents[-2] # ensure access to the currently running EFI bootloader / stub kernel
if not esp.exists() or mount.force: if not Kernel.boot.exists():
# find current bootloader
mgr = subprocess.run(
["efibootmgr"],
capture_output=True,
check=True
)
lines = iter(mgr.stdout.decode().splitlines())
bootnum = "NaN"
for l in lines:
if l.startswith("BootCurrent"):
bootnum = l.split()[1]
break
for l in lines:
if l.startswith(f"Boot{bootnum}"):
i = l.find("File")
if i < 0:
raise RuntimeError(f"error locating bootloader:\n{l}")
i += 6
j = l.find(")", i)
loader = pathlib.Path(l[i:j].replace("\\", "/"))
break
# find mountpoint
for l in pathlib.Path("/etc/fstab").read_text().splitlines():
if not l.startswith("#"):
for p in ["/boot", "/efi"]:
if p in l:
Kernel.esp = pathlib.Path(p)
Kernel.boot = Kernel.esp / loader
break
else: continue
break
# mount esp
if not Kernel.boot.exists():
try: try:
subprocess.run( subprocess.run(
["mount", str(esp)], ["mount", str(Kernel.esp)],
capture_output=True, capture_output=True,
check=True check=True
) )
mounted = True mounted = True
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
msg = e.stderr.decode().strip() msg = e.stderr.decode().strip()
if f"already mounted on {esp}" not in msg: if f"already mounted on {Kernel.esp}" not in msg:
raise RuntimeError(e.stderr.decode().splitlines()[0]) raise RuntimeError(e.stderr.decode().splitlines()[0])
assert Kernel.boot.exists()
r = f(*args, **kwargs) r = f(*args, **kwargs)
# umount esp
if mounted: if mounted:
subprocess.run(["umount", str(esp)], check=True) subprocess.run(["umount", str(Kernel.esp)], check=True)
return r return r
mount.force = False return locator
return mounter
@cli @cli
def configure (argv): def configure (argv):
@ -347,7 +378,7 @@ def build (argv):
subprocess.run(["make", "modules_install"], check=True) subprocess.run(["make", "modules_install"], check=True)
@cli @cli
@mount @efi
def install (argv): def install (argv):
""" """
Install a kernel. Install a kernel.
@ -359,9 +390,6 @@ def install (argv):
Command Line Arguments Command Line Arguments
---------------------- ----------------------
``-e <esp>``
EFI bootloader directory (default: ``/boot/EFI/Gentoo``)
``-s <src>`` ``-s <src>``
kernel source directory (default: latest) kernel source directory (default: latest)
@ -388,13 +416,6 @@ def install (argv):
description="Install a kernel.", description="Install a kernel.",
formatter_class=argparse.RawDescriptionHelpFormatter formatter_class=argparse.RawDescriptionHelpFormatter
) )
parser.add_argument(
"-e",
metavar="<esp>",
dest="esp",
type=pathlib.Path,
help="EFI bootloader directory (default: /boot/EFI/Gentoo)"
)
parser.add_argument( parser.add_argument(
"-s", "-s",
metavar="<src>", metavar="<src>",
@ -410,7 +431,6 @@ def install (argv):
help="be quiet" help="be quiet"
) )
args = parser.parse_args(argv) args = parser.parse_args(argv)
if args.esp: Kernel.esp = args.esp # redundant
kernel = Kernel(args.src) kernel = Kernel(args.src)
out.quiet = args.quiet out.quiet = args.quiet
@ -429,19 +449,19 @@ def install (argv):
) )
# copy boot image # copy boot image
out.einfo(f"creating boot image {out.hilite(kernel.bootx64)}") out.einfo(f"creating boot image {out.hilite(kernel.boot)}")
shutil.copy(kernel.bzImage, kernel.bootx64) shutil.copy(kernel.bzImage, kernel.boot)
# create backup # create backup
out.einfo(f"creating backup image {out.hilite(kernel.efi)}") out.einfo(f"creating backup image {out.hilite(kernel.bkp)}")
shutil.copy(kernel.bzImage, kernel.efi) shutil.copy(kernel.bzImage, kernel.bkp)
# rebuild external modules # rebuild external modules
out.einfo(f"rebuilding external kernel modules") out.einfo(f"rebuilding external kernel modules")
subprocess.run(["emerge", "@module-rebuild"], check=True) subprocess.run(["emerge", "@module-rebuild"], check=True)
@cli @cli
@mount @efi
def clean (argv): def clean (argv):
""" """
Remove unused kernel leftovers. Remove unused kernel leftovers.
@ -455,9 +475,6 @@ def clean (argv):
Command Line Arguments Command Line Arguments
---------------------- ----------------------
``-e <esp>``
EFI bootloader directory (default: ``/boot/EFI/Gentoo``)
``-k <num>`` ``-k <num>``
keep the previous ``<num>`` kernels (default: 1) keep the previous ``<num>`` kernels (default: 1)
@ -473,14 +490,6 @@ def clean (argv):
description="Remove unused kernel leftovers.", description="Remove unused kernel leftovers.",
formatter_class=argparse.RawDescriptionHelpFormatter formatter_class=argparse.RawDescriptionHelpFormatter
) )
parser.add_argument(
"-e",
metavar="<esp>",
dest="esp",
type=pathlib.Path,
default=Kernel.esp,
help="EFI bootloader directory (default: /boot/EFI/Gentoo)"
)
parser.add_argument( parser.add_argument(
"-k", "-k",
metavar="<keep>", metavar="<keep>",
@ -502,15 +511,14 @@ def clean (argv):
help="be quiet" help="be quiet"
) )
args = parser.parse_args(argv) args = parser.parse_args(argv)
if args.esp: Kernel.esp = args.esp # redundant
out.quiet = args.quiet out.quiet = args.quiet
if args.keep < 0: if args.keep < 0:
raise ValueError("invalid int value: must be greater equal zero") raise ValueError("invalid keep value: must be greater equal zero")
# kernels to remove # kernels to remove
kernels = Kernel.list() kernels = Kernel.list()
def obsolete (k): def obsolete (k):
if args.keep and k.efi.exists() and k.modules.exists(): if args.keep and k.bkp.exists() and k.modules.exists():
args.keep -= 1 args.keep -= 1
return False return False
return True return True
@ -534,7 +542,7 @@ def clean (argv):
out.einfo(f"removing {out.hilite(k.src.name)}") out.einfo(f"removing {out.hilite(k.src.name)}")
shutil.rmtree(k.src) shutil.rmtree(k.src)
shutil.rmtree(k.modules, ignore_errors=True) shutil.rmtree(k.modules, ignore_errors=True)
k.efi.unlink(missing_ok=True) k.bkp.unlink(missing_ok=True)
@cli @cli
def commit (argv): def commit (argv):
@ -762,6 +770,7 @@ def commit (argv):
raise RuntimeError(e.stderr.decode()) raise RuntimeError(e.stderr.decode())
@cli @cli
@efi
def update (argv): def update (argv):
"""Custom Gentoo EFI stub kernel updater.""" """Custom Gentoo EFI stub kernel updater."""
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
@ -776,13 +785,6 @@ def update (argv):
type=int, type=int,
help=f"number of parallel make jobs (default: {jobs})" help=f"number of parallel make jobs (default: {jobs})"
) )
parser.add_argument(
"-e",
metavar="<esp>",
dest="esp",
type=pathlib.Path,
help="EFI bootloader directory (default: /boot/EFI/Gentoo)"
)
parser.add_argument( parser.add_argument(
"-s", "-s",
metavar="<src>", metavar="<src>",
@ -812,7 +814,6 @@ def update (argv):
) )
args = parser.parse_args(argv) args = parser.parse_args(argv)
args.jobs = ["-j", str(args.jobs)] if args.jobs else [] args.jobs = ["-j", str(args.jobs)] if args.jobs else []
args.esp = ["-e", str(args.esp)] if args.esp else [] # redundant
args.src = ["-s", str(args.src)] if args.src else [] args.src = ["-s", str(args.src)] if args.src else []
args.keep = ["-k", str(args.keep)] if args.keep is not None else [] args.keep = ["-k", str(args.keep)] if args.keep is not None else []
args.msg = ["-m", args.msg] if args.msg else [] args.msg = ["-m", args.msg] if args.msg else []
@ -820,6 +821,6 @@ def update (argv):
configure(args.quiet + args.src) configure(args.quiet + args.src)
build(args.quiet + args.jobs + args.src) build(args.quiet + args.jobs + args.src)
install(args.quiet + args.esp + args.src) install(args.quiet + args.src)
clean(args.quiet + args.esp + args.keep) clean(args.quiet + args.keep)
commit(args.quiet + args.msg) commit(args.quiet + args.msg)

View File

@ -1,28 +1,30 @@
"""Setup the kernel test environment.""" """Setup the kernel test environment."""
import functools
import pathlib import pathlib
import shutil import shutil
import subprocess
import tempfile import tempfile
from ekernel import Kernel from ekernel import Kernel
# create temporary directory # create temporary directory
tmpdir = tempfile.TemporaryDirectory() tmpdir = tempfile.TemporaryDirectory()
root = pathlib.Path(tmpdir.name) tmp = pathlib.Path(tmpdir.name)
# kernel source directory # kernel source directory
src = root / "usr/src" src = tmp / "usr/src"
# kernel source symlink # kernel source symlink
linux = src / "linux" linux = src / "linux"
# kernel module directory # kernel module directory
modules = root / "lib/modules" modules = tmp / "lib/modules"
# EFI system partition # EFI system partition
esp = root / "boot/EFI/Gentoo" esp = tmp.parents[-2]
# boot image # boot image
bootx64 = esp / "bootx64.efi" boot = tmp / "boot/EFI/Gentoo/bootx64.efi"
# list of installed kernels # list of installed kernels
kernels = [] kernels = []
@ -67,21 +69,41 @@ CONFIG_D=y
CONFIG_F=y CONFIG_F=y
""" """
def efi (f):
"""Decorator adding common EFI related test actions."""
@functools.wraps(f)
def runner (t, *args, **kwargs):
if args[0][0] == "efibootmgr":
boot.touch()
return subprocess.CompletedProcess("", 0,
"BootCurrent: 0001\n"
"Timeout: 1 seconds\n"
"BootOrder: 0001,0000\n"
"Boot0000* Windows HD()/File()\n"
"Boot0001* Gentoo HD()/File(\\EFI\\gentoo\\bootx64.efi)\n"
.encode()
)
elif args[0][0] == "mount":
Kernel.esp = esp
Kernel.boot = boot
return f(t, *args, **kwargs)
return runner
def setup (): def setup ():
"""Setup the kernel test environment.""" """Setup the kernel test environment."""
# remove any existing files # remove any existing files
for p in root.glob("*"): for p in tmp.glob("*"):
shutil.rmtree(p) shutil.rmtree(p)
# change Kernel class' root directory # change Kernel paths
Kernel.src = src Kernel.src = src
Kernel.linux = linux Kernel.linux = linux
Kernel.modules = modules Kernel.modules = modules
Kernel.esp = esp Kernel.esp = esp
Kernel.bootx64 = bootx64 Kernel.boot = boot
# create EFI system partition # create EFI system partition
esp.mkdir(parents=True) boot.parent.mkdir(parents=True)
# create Kernels # create Kernels
for s in sources: s.mkdir(parents=True) for s in sources: s.mkdir(parents=True)
@ -97,7 +119,7 @@ def setup ():
else: else:
k.config.touch() k.config.touch()
k.bzImage.touch() k.bzImage.touch()
k.efi.touch() k.bkp.touch()
k.modules.mkdir(parents=True) k.modules.mkdir(parents=True)
# symlink to old source directory # symlink to old source directory

View File

@ -79,7 +79,7 @@ class Tests (unittest.TestCase):
@capture_stderr @capture_stderr
def test_build_source_illegal (self): def test_build_source_illegal (self):
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
run("-s", str(data.root)) run("-s", str(data.tmp))
def test_build_jobs_source (self): def test_build_jobs_source (self):
self.jobs = "128" self.jobs = "128"

View File

@ -23,19 +23,19 @@ class Tests (unittest.TestCase):
data.linux.unlink() data.linux.unlink()
data.linux.symlink_to(data.latest) data.linux.symlink_to(data.latest)
# initialize git repository # initialize git repository
os.chdir(data.root) os.chdir(data.tmp)
for k in data.kernels[:-2]: for k in data.kernels[:-2]:
if not k.config.exists(): if not k.config.exists():
k.config.touch() k.config.touch()
if not k.modules.exists(): if not k.modules.exists():
k.modules.mkdir(parents=True) k.modules.mkdir(parents=True)
if not k.efi.exists(): if not k.bkp.exists():
k.efi.touch() k.bkp.touch()
# force mounting
ekernel.mount.force = True
# start interceptor # start interceptor
@data.efi
def run (tracer, *args, **kwargs): pass
self.interceptor = Interceptor() self.interceptor = Interceptor()
self.interceptor.add(subprocess.run, call=True) self.interceptor.add(subprocess.run, call=run)
self.interceptor.start() self.interceptor.start()
def tearDown (self): def tearDown (self):
@ -45,10 +45,15 @@ class Tests (unittest.TestCase):
def check_clean (self, keep=1): def check_clean (self, keep=1):
split = data.kernels.index(Kernel.current()) + keep + 1 split = data.kernels.index(Kernel.current()) + keep + 1
trace_it = iter(self.interceptor.trace) trace_it = iter(self.interceptor.trace)
# efibootmgr
tracer, (args, kwargs) = next(trace_it)
self.assertEqual(tracer.name, "subprocess.run")
self.assertEqual(args, (["efibootmgr"],))
self.assertEqual(kwargs, {"capture_output": True, "check": True})
# mount /boot # mount /boot
tracer, (args, kwargs) = next(trace_it) tracer, (args, kwargs) = next(trace_it)
self.assertEqual(tracer.name, "subprocess.run") self.assertEqual(tracer.name, "subprocess.run")
self.assertEqual(args, (["mount", "/tmp"],)) self.assertEqual(args, (["mount", "/boot"],))
self.assertEqual(kwargs, {"capture_output": True, "check": True}) self.assertEqual(kwargs, {"capture_output": True, "check": True})
# emerge -cq gentoo-sources # emerge -cq gentoo-sources
tracer, (args, kwargs) = next(trace_it) tracer, (args, kwargs) = next(trace_it)
@ -58,11 +63,11 @@ class Tests (unittest.TestCase):
for k in data.kernels[:split]: for k in data.kernels[:split]:
self.assertTrue(k.src.exists()) self.assertTrue(k.src.exists())
self.assertTrue(k.modules.exists()) self.assertTrue(k.modules.exists())
self.assertTrue(k.efi.exists()) self.assertTrue(k.bkp.exists())
for k in data.kernels[split:]: for k in data.kernels[split:]:
self.assertFalse(k.src.exists()) self.assertFalse(k.src.exists())
self.assertFalse(k.modules.exists()) self.assertFalse(k.modules.exists())
self.assertFalse(k.efi.exists()) self.assertFalse(k.bkp.exists())
# umount /boot # umount /boot
tracer, (args, kwargs) = next(trace_it) tracer, (args, kwargs) = next(trace_it)
self.assertEqual(tracer.name, "subprocess.run") self.assertEqual(tracer.name, "subprocess.run")
@ -74,7 +79,7 @@ class Tests (unittest.TestCase):
self.check_clean() self.check_clean()
def test_clean_missing_efi (self): def test_clean_missing_efi (self):
data.kernels[-1].efi.unlink() data.kernels[-1].bkp.unlink()
self.assertEqual(run("-q"), 0) self.assertEqual(run("-q"), 0)
self.check_clean() self.check_clean()
@ -95,19 +100,6 @@ class Tests (unittest.TestCase):
self.assertEqual(run("-q", "-k", "10"), 0) self.assertEqual(run("-q", "-k", "10"), 0)
self.check_clean(10) self.check_clean(10)
def test_clean_esp (self):
esp = data.root / "boot/EFI/linux"
esp.mkdir(parents=True)
for k in data.kernels:
efi = esp / k.efi.name
if k.efi.exists():
efi.touch()
k.efi.unlink()
k.efi = efi
data.esp.rmdir()
self.assertEqual(run("-q", "-e", str(esp)), 0)
self.check_clean()
@colorless @colorless
@capture_stdout @capture_stdout
def test_clean_dry_run (self): def test_clean_dry_run (self):

View File

@ -24,7 +24,7 @@ class Tests (unittest.TestCase):
data.linux.unlink() data.linux.unlink()
data.linux.symlink_to(data.latest) data.linux.symlink_to(data.latest)
# initialize git repository # initialize git repository
os.chdir(data.root) os.chdir(data.tmp)
git(["init"]) git(["init"])
git(["config", "user.email", "some@e.mail"]) git(["config", "user.email", "some@e.mail"])
git(["config", "user.name", "some body"]) git(["config", "user.name", "some body"])
@ -51,7 +51,7 @@ class Tests (unittest.TestCase):
git([ git([
"cat-file", "cat-file",
"-e", "-e",
f"HEAD:{self.latest.config.relative_to(data.root)}"] f"HEAD:{self.latest.config.relative_to(data.tmp)}"]
).returncode, ).returncode,
0 0
) )
@ -141,7 +141,7 @@ class Tests (unittest.TestCase):
@colorless @colorless
@capture_stderr @capture_stderr
def test_commit_missing_repository (self): def test_commit_missing_repository (self):
shutil.rmtree(data.root / ".git") shutil.rmtree(data.tmp / ".git")
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
self.assertEqual(run(), 1) self.assertEqual(run(), 1)
self.assertRegex(sys.stderr.getvalue(), r"not a git repository") self.assertRegex(sys.stderr.getvalue(), r"not a git repository")

View File

@ -18,14 +18,13 @@ class Tests (unittest.TestCase):
data.setup() data.setup()
self.kernel = Kernel.latest() self.kernel = Kernel.latest()
self.kernel.bzImage.touch() self.kernel.bzImage.touch()
# force mounting
ekernel.mount.force = True
# start interceptor # start interceptor
self.interceptor = Interceptor() @data.efi
def run (tracer, *args, **kwargs): def run (tracer, *args, **kwargs):
if args[0][0] == "eselect": if args[0][0] == "eselect":
data.linux.unlink() data.linux.unlink()
data.linux.symlink_to(self.kernel.src.name) data.linux.symlink_to(self.kernel.src.name)
self.interceptor = Interceptor()
self.interceptor.add(subprocess.run, call=run) self.interceptor.add(subprocess.run, call=run)
self.interceptor.start() self.interceptor.start()
@ -35,10 +34,15 @@ class Tests (unittest.TestCase):
def check_install (self): def check_install (self):
trace_it = iter(self.interceptor.trace) trace_it = iter(self.interceptor.trace)
# efibootmgr
tracer, (args, kwargs) = next(trace_it)
self.assertEqual(tracer.name, "subprocess.run")
self.assertEqual(args, (["efibootmgr"],))
self.assertEqual(kwargs, {"capture_output": True, "check": True})
# mount /boot # mount /boot
tracer, (args, kwargs) = next(trace_it) tracer, (args, kwargs) = next(trace_it)
self.assertEqual(tracer.name, "subprocess.run") self.assertEqual(tracer.name, "subprocess.run")
self.assertEqual(args, (["mount", "/tmp"],)) self.assertEqual(args, (["mount", "/boot"],))
self.assertEqual(kwargs, {"capture_output": True, "check": True}) self.assertEqual(kwargs, {"capture_output": True, "check": True})
# eselect kernel set <name> # eselect kernel set <name>
tracer, (args, kwargs) = next(trace_it) tracer, (args, kwargs) = next(trace_it)
@ -54,26 +58,19 @@ class Tests (unittest.TestCase):
self.assertEqual(tracer.name, "subprocess.run") self.assertEqual(tracer.name, "subprocess.run")
self.assertEqual(args, (["emerge", "@module-rebuild"],)) self.assertEqual(args, (["emerge", "@module-rebuild"],))
self.assertEqual(kwargs, {"check": True}) self.assertEqual(kwargs, {"check": True})
# umount /boot
tracer, (args, kwargs) = next(trace_it)
self.assertEqual(tracer.name, "subprocess.run")
self.assertEqual(args, (["umount", "/tmp"],))
self.assertEqual(kwargs, {"check": True})
# check generated files # check generated files
self.assertTrue(self.kernel.bootx64.exists()) self.assertTrue(self.kernel.boot.exists())
self.assertTrue(self.kernel.efi.exists()) self.assertTrue(self.kernel.bkp.exists())
def test_install (self): def test_install (self):
self.assertEqual(run("-q"), 0) self.assertEqual(run("-q"), 0)
self.check_install() self.check_install()
def test_install_esp (self):
esp = data.root / "boot/EFI/linux"
esp.mkdir(parents=True)
self.kernel.efi = esp / self.kernel.efi.name
self.kernel.bootx64 = esp / self.kernel.bootx64.name
self.assertEqual(run("-q", "-e", str(esp)), 0)
self.check_install()
def test_install_esp_missing (self):
with self.assertRaises(SystemExit):
run("-q", "-e", str(data.root / "boot/EFI/linux"))
def test_install_source (self): def test_install_source (self):
self.kernel = Kernel.current() self.kernel = Kernel.current()
self.assertEqual(run("-q", "-s", str(data.current)), 0) self.assertEqual(run("-q", "-s", str(data.current)), 0)

View File

@ -19,14 +19,17 @@ class Tests (unittest.TestCase):
self.assertEqual(k.src, s) self.assertEqual(k.src, s)
self.assertEqual(k.config, s / ".config") self.assertEqual(k.config, s / ".config")
self.assertEqual(k.bzImage, s / "arch/x86_64/boot/bzImage") self.assertEqual(k.bzImage, s / "arch/x86_64/boot/bzImage")
self.assertEqual(k.efi, data.esp / f"gentoo-{v.base_version}.efi")
self.assertEqual(k.modules, data.modules / f"{v.base_version}-gentoo") self.assertEqual(k.modules, data.modules / f"{v.base_version}-gentoo")
self.assertEqual(
k.bkp,
data.boot.parent / f"gentoo-{v.base_version}.efi"
)
def test_paths (self): def test_paths (self):
self.assertEqual(ekernel.Kernel.src, data.src) self.assertEqual(ekernel.Kernel.src, data.src)
self.assertEqual(ekernel.Kernel.linux, data.linux) self.assertEqual(ekernel.Kernel.linux, data.linux)
self.assertEqual(ekernel.Kernel.esp, data.esp) self.assertEqual(ekernel.Kernel.esp, data.esp)
self.assertEqual(ekernel.Kernel.bootx64, data.bootx64) self.assertEqual(ekernel.Kernel.boot, data.boot)
self.assertEqual(ekernel.Kernel.modules, data.modules) self.assertEqual(ekernel.Kernel.modules, data.modules)
def test_version (self): def test_version (self):

View File

@ -15,8 +15,19 @@ def run (*argv):
class Tests (unittest.TestCase): class Tests (unittest.TestCase):
def setUp (self): def setUp (self):
# setup test environment
data.setup()
self.latest = Kernel.latest()
self.oldconfig = data.latest / ".config.old"
# initialize git repository
os.chdir(data.tmp)
git(["init"])
git(["config", "user.email", "some@e.mail"])
git(["config", "user.name", "some body"])
git(["add", "-f", Kernel.current().config])
git(["commit", "-m", "initial"])
# start interceptor # start interceptor
self.interceptor = Interceptor() @data.efi
def run (tracer, *args, **kwargs): def run (tracer, *args, **kwargs):
if args[0][0] == "make": if args[0][0] == "make":
if args[0][1] == "listnewconfig": if args[0][1] == "listnewconfig":
@ -33,38 +44,28 @@ class Tests (unittest.TestCase):
data.linux.symlink_to(data.latest) data.linux.symlink_to(data.latest)
elif args[0][0] == "git": elif args[0][0] == "git":
return tracer.target(*args, **kwargs) return tracer.target(*args, **kwargs)
self.interceptor = Interceptor()
self.interceptor.add(subprocess.run, call=run) self.interceptor.add(subprocess.run, call=run)
self.interceptor.start() self.interceptor.start()
# setup test environmenT
data.setup()
self.latest = Kernel.latest()
self.oldconfig = data.latest / ".config.old"
# initialize git repository
os.chdir(data.root)
git(["init"])
git(["config", "user.email", "some@e.mail"])
git(["config", "user.name", "some body"])
git(["add", "-f", Kernel.current().config])
git(["commit", "-m", "initial"])
def check_update (self): def check_update (self):
# configure # configure
self.assertTrue(self.oldconfig.exists()) self.assertTrue(self.oldconfig.exists())
self.assertTrue(self.latest.config.exists()) self.assertTrue(self.latest.config.exists())
# install # install
self.assertTrue(self.latest.bootx64.exists()) self.assertTrue(self.latest.boot.exists())
self.assertTrue(self.latest.efi.exists()) self.assertTrue(self.latest.bkp.exists())
# clean # clean
for k in data.kernels[2:]: for k in data.kernels[2:]:
self.assertFalse(k.src.exists()) self.assertFalse(k.src.exists())
self.assertFalse(k.modules.exists()) self.assertFalse(k.modules.exists())
self.assertFalse(k.efi.exists()) self.assertFalse(k.bkp.exists())
# check if config has been commited # check if config has been commited
self.assertEqual( self.assertEqual(
git([ git([
"cat-file", "cat-file",
"-e", "-e",
f"HEAD:{self.latest.config.relative_to(data.root)}"] f"HEAD:{self.latest.config.relative_to(data.tmp)}"]
).returncode, ).returncode,
0 0
) )
@ -81,21 +82,6 @@ class Tests (unittest.TestCase):
self.assertEqual(run("-q", "-j", "8"), 0) self.assertEqual(run("-q", "-j", "8"), 0)
self.check_update() self.check_update()
def test_update_esp (self):
esp = data.root / "boot/EFI/linux"
esp.mkdir(parents=True)
for k in data.kernels:
efi = esp / k.efi.name
if k.efi.exists():
efi.touch()
k.efi.unlink()
k.efi = efi
data.esp.rmdir()
self.latest.efi = esp / self.latest.efi.name
self.latest.bootx64 = esp / self.latest.bootx64.name
self.assertEqual(run("-q", "-e", str(esp)), 0)
self.check_update()
def test_update_source (self): def test_update_source (self):
self.assertEqual(run("-q", "-s", str(data.latest)), 0) self.assertEqual(run("-q", "-s", str(data.latest)), 0)
self.check_update() self.check_update()
@ -106,7 +92,7 @@ class Tests (unittest.TestCase):
self.check_update() self.check_update()
self.assertFalse(current.src.exists()) self.assertFalse(current.src.exists())
self.assertFalse(current.modules.exists()) self.assertFalse(current.modules.exists())
self.assertFalse(current.efi.exists()) self.assertFalse(current.bkp.exists())
@capture_stdout @capture_stdout
def test_update_message (self): def test_update_message (self):