Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c36c0e8
usbguard: Fix default permissions on rules file
hunger Jun 6, 2020
d692c66
Firestarter: Add efi-options and efi-fs-type to install_partition
hunger Jun 12, 2020
0ecc1be
Firestarter: Use mounted borg image when possible
hunger Jun 12, 2020
8610941
Firestarter: Remove some dead code
hunger Jun 14, 2020
6348262
Firestarter: Add partitioner
hunger Jun 22, 2020
c8e17dc
Firestarter: Add qemu-image install target
hunger Jun 24, 2020
34b4d8e
new command to install nvidia drivers
phunni Jul 13, 2020
e42df7f
Small fixes for various warnings found by python linters
hunger Jul 13, 2020
8f47d27
Clrm: Add ensure_depmod command
hunger Jul 13, 2020
9294405
Clrm: pkg_nvidia_gpu: Formatting/typo fixes
hunger Jul 13, 2020
7e0fd9e
Fix broken rebase
hunger Jul 15, 2020
88f4dd4
Clrm: Sort keys in binarymanager
hunger Jul 15, 2020
dcff1ba
fixed typo in the nouveau blacklist
phunni Jul 17, 2020
d160826
Fix pylance warnings
hunger Jul 20, 2020
49fb92d
Clrm: Have a pretty system name available as property on SystemContext
hunger Jul 22, 2020
21ba6f3
Clrm: Change the name of the exported image and kernel file
hunger Jul 22, 2020
c014f1b
Clrm: Remove TPM support from initrd
hunger Jul 24, 2020
1ac5fb2
Clrm: Allow for the exact same substitutions several times
hunger Jul 24, 2020
1ac3035
Examples: Fix system-example.def
hunger Aug 30, 2020
3bb6dca
clrm: Add Binaries.FIND
hunger Aug 30, 2020
fa78cc3
clrm: Change way helper directories for commands are handled
hunger Aug 30, 2020
a4e2f2e
clrm: More debug output in create_efi_kernel
hunger Aug 30, 2020
bd63baa
clrm: Handle missing working directory in file helper
hunger Sep 5, 2020
f4d94f5
clrm: Create an extra initrd with the CLRM-specific logic
hunger Aug 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 47 additions & 37 deletions cleanroom/binarymanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,36 @@
class Binaries(Enum):
"""Important binaries."""

APT_GET = auto()
BORG = auto()
BTRFS = auto()
MKNOD = auto()
PACMAN = auto()
PACMAN_KEY = auto()
APT_GET = auto()
DPKG = auto()
CHROOT_HELPER = auto()
CPIO = auto()
DEBOOTSTRAP = auto()
SBSIGN = auto()
OBJCOPY = auto()
MKSQUASHFS = auto()
VERITYSETUP = auto()
TAR = auto()
USERMOD = auto()
USERADD = auto()
DEPMOD = auto()
DPKG = auto()
FIND = auto()
FLOCK = auto()
GROUPADD = auto()
GROUPMOD = auto()
CHROOT_HELPER = auto()
SYSTEMCTL = auto()
SFDISK = auto()
FLOCK = auto()
MKFS_VFAT = auto()
MKNOD = auto()
MKSQUASHFS = auto()
MODPROBE = auto()
NBD_CLIENT = auto()
OBJCOPY = auto()
PACMAN = auto()
PACMAN_KEY = auto()
QEMU_IMG = auto()
QEMU_NBD = auto()
NBD_CLIENT = auto()
MKFS_VFAT = auto()
SBSIGN = auto()
SFDISK = auto()
SYNC = auto()
MODPROBE = auto()
SYSTEMCTL = auto()
TAR = auto()
USERADD = auto()
USERMOD = auto()
VERITYSETUP = auto()


