added option to create a fallback boot entry
This commit is contained in:
parent
d622c8064c
commit
588b8c05ac
188
ekernel.py
188
ekernel.py
@ -4,6 +4,7 @@ import functools
|
|||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
import platform
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -44,12 +45,6 @@ class Kernel:
|
|||||||
# module directory
|
# module directory
|
||||||
modules = pathlib.Path("/lib/modules")
|
modules = pathlib.Path("/lib/modules")
|
||||||
|
|
||||||
# EFI system partition
|
|
||||||
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."""
|
||||||
self.src = pathlib.Path(src)
|
self.src = pathlib.Path(src)
|
||||||
@ -61,7 +56,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.bkp = self.boot.parent / f"gentoo-{self.version.base_version}.efi"
|
self.bkp = efi.boot.parent / 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):
|
||||||
@ -123,62 +118,91 @@ def cli (f):
|
|||||||
|
|
||||||
def efi (f):
|
def efi (f):
|
||||||
"""Decorator locating and mounting the ESP through efivars."""
|
"""Decorator locating and mounting the ESP through efivars."""
|
||||||
|
efi.skip = False
|
||||||
|
# system partition
|
||||||
|
efi.esp = pathlib.Path("/boot")
|
||||||
|
# bootloader (stub kernel)
|
||||||
|
efi.boot = efi.esp / "EFI/Gentoo/bootx64.efi"
|
||||||
|
# backup entry data
|
||||||
|
efi.bkp = {}
|
||||||
|
# analyze boot entries and ensure access to the currently running image
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def locator (*args, **kwargs):
|
def locator (*args, **kwargs):
|
||||||
|
# skip detection
|
||||||
|
if efi.skip:
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
efi.skip = True
|
||||||
|
# get boot entries
|
||||||
|
mgr = subprocess.run(
|
||||||
|
["efibootmgr"],
|
||||||
|
capture_output=True,
|
||||||
|
check=True
|
||||||
|
)
|
||||||
|
entries = mgr.stdout.decode().splitlines()
|
||||||
|
bootnum = "NaN"
|
||||||
|
for l in entries:
|
||||||
|
if l.startswith("BootCurrent"):
|
||||||
|
bootnum = l.split()[1]
|
||||||
|
break
|
||||||
|
# find currently running boot entry / loader
|
||||||
|
def parse (entry):
|
||||||
|
# label
|
||||||
|
i = l.find(" ") + 1
|
||||||
|
j = l.find("\t", i)
|
||||||
|
label = l[i:j]
|
||||||
|
# loader
|
||||||
|
i = l.find("File", j)
|
||||||
|
if i < 0:
|
||||||
|
raise RuntimeError(f"error locating bootloader:\n{l}")
|
||||||
|
i += 6
|
||||||
|
j = l.find(")", i)
|
||||||
|
loader = pathlib.Path(l[i:j].replace("\\", "/"))
|
||||||
|
return label, loader
|
||||||
|
for l in entries:
|
||||||
|
if l.startswith(f"Boot{bootnum}"):
|
||||||
|
label, loader = parse(l)
|
||||||
|
efi.label = label
|
||||||
|
efi.bkp["label"] = f"{label} (fallback)"
|
||||||
|
break
|
||||||
|
# find bootnum of backup entry
|
||||||
|
for l in entries:
|
||||||
|
if efi.bkp["label"] in l:
|
||||||
|
efi.bkp["bootnum"] = l[4:8]
|
||||||
|
break
|
||||||
|
# mount esp
|
||||||
mounted = False
|
mounted = False
|
||||||
# ensure access to the currently running EFI bootloader / stub kernel
|
if not efi.boot.exists():
|
||||||
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
|
# find mountpoint
|
||||||
for l in pathlib.Path("/etc/fstab").read_text().splitlines():
|
for l in pathlib.Path("/etc/fstab").read_text().splitlines():
|
||||||
if not l.startswith("#"):
|
if not l.startswith("#"):
|
||||||
for p in ["/boot", "/efi"]:
|
for p in ["/boot", "/efi"]:
|
||||||
if p in l:
|
if p in l:
|
||||||
Kernel.esp = pathlib.Path(p)
|
efi.esp = pathlib.Path(p)
|
||||||
Kernel.boot = Kernel.esp / loader
|
efi.boot = efi.esp / loader
|
||||||
break
|
break
|
||||||
else: continue
|
else: continue
|
||||||
break
|
break
|
||||||
# mount esp
|
else:
|
||||||
if not Kernel.boot.exists():
|
raise RuntimeError("error finding ESP mountpoint")
|
||||||
try:
|
try:
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
["mount", str(Kernel.esp)],
|
["mount", str(efi.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 {Kernel.esp}" not in msg:
|
if f"already mounted on {efi.esp}" not in msg:
|
||||||
raise RuntimeError(e.stderr.decode().splitlines()[0])
|
raise RuntimeError(e.stderr.decode().splitlines()[0])
|
||||||
assert Kernel.boot.exists()
|
assert efi.boot.exists()
|
||||||
try:
|
try:
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
finally:
|
finally:
|
||||||
|
efi.skip = False
|
||||||
# umount esp
|
# umount esp
|
||||||
if mounted:
|
if mounted:
|
||||||
subprocess.run(["umount", str(Kernel.esp)], check=True)
|
subprocess.run(["umount", str(efi.esp)], check=True)
|
||||||
return locator
|
return locator
|
||||||
|
|
||||||
@cli
|
@cli
|
||||||
@ -267,7 +291,7 @@ def configure (argv):
|
|||||||
try:
|
try:
|
||||||
oldconfig = Kernel.current().config
|
oldconfig = Kernel.current().config
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
oldconfig = Kernel.esp / "FILENOTFOUND"
|
oldconfig = efi.esp / "FILENOTFOUND"
|
||||||
|
|
||||||
# change to source directory
|
# change to source directory
|
||||||
os.chdir(kernel.src)
|
os.chdir(kernel.src)
|
||||||
@ -391,6 +415,9 @@ def install (argv):
|
|||||||
Command Line Arguments
|
Command Line Arguments
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
``-b``
|
||||||
|
create fallback boot entry (default: false)
|
||||||
|
|
||||||
``-s <src>``
|
``-s <src>``
|
||||||
kernel source directory (default: latest)
|
kernel source directory (default: latest)
|
||||||
|
|
||||||
@ -417,6 +444,12 @@ def install (argv):
|
|||||||
description="Install a kernel.",
|
description="Install a kernel.",
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter
|
formatter_class=argparse.RawDescriptionHelpFormatter
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-b",
|
||||||
|
dest="bkp",
|
||||||
|
action="store_true",
|
||||||
|
help="create fallback boot entry"
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-s",
|
"-s",
|
||||||
metavar="<src>",
|
metavar="<src>",
|
||||||
@ -439,6 +472,50 @@ def install (argv):
|
|||||||
if not kernel.bzImage.exists():
|
if not kernel.bzImage.exists():
|
||||||
raise FileNotFoundError(f"missing bzImage {kernel.bzImage}")
|
raise FileNotFoundError(f"missing bzImage {kernel.bzImage}")
|
||||||
|
|
||||||
|
# create backup boot entry
|
||||||
|
if args.bkp:
|
||||||
|
# path to backup image
|
||||||
|
bkp = None
|
||||||
|
# find the currently running kernel's backup image
|
||||||
|
boot_bytes = efi.boot.read_bytes()
|
||||||
|
for f in efi.boot.parent.glob("gentoo*.efi"):
|
||||||
|
if f.read_bytes() == boot_bytes:
|
||||||
|
bkp = f
|
||||||
|
break
|
||||||
|
# not found
|
||||||
|
else:
|
||||||
|
name = f"gentoo-{version(platform.release()).base_version}.efi"
|
||||||
|
bkp = efi.boot.parent / name
|
||||||
|
shutil.copy(efi.boot, bkp)
|
||||||
|
# get ESP disk and partition number
|
||||||
|
dev = subprocess.run(
|
||||||
|
["findmnt", "-rno", "SOURCE", str(efi.esp)],
|
||||||
|
capture_output=True,
|
||||||
|
check=True
|
||||||
|
)
|
||||||
|
disk, part = filter(
|
||||||
|
None,
|
||||||
|
re.search(r"([/a-z]+)(\d+)", dev.stdout.decode()).groups()
|
||||||
|
)
|
||||||
|
# remove previous entry
|
||||||
|
if "bootnum" in efi.bkp:
|
||||||
|
subprocess.run([
|
||||||
|
"efibootmgr",
|
||||||
|
"-q",
|
||||||
|
"-b", efi.bkp["bootnum"],
|
||||||
|
"-B"
|
||||||
|
], check=True)
|
||||||
|
# create entry
|
||||||
|
subprocess.run([
|
||||||
|
"efibootmgr",
|
||||||
|
"-q",
|
||||||
|
"-c",
|
||||||
|
"-d", disk,
|
||||||
|
"-p", part,
|
||||||
|
"-L", efi.bkp["label"],
|
||||||
|
"-l", str(bkp)
|
||||||
|
], check=True)
|
||||||
|
|
||||||
# update symlink to the new source directory
|
# update symlink to the new source directory
|
||||||
out.einfo(
|
out.einfo(
|
||||||
"updating symlink "
|
"updating symlink "
|
||||||
@ -450,8 +527,8 @@ def install (argv):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# copy boot image
|
# copy boot image
|
||||||
out.einfo(f"creating boot image {out.hilite(kernel.boot)}")
|
out.einfo(f"creating boot image {out.hilite(efi.boot)}")
|
||||||
shutil.copy(kernel.bzImage, kernel.boot)
|
shutil.copy(kernel.bzImage, efi.boot)
|
||||||
|
|
||||||
# create backup
|
# create backup
|
||||||
out.einfo(f"creating backup image {out.hilite(kernel.bkp)}")
|
out.einfo(f"creating backup image {out.hilite(kernel.bkp)}")
|
||||||
@ -530,7 +607,7 @@ def clean (argv):
|
|||||||
if leftovers:
|
if leftovers:
|
||||||
out.einfo("the following kernels will be removed:")
|
out.einfo("the following kernels will be removed:")
|
||||||
for k in leftovers:
|
for k in leftovers:
|
||||||
print(f" {colorize('BAD', '✗')} {k.src.name}")
|
out.print(f" {colorize('BAD', '✗')} {k.src.name}")
|
||||||
else:
|
else:
|
||||||
out.einfo("nothing to see here")
|
out.einfo("nothing to see here")
|
||||||
return
|
return
|
||||||
@ -793,6 +870,12 @@ def update (argv):
|
|||||||
type=pathlib.Path,
|
type=pathlib.Path,
|
||||||
help="kernel source directory (default: latest)"
|
help="kernel source directory (default: latest)"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-b",
|
||||||
|
dest="bkp",
|
||||||
|
action="store_true",
|
||||||
|
help="create fallback boot entry"
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-k",
|
"-k",
|
||||||
metavar="<keep>",
|
metavar="<keep>",
|
||||||
@ -816,12 +899,13 @@ 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.src = ["-s", str(args.src)] if args.src else []
|
args.src = ["-s", str(args.src)] if args.src else []
|
||||||
|
args.bkp = ["-b"] if args.bkp 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 []
|
||||||
args.quiet = ["-q"] if args.quiet else []
|
args.quiet = ["-q"] if args.quiet else []
|
||||||
|
|
||||||
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.src)
|
install(args.quiet + args.bkp + args.src)
|
||||||
clean(args.quiet + args.keep)
|
clean(args.quiet + args.keep)
|
||||||
commit(args.quiet + args.msg)
|
commit(args.quiet + args.msg)
|
||||||
|
@ -5,7 +5,7 @@ import shutil
|
|||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from ekernel import Kernel
|
import ekernel
|
||||||
|
|
||||||
# create temporary directory
|
# create temporary directory
|
||||||
tmpdir = tempfile.TemporaryDirectory()
|
tmpdir = tempfile.TemporaryDirectory()
|
||||||
@ -74,18 +74,20 @@ def efi (f):
|
|||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def runner (t, *args, **kwargs):
|
def runner (t, *args, **kwargs):
|
||||||
if args[0][0] == "efibootmgr":
|
if args[0][0] == "efibootmgr":
|
||||||
boot.touch()
|
|
||||||
return subprocess.CompletedProcess("", 0,
|
return subprocess.CompletedProcess("", 0,
|
||||||
"BootCurrent: 0001\n"
|
"BootCurrent: 0001\n"
|
||||||
"Timeout: 1 seconds\n"
|
"Timeout: 1 seconds\n"
|
||||||
"BootOrder: 0001,0000\n"
|
"BootOrder: 0001,0000\n"
|
||||||
"Boot0000* Windows HD()/File()\n"
|
"Boot0000* Windows\tHD()/File()\n"
|
||||||
"Boot0001* Gentoo HD()/File(\\EFI\\gentoo\\bootx64.efi)\n"
|
"Boot0001* Gentoo\tHD()/File(\\EFI\\Gentoo\\bootx64.efi)\n"
|
||||||
|
"Boot0002* Gentoo (ignore)\tHD()/File()\n"
|
||||||
|
"Boot0003* Gentoo (fallback)\tHD()/File()\n"
|
||||||
.encode()
|
.encode()
|
||||||
)
|
)
|
||||||
elif args[0][0] == "mount":
|
elif args[0][0] == "mount":
|
||||||
Kernel.esp = esp
|
ekernel.efi.esp = esp
|
||||||
Kernel.boot = boot
|
ekernel.efi.boot = boot
|
||||||
|
boot.write_bytes(str(kernels[1].bkp).encode())
|
||||||
return f(t, *args, **kwargs)
|
return f(t, *args, **kwargs)
|
||||||
return runner
|
return runner
|
||||||
|
|
||||||
@ -96,11 +98,13 @@ def setup ():
|
|||||||
shutil.rmtree(p)
|
shutil.rmtree(p)
|
||||||
|
|
||||||
# change Kernel paths
|
# change Kernel paths
|
||||||
Kernel.src = src
|
ekernel.Kernel.src = src
|
||||||
Kernel.linux = linux
|
ekernel.Kernel.linux = linux
|
||||||
Kernel.modules = modules
|
ekernel.Kernel.modules = modules
|
||||||
Kernel.esp = esp
|
|
||||||
Kernel.boot = boot
|
# change EFI paths
|
||||||
|
ekernel.efi.esp = esp
|
||||||
|
ekernel.efi.boot = boot
|
||||||
|
|
||||||
# create EFI system partition
|
# create EFI system partition
|
||||||
boot.parent.mkdir(parents=True)
|
boot.parent.mkdir(parents=True)
|
||||||
@ -108,7 +112,7 @@ def setup ():
|
|||||||
# create Kernels
|
# create Kernels
|
||||||
for s in sources: s.mkdir(parents=True)
|
for s in sources: s.mkdir(parents=True)
|
||||||
global kernels
|
global kernels
|
||||||
kernels = [ Kernel(s) for s in sources ]
|
kernels = [ ekernel.Kernel(s) for s in sources ]
|
||||||
|
|
||||||
# create config and build files, expect for the latest
|
# create config and build files, expect for the latest
|
||||||
for k in kernels:
|
for k in kernels:
|
||||||
@ -119,7 +123,7 @@ def setup ():
|
|||||||
else:
|
else:
|
||||||
k.config.touch()
|
k.config.touch()
|
||||||
k.bzImage.touch()
|
k.bzImage.touch()
|
||||||
k.bkp.touch()
|
k.bkp.write_bytes(str(k.bkp).encode())
|
||||||
k.modules.mkdir(parents=True)
|
k.modules.mkdir(parents=True)
|
||||||
|
|
||||||
# symlink to old source directory
|
# symlink to old source directory
|
||||||
|
@ -26,7 +26,7 @@ class Tests (unittest.TestCase):
|
|||||||
if args[0][0] == "make":
|
if args[0][0] == "make":
|
||||||
if args[0][1] == "listnewconfig":
|
if args[0][1] == "listnewconfig":
|
||||||
make = subprocess.CompletedProcess("", 0)
|
make = subprocess.CompletedProcess("", 0)
|
||||||
make.stdout = str.encode(data.newoptions)
|
make.stdout = data.newoptions.encode()
|
||||||
return make
|
return make
|
||||||
elif args[0][1] == "menuconfig":
|
elif args[0][1] == "menuconfig":
|
||||||
self.kernel.config.touch()
|
self.kernel.config.touch()
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import platform
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
@ -18,32 +19,66 @@ class Tests (unittest.TestCase):
|
|||||||
data.setup()
|
data.setup()
|
||||||
self.kernel = Kernel.latest()
|
self.kernel = Kernel.latest()
|
||||||
self.kernel.bzImage.touch()
|
self.kernel.bzImage.touch()
|
||||||
|
self.current = Kernel.current()
|
||||||
# start interceptor
|
# start interceptor
|
||||||
@data.efi
|
@data.efi
|
||||||
def run (tracer, *args, **kwargs):
|
def run (tracer, *args, **kwargs):
|
||||||
if args[0][0] == "eselect":
|
if args[0][0] == "findmnt":
|
||||||
|
return subprocess.CompletedProcess("", 0, b"/dev/sda1")
|
||||||
|
elif 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)
|
||||||
|
def release (tracer, *args, **kwargs):
|
||||||
|
return f"{self.current.version.base_version}-gentoo"
|
||||||
self.interceptor = Interceptor()
|
self.interceptor = Interceptor()
|
||||||
self.interceptor.add(subprocess.run, call=run)
|
self.interceptor.add(subprocess.run, call=run)
|
||||||
|
self.interceptor.add(platform.release, call=release)
|
||||||
self.interceptor.start()
|
self.interceptor.start()
|
||||||
|
|
||||||
def tearDown (self):
|
def tearDown (self):
|
||||||
# stop interceptor
|
# stop interceptor
|
||||||
self.interceptor.stop()
|
self.interceptor.stop()
|
||||||
|
|
||||||
def check_install (self):
|
def check_install (self, backup=False):
|
||||||
trace_it = iter(self.interceptor.trace)
|
trace_it = iter(self.interceptor.trace)
|
||||||
# efibootmgr
|
# efibootmgr
|
||||||
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, (["efibootmgr"],))
|
self.assertEqual(args, (["efibootmgr"],))
|
||||||
self.assertEqual(kwargs, {"capture_output": True, "check": True})
|
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", "/boot"],))
|
self.assertEqual(args, (["mount", "/boot"],))
|
||||||
self.assertEqual(kwargs, {"capture_output": True, "check": True})
|
self.assertEqual(kwargs, {"capture_output": True, "check": True})
|
||||||
|
if backup:
|
||||||
|
if data.boot.read_bytes() == b"missing image":
|
||||||
|
# platform.release
|
||||||
|
tracer, (args, kwargs) = next(trace_it)
|
||||||
|
self.assertEqual(tracer.name, "platform.release")
|
||||||
|
# findmnt -rno SOURCE <boot>
|
||||||
|
tracer, (args, kwargs) = next(trace_it)
|
||||||
|
self.assertEqual(tracer.name, "subprocess.run")
|
||||||
|
self.assertEqual(args, (["findmnt", "-rno", "SOURCE", "/tmp"],))
|
||||||
|
self.assertEqual(kwargs, {"capture_output": True, "check": True})
|
||||||
|
# efibootmgr -b 0003 -B
|
||||||
|
tracer, (args, kwargs) = next(trace_it)
|
||||||
|
self.assertEqual(tracer.name, "subprocess.run")
|
||||||
|
self.assertEqual(args, (["efibootmgr", "-q", "-b", "0003", "-B"],))
|
||||||
|
self.assertEqual(kwargs, {"check": True})
|
||||||
|
# efibootmgr -c -d <disk> -p <part> -L <label> -l <loader>
|
||||||
|
tracer, (args, kwargs) = next(trace_it)
|
||||||
|
self.assertEqual(tracer.name, "subprocess.run")
|
||||||
|
self.assertEqual(args, ([
|
||||||
|
"efibootmgr",
|
||||||
|
"-q",
|
||||||
|
"-c",
|
||||||
|
"-d", "/dev/sda",
|
||||||
|
"-p", "1",
|
||||||
|
"-L", "Gentoo (fallback)",
|
||||||
|
"-l", str(self.current.bkp)
|
||||||
|
],))
|
||||||
|
self.assertEqual(kwargs, {"check": True})
|
||||||
# eselect kernel set <name>
|
# eselect kernel set <name>
|
||||||
tracer, (args, kwargs) = next(trace_it)
|
tracer, (args, kwargs) = next(trace_it)
|
||||||
self.assertEqual(tracer.name, "subprocess.run")
|
self.assertEqual(tracer.name, "subprocess.run")
|
||||||
@ -58,13 +93,13 @@ 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
|
# 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")
|
||||||
self.assertEqual(args, (["umount", "/tmp"],))
|
self.assertEqual(args, (["umount", "/tmp"],))
|
||||||
self.assertEqual(kwargs, {"check": True})
|
self.assertEqual(kwargs, {"check": True})
|
||||||
# check generated files
|
# check generated files
|
||||||
self.assertTrue(self.kernel.boot.exists())
|
self.assertTrue(ekernel.efi.boot.exists())
|
||||||
self.assertTrue(self.kernel.bkp.exists())
|
self.assertTrue(self.kernel.bkp.exists())
|
||||||
|
|
||||||
def test_install (self):
|
def test_install (self):
|
||||||
@ -76,6 +111,17 @@ class Tests (unittest.TestCase):
|
|||||||
self.assertEqual(run("-q", "-s", str(data.current)), 0)
|
self.assertEqual(run("-q", "-s", str(data.current)), 0)
|
||||||
self.check_install()
|
self.check_install()
|
||||||
|
|
||||||
|
def test_install_backup (self):
|
||||||
|
self.assertEqual(run("-q", "-b"), 0)
|
||||||
|
self.check_install(backup=True)
|
||||||
|
|
||||||
|
def test_install_backup_missing_image (self):
|
||||||
|
self.current.bkp.unlink()
|
||||||
|
self.kernel.bzImage.write_bytes(b"missing image")
|
||||||
|
self.assertEqual(run("-q", "-b"), 0)
|
||||||
|
self.check_install(backup=True)
|
||||||
|
self.assertTrue(self.current.bkp.exists())
|
||||||
|
|
||||||
@capture_stderr
|
@capture_stderr
|
||||||
def test_install_missing_bzImage (self):
|
def test_install_missing_bzImage (self):
|
||||||
self.kernel.bzImage.unlink()
|
self.kernel.bzImage.unlink()
|
||||||
|
@ -28,8 +28,6 @@ class Tests (unittest.TestCase):
|
|||||||
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.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):
|
||||||
|
@ -32,7 +32,7 @@ class Tests (unittest.TestCase):
|
|||||||
if args[0][0] == "make":
|
if args[0][0] == "make":
|
||||||
if args[0][1] == "listnewconfig":
|
if args[0][1] == "listnewconfig":
|
||||||
make = subprocess.CompletedProcess("", 0)
|
make = subprocess.CompletedProcess("", 0)
|
||||||
make.stdout = str.encode(data.newoptions)
|
make.stdout = data.newoptions.encode()
|
||||||
return make
|
return make
|
||||||
elif args[0][1] == "oldconfig":
|
elif args[0][1] == "oldconfig":
|
||||||
self.latest.config.write_text(data.newconfig)
|
self.latest.config.write_text(data.newconfig)
|
||||||
@ -53,7 +53,7 @@ class Tests (unittest.TestCase):
|
|||||||
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.boot.exists())
|
self.assertTrue(ekernel.efi.boot.exists())
|
||||||
self.assertTrue(self.latest.bkp.exists())
|
self.assertTrue(self.latest.bkp.exists())
|
||||||
# clean
|
# clean
|
||||||
for k in data.kernels[2:]:
|
for k in data.kernels[2:]:
|
||||||
|
Loading…
Reference in New Issue
Block a user