Skip to content

Commit 2171ca3

Browse files
committed
added functions to be imported into the init source, improved docs
Signed-off-by: Zen <[email protected]>
1 parent 8afdb7e commit 2171ca3

File tree

6 files changed

+75
-39
lines changed

6 files changed

+75
-39
lines changed

readme.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,14 @@ This module is loaded in the imports section of the `base.yaml` file:
469469
"ugrd.fs.mounts" = [ "_process_mounts_multi" ]
470470
```
471471

472-
#### build_tasks
472+
#### Imports
473+
474+
UGRD allows functions to be imported from modules using the `imports` dict.
475+
476+
This is primarily used to run additional functions at build time, add init functions, and add library functions.
477+
478+
479+
##### build_tasks
473480

474481
Build tasks are functions which will be executed after the directory structure has been generated using the specified `paths`.
475482

@@ -480,7 +487,7 @@ The base module includes a build task for generating the fstab, which is activat
480487
"ugrd.fs.mounts" = [ "generate_fstab" ]
481488
```
482489

483-
#### Packing tasks
490+
##### pack
484491

485492
Packing facts, such as CPIO generation can be defined in the `pack` import.
486493

@@ -491,7 +498,11 @@ The `cpio` module imports the `make_cpio_list` packing function with:
491498
"ugrd.base.base" = [ "make_cpio_list" ]
492499
```
493500

494-
#### init hooks
501+
##### funcs
502+
503+
Functions can be added to `imports.funcs` to force the output to be added to `init_funcs.sh`.
504+
505+
##### init hooks
495506

496507
By default, the specified init hooks are:
497508
* `init_pre` - Where the base initramfs environment is set up, such as creating a devtmpfs.
@@ -514,7 +525,7 @@ The `InitramfsGenerator.generate_init_main()` function (often called from `self`
514525

515526
A general overview of the procedure used for generating the init is to write the chosen `shebang`, then every init hook. The `custom_init` import can be used for more advanced confugrations, such as running another script in `agetty`.
516527

517-
#### custom_init
528+
##### custom_init
518529

519530
To change how everything but `init_pre` and `init_file` are handled at runtime, `custom_init` can be used.
520531

ugrd/crypto/cryptsetup.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
__author__ = 'desultory'
2-
__version__ = '1.0.1'
2+
__version__ = '1.1.0'
33

44
_module_name = 'ugrd.crypto.cryptsetup'
55

@@ -97,10 +97,15 @@ def get_crypt_sources(self) -> list[str]:
9797
parameters['_host_device_path'] = _get_device_path_from_token(self, token)
9898
# Add a blkid command to get the source device in the initramfs, only match if the device has a partuuid
9999
out.append(f"export SOURCE_TOKEN_{name}='{token[0]}={token[1]}'")
100-
out.append(f'export CRYPTSETUP_SOURCE_{name}=$(blkid --match-token "$SOURCE_TOKEN_{name}" --match-tag PARTUUID --output device)')
101-
102-
check_command = f'if [ -z "$CRYPTSETUP_SOURCE_{name}" ]; then echo "Unable to resolve device source for {name}"; bash; else echo "Resolved device source: $CRYPTSETUP_SOURCE_{name}"; fi\n'
103-
out += [f"echo 'Attempting to get device path for {name}'", check_command]
100+
source_cmd = f'export CRYPTSETUP_SOURCE_{name}=$(blkid --match-token "$SOURCE_TOKEN_{name}" --match-tag PARTUUID --output device)'
101+
102+
check_command = [f'if [ -z "$CRYPTSETUP_SOURCE_{name}" ]; then',
103+
f' echo "Unable to resolve device source for {name}"',
104+
' bash',
105+
'else',
106+
f' echo "Resolved device source: $CRYPTSETUP_SOURCE_{name}"',
107+
'fi']
108+
out += [f"echo 'Attempting to get device path for {name}'", source_cmd, *check_command]
104109

105110
return out
106111

ugrd/fs/btrfs.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = '0.1.0'
1+
__version__ = '0.2.0'
22
__author__ = 'desultory'
33

44

@@ -23,23 +23,18 @@ def btrfs_scan(self) -> str:
2323
return "btrfs device scan"
2424

2525

26-
def _get_devices(self) -> str:
26+
def get_btrfs_devices(self) -> str:
2727
"""
2828
Returns a bash function which uses blkid to get all btrfs devices
2929
"""
30-
return """
31-
function get_btrfs_devices() {{
32-
blkid -t TYPE=btrfs -o device
33-
}}
34-
"""
30+
return "blkid -t TYPE=btrfs -o device"
3531

3632

3733
def select_subvol(self) -> str:
3834
"""
3935
selects a subvolume
4036
"""
41-
out = [_get_devices(self)]
42-
37+
out = []
4338
if root_subvol := self.config_dict.get("root_subvol"):
4439
out.append(f"btrfs subvolume set-default {root_subvol}")
4540

ugrd/fs/btrfs.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ _kmod_depend = [ "btrfs" ]
33

44
subvol_selector = false
55

6+
[imports.functions]
7+
"ugrd.fs.btrfs" = [ "get_btrfs_devices" ]
8+
69
[imports.config_processing]
710
"ugrd.fs.btrfs" = [ "_process_root_subvol" ]
811

ugrd/initramfs_dict.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
__author__ = "desultory"
3-
__version__ = "0.9.0"
3+
__version__ = "0.10.0"
44

55
from tomllib import load, TOMLDecodeError
66
from pathlib import Path
@@ -123,6 +123,11 @@ def _process_imports(self, import_type: str, import_value: dict) -> None:
123123
self['custom_processing'][function.__name__] = function
124124
self.logger.debug("Registered config processing function: %s" % function.__name__)
125125

126+
if import_type == 'funcs':
127+
for function in function_list:
128+
if function.__name__ in self['imports']['funcs']:
129+
raise ValueError("Function '%s' already registered" % function.__name__)
130+
126131
@handle_plural
127132
def _process_mod_depends(self, module: str) -> None:
128133
"""

ugrd/initramfs_generator.py

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ def __init__(self, config='/etc/ugrd/config.toml', *args, **kwargs):
2020
self.build_pre = [self.generate_structure]
2121
self.config_dict = InitramfsConfigDict(logger=self.logger)
2222

23-
# This will be filled with function definitions for imported functions
24-
self._init_funcs = {}
23+
# Used for functions that are added to the bash source file
24+
self.included_functions = {}
2525

2626
# init_pre and init_final are run as part of generate_initramfs_main
2727
self.init_types = ['init_debug', 'init_early', 'init_main', 'init_late', 'init_premount', 'init_mount', 'init_cleanup']
@@ -84,9 +84,12 @@ def build_structure(self) -> None:
8484
self._run_hook('build_pre', return_output=False)
8585
self._run_hook('build_tasks', return_output=False)
8686

87-
def _run_func(self, function, external=False, return_output=True) -> list[str]:
87+
def _run_func(self, function, external=False, return_output=True, force_include=False) -> list[str]:
8888
"""
89-
Runs a function, returning the output in a list
89+
Runs a function.
90+
External ones must have self passed as the first argument.
91+
Returns the output if return_output is set.
92+
If force_include is set, forces the function to be included in the bash source file.
9093
"""
9194
self.logger.debug("Running function: %s" % function.__name__)
9295
if external:
@@ -99,17 +102,27 @@ def _run_func(self, function, external=False, return_output=True) -> list[str]:
99102
return
100103

101104
if function_output:
105+
if isinstance(function_output, list) and len(function_output) == 1:
106+
self.logger.debug("[%s] Function returned list with one element: %s" % (function.__name__, function_output[0]))
107+
function_output = function_output[0]
108+
109+
if function.__name__ in self.included_functions:
110+
raise ValueError("Function '%s' has already been included in the bash source file" % function.__name__)
111+
102112
if isinstance(function_output, str):
103113
self.logger.debug("[%s] Function returned string: %s" % (function.__name__, function_output))
114+
if force_include:
115+
self.logger.debug("[%s] Function output is being forced into bash source file" % function.__name__)
116+
self.included_functions[function.__name__] = function_output
104117
return function_output
105118
else:
106119
self.logger.debug("[%s] Function returned output: %s" % (function.__name__, pretty_print(function_output)))
107-
self._init_funcs[function.__name__] = function_output
120+
self.included_functions[function.__name__] = function_output
108121
return function.__name__
109122
else:
110123
self.logger.debug("[%s] Function returned no output" % function.__name__)
111124

112-
def _run_funcs(self, functions: list[str], external=False, return_output=True) -> list[str]:
125+
def _run_funcs(self, functions: list[str], *args, return_output=True, **kwargs) -> list[str]:
113126
"""
114127
Runs a list of functions
115128
Returns the output if return_output is set
@@ -119,25 +132,25 @@ def _run_funcs(self, functions: list[str], external=False, return_output=True) -
119132
for function in functions:
120133
# Only append if returning the output
121134
if return_output:
122-
if function_output := self._run_func(function, external=external, return_output=return_output):
135+
if function_output := self._run_func(function, *args, **kwargs):
123136
out.append(function_output)
124137
else:
125-
self._run_func(function, external=external, return_output=return_output)
138+
self._run_func(function, *args, **kwargs)
126139
return out
127140

128-
def _run_hook(self, hook: str, return_output=True) -> list[str]:
141+
def _run_hook(self, hook: str, *args, return_output=True, **kwargs) -> list[str]:
129142
"""
130143
Runs a hook for imported functions
131144
"""
132145
out = []
133146
self.logger.info("Running hook: %s" % hook)
134147
if hasattr(self, hook):
135148
self.logger.debug("Running internal functions for hook: %s" % hook)
136-
out += self._run_funcs(getattr(self, hook), return_output=return_output)
149+
out += self._run_funcs(getattr(self, hook), return_output=return_output, *args, **kwargs)
137150

138151
if external_functions := self.config_dict['imports'].get(hook):
139152
self.logger.debug("Running external functions for hook: %s" % hook)
140-
function_output = self._run_funcs(external_functions, external=True, return_output=return_output)
153+
function_output = self._run_funcs(external_functions, external=True, return_output=return_output, *args, **kwargs)
141154
out += function_output
142155

143156
if return_output:
@@ -154,18 +167,19 @@ def _run_init_hook(self, level: str) -> list[str]:
154167

155168
def generate_init_funcs(self) -> None:
156169
"""
157-
Generates the init functions file based on self._init_funcs
170+
Generates the init functions file based on self.included_functions
158171
"""
159-
if not self._init_funcs:
160-
self.logger.warning("No init functions to generate")
161-
return
162-
163172
out = [f"# Generated by UGRD v{__version__}"]
164173

165-
for func_name, func_content in self._init_funcs.items():
174+
for func_name, func_content in self.included_functions.items():
166175
out.append("\n\n" + func_name + "() {")
167-
for line in func_content:
168-
out.append(f" {line}")
176+
if isinstance(func_content, str):
177+
out.append(f" {func_content}")
178+
elif isinstance(func_content, list):
179+
for line in func_content:
180+
out.append(f" {line}")
181+
else:
182+
raise TypeError("Function content is not a string or list: %s" % func_content)
169183
out.append("}")
170184

171185
return out
@@ -194,6 +208,9 @@ def generate_init(self) -> None:
194208
init = [self.config_dict['shebang']]
195209
init += ["# Generated by UGRD v%s" % __version__]
196210

211+
# Run all included functions, so they get included
212+
self._run_hook('functions', force_include=True)
213+
197214
init.extend(self._run_init_hook('init_pre'))
198215

199216
if self.config_dict['imports'].get('custom_init'):
@@ -205,7 +222,7 @@ def generate_init(self) -> None:
205222
init.extend(self._run_init_hook('init_final'))
206223
init += ["\n\n# END INIT"]
207224

208-
if self._init_funcs:
225+
if self.included_functions:
209226
init_funcs = self.generate_init_funcs()
210227
self._write('init_funcs.sh', init_funcs, 0o755)
211228
init.insert(2, "source /init_funcs.sh")

0 commit comments

Comments
 (0)