def _check_for_binary(binary: str) -> str:
Expand All @@ -67,40 +70,43 @@ def _find_binaries() -> typing.Dict[Binaries, str]:
binaries = {
Binaries.BORG: _check_for_binary("/usr/bin/borg"),
Binaries.BTRFS: _check_for_binary("/usr/bin/btrfs"),
Binaries.SBSIGN: _check_for_binary("/usr/bin/sbsign"),
Binaries.OBJCOPY: _check_for_binary("/usr/bin/objcopy"),
Binaries.MKNOD: _check_for_binary("/usr/bin/mknod"),
Binaries.MKSQUASHFS: _check_for_binary("/usr/bin/mksquashfs"),
Binaries.TAR: _check_for_binary("/usr/bin/tar"),
Binaries.USERMOD: _check_for_binary("/usr/sbin/usermod"),
Binaries.USERADD: _check_for_binary("/usr/sbin/useradd"),
Binaries.GROUPMOD: _check_for_binary("/usr/sbin/groupmod"),
Binaries.GROUPADD: _check_for_binary("/usr/sbin/groupadd"),
Binaries.CHROOT_HELPER: _check_for_binary("/usr/bin/arch-chroot"),
Binaries.SYSTEMCTL: _check_for_binary("/usr/bin/systemctl"),
Binaries.CPIO: _check_for_binary("/usr/bin/cpio"),
Binaries.DEPMOD: _check_for_binary("/usr/bin/depmod"),
Binaries.FIND: _check_for_binary("/usr/bin/find"),
Binaries.FLOCK: _check_for_binary("/usr/bin/flock"),
Binaries.SFDISK: _check_for_binary("/usr/bin/sfdisk"),
Binaries.GROUPADD: _check_for_binary("/usr/sbin/groupadd"),
Binaries.GROUPMOD: _check_for_binary("/usr/sbin/groupmod"),
Binaries.MKFS_VFAT: _check_for_binary("/usr/bin/mkfs.vfat"),
Binaries.MKNOD: _check_for_binary("/usr/bin/mknod"),
Binaries.MKSQUASHFS: _check_for_binary("/usr/bin/mksquashfs"),
Binaries.MODPROBE: _check_for_binary("/usr/bin/modprobe"),
Binaries.NBD_CLIENT: _check_for_binary("/usr/bin/nbd-client"),
Binaries.OBJCOPY: _check_for_binary("/usr/bin/objcopy"),
Binaries.QEMU_IMG: _check_for_binary("/usr/bin/qemu-img"),
Binaries.QEMU_NBD: _check_for_binary("/usr/bin/qemu-nbd"),
Binaries.NBD_CLIENT: _check_for_binary("/usr/bin/nbd-client"),
Binaries.MKFS_VFAT: _check_for_binary("/usr/bin/mkfs.vfat"),
Binaries.SBSIGN: _check_for_binary("/usr/bin/sbsign"),
Binaries.SFDISK: _check_for_binary("/usr/bin/sfdisk"),
Binaries.SYNC: _check_for_binary("/usr/bin/sync"),
Binaries.MODPROBE: _check_for_binary("/usr/bin/modprobe"),
Binaries.SYSTEMCTL: _check_for_binary("/usr/bin/systemctl"),
Binaries.TAR: _check_for_binary("/usr/bin/tar"),
Binaries.USERADD: _check_for_binary("/usr/sbin/useradd"),
Binaries.USERMOD: _check_for_binary("/usr/sbin/usermod"),
}
os_binaries: typing.Dict[Binaries, str] = {}
distribution = _get_distribution()
debug("Distribution: {}".format(distribution))
if distribution == "debian":
os_binaries = {
Binaries.APT_GET: _check_for_binary("/usr/bin/apt-get"),
Binaries.DPKG: _check_for_binary("/usr/bin/dpkg"),
Binaries.DEBOOTSTRAP: _check_for_binary("/usr/sbin/debootstrap"),
Binaries.DPKG: _check_for_binary("/usr/bin/dpkg"),
Binaries.VERITYSETUP: _check_for_binary("/usr/sbin/veritysetup"),
}
elif distribution == "arch" or distribution == "archlinux":
os_binaries = {
Binaries.PACMAN: _check_for_binary("/usr/bin/pacman"),
Binaries.PACMAN_KEY: _check_for_binary("/usr/bin/pacman-key"),
Binaries.PACMAN: _check_for_binary("/usr/bin/pacman"),
Binaries.VERITYSETUP: _check_for_binary("/usr/bin/veritysetup"),
}
else:
Expand All @@ -116,15 +122,19 @@ class BinaryManager:
def __init__(self) -> None:
"""Constructor."""
self._binaries = _find_binaries()
self._optionals: typing.List[Binaries] = []

def preflight_check(self) -> None:
passed = True
for b in self._binaries.items():
if b[1]:
debug("{} found: {}...".format(b[0], b[1]))
else:
warn("{} not found.".format(b[0]))
passed = False
if b in self._optionals:
debug("[OPTIONAL] {} not found, ignoring.")
else:
warn("{} not found.".format(b[0]))
passed = False
if not passed:
raise PreflightError("Required binaries are not available.")

Expand Down
27 changes: 16 additions & 11 deletions cleanroom/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from .exceptions import GenerateError, ParseError
from .execobject import ExecObject
from .location import Location
from .printer import fail, h3, success, verbose
from .printer import debug, fail, h3, success, verbose
from .systemcontext import SystemContext

import os
Expand Down Expand Up @@ -47,18 +47,23 @@ def __init__(
file: str,
syntax: str = "",
help_string: str,
**services: typing.Any
**services: typing.Any,
) -> None:
"""Constructor."""
self._name = name
self._syntax_string = syntax
self._help_string = help_string
helper_directory = os.path.join(
os.path.dirname(os.path.realpath(file)), "helper", self._name
os.path.dirname(os.path.realpath(file)), os.path.basename(file)[:-3],
)
self.__helper_directory = (
helper_directory if os.path.isdir(helper_directory) else None
)
if self.__helper_directory is None:
debug(f"Checked {helper_directory} for helpers for command {name}: NONE")
else:
debug(f"Checked {helper_directory} for helpers for command {name}: FOUND")

self._services = services

@property
Expand Down Expand Up @@ -103,7 +108,7 @@ def __call__(
location: Location,
system_context: SystemContext,
*args: typing.Any,
**kwargs: typing.Any
**kwargs: typing.Any,
) -> None:
"""Implement this!

Expand All @@ -117,7 +122,7 @@ def _execute(
system_context: SystemContext,
command: str,
*args: typing.Any,
**kwargs: typing.Any
**kwargs: typing.Any,
) -> None:
command_info = self._service("command_manager").command(command)
if not command_info:
Expand All @@ -132,7 +137,7 @@ def _add_hook(
hook_name: str,
command: str,
*args: typing.Any,
**kwargs: typing.Any
**kwargs: typing.Any,
) -> None:
"""Add a hook."""
command_info = self._service("command_manager").command(command)
Expand Down Expand Up @@ -170,7 +175,7 @@ def _helper_directory(self) -> typing.Optional[str]:
"""Return the helper directory."""
return self.__helper_directory

def _config_directory(self, system_context) -> str:
def _config_directory(self, system_context: SystemContext) -> str:
return os.path.join(
system_context.systems_definition_directory, "config", self.name
)
Expand All @@ -188,7 +193,7 @@ def _validate_arguments_exact(
arg_count: int,
message: str,
*args: typing.Any,
**kwargs: typing.Any
**kwargs: typing.Any,
) -> None:
self._validate_args_exact(location, arg_count, message, *args)
self._validate_kwargs(location, (), **kwargs)
Expand All @@ -199,7 +204,7 @@ def _validate_arguments_at_least(
arg_count: int,
message: str,
*args: typing.Any,
**kwargs: typing.Any
**kwargs: typing.Any,
) -> None:
self._validate_args_at_least(location, arg_count, message, *args)
self._validate_kwargs(location, (), **kwargs)
Expand All @@ -223,7 +228,7 @@ def _validate_kwargs(
self,
location: Location,
known_kwargs: typing.Tuple[str, ...],
**kwargs: typing.Any
**kwargs: typing.Any,
) -> None:
if not known_kwargs:
if kwargs:
Expand All @@ -244,7 +249,7 @@ def _require_kwargs(
self,
location: Location,
required_kwargs: typing.Tuple[str, ...],
**kwargs: typing.Any
**kwargs: typing.Any,
) -> None:
for key in required_kwargs:
if key not in kwargs:
Expand Down
83 changes: 53 additions & 30 deletions cleanroom/commandmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,58 @@
from .command import Command, stringify
from .exceptions import PreflightError
from .location import Location
from .printer import debug, error, h2, success, trace
from .systemcontext import SystemContext, _recursive_expand
from .printer import debug, h2, success, trace
from .systemcontext import SystemContext

import collections
import importlib.util
import inspect
import os
import re
import typing


CommandInfo = collections.namedtuple(
"CommandInfo",
[
"name",
"syntax_string",
"help_string",
"file_name",
"dependency_func",
"validate_func",
"execute_func",
"register_substitutions",
],
)
class CommandInfo(typing.NamedTuple):
name: str
syntax_string: str
help_string: str
file_name: str
dependency_func: typing.Callable[
[typing.Tuple[typing.Any, ...], typing.Dict[str, typing.Any]],
typing.Optional[str],
]
validate_func: typing.Callable[
[Location, typing.Tuple[typing.Any, ...], typing.Dict[str, typing.Any],], None,
]
execute_func: typing.Callable[
[
Location,
SystemContext,
typing.Tuple[typing.Any, ...],
typing.Dict[str, typing.Any],
],
None,
]
register_substitutions: typing.Callable[
[], typing.List[typing.Tuple[str, str, str]]
]


def _process_args(system_context: SystemContext, *args: typing.Any) -> typing.Any:
return tuple(map(lambda a: _recursive_expand(system_context, a), args))
return tuple(map(lambda a: system_context.expand(a), args))


def _process_kwargs(
system_context: SystemContext, **kwargs: typing.Any
) -> typing.Dict[str, typing.Any]:
return {k: _recursive_expand(system_context, v) for k, v in kwargs.items()}
return {k: system_context.expand(v) for k, v in kwargs.items()}


def call_command(
location: Location,
system_context: SystemContext,
command: Command,
*args: typing.Any,
**kwargs: typing.Dict[str, typing.Any]
**kwargs: typing.Any
):
_args = _process_args(system_context, *args)
_kwargs = _process_kwargs(system_context, **kwargs)
Expand Down Expand Up @@ -82,20 +92,33 @@ def print_commands(self) -> None:
)
)

def _collect_substitutions(self) -> typing.List[typing.Tuple[str, str, str, str]]:
result: typing.List[typing.Tuple[str, str, str, str]] = []
duplications: typing.Dict[str, str] = {}
def _collect_substitutions(
self,
) -> typing.List[typing.Tuple[str, str, str, typing.Tuple[str, ...]]]:
result: typing.Dict[
str, typing.Tuple[str, str, str, typing.Tuple[str, ...]]
] = {}

for cmd in self._commands.keys():
command_info = self.command(cmd)
assert command_info

name = command_info.name
for (key, value, description) in command_info.register_substitutions():
result.append((key, value, description, name))
assert not key in duplications
duplications[key] = name

return result
if not key in result:
result[key] = (key, value, description, (name,))
else:
(old_key, old_value, old_description, old_names) = result[key]
assert (
old_key == key
and old_value == value
and old_description == description
and not name in old_names
and old_names
)
result[key] = (key, value, description, (*old_names, name))

return [v for v in result.values()]

def print_substitutions(self) -> None:
h2("Predefined Substitutions:")
Expand All @@ -117,10 +140,10 @@ def print_substitutions(self) -> None:
print(' {} ("{}"): {}\n {}\n'.format(key, value, name, description))

def setup_substitutions(self, system_context: SystemContext):
if system_context._base_context:
if system_context.base_context:
debug(
'System Context inherited, using substitutions from "{}".'.format(
system_context._base_context.system_name
system_context.base_context.system_name
)
)
return
Expand Down Expand Up @@ -216,7 +239,7 @@ def _find_commands_in_directory(self, directory: str) -> None:
assert spec and spec.loader
spec.loader.exec_module(cmd_module)

def is_command(x):
def is_command(x: typing.Any) -> bool:
return (
inspect.isclass(x)
and x.__name__.endswith("Command")
Expand Down
Loading