Skip to content

Commit e3d6bd9

Browse files
committed
made libary path detction more generic, added old_count to control how old files are cycled
Signed-off-by: Zen <[email protected]>
1 parent 7d190f2 commit e3d6bd9

File tree

10 files changed

+122
-46
lines changed

10 files changed

+122
-46
lines changed

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Modules write to a shared config dict that is accessible by other modules.
7070
* `build_dir` (/tmp/initramfs) Defines where the build will take place.
7171
* `out_dir` (/tmp/initramfs_out) Defines where packed files will be placed.
7272
* `clean` (true) forces the build dir to be cleaned on each run.
73+
* `old_count` (1) Sets the number of old file to keep when running the `_rotate_old` function.
7374
* `file_owner` (portage) sets the owner for items pulled into the initramfs on the build system
7475
* `binaries` is a list used to define programs to be pulled into the initrams. `which` is used to find the path of added entries, and `lddtree` is used to resolve dependendies.
7576
* `paths` is a list of directores to create in the `build_dir`. They do not need a leading `/`.

ugrd/base/core.py

Lines changed: 43 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
from pathlib import Path
55

@@ -82,15 +82,49 @@ def deploy_nodes(self):
8282
raise e
8383

8484

85+
def configure_library_paths(self):
86+
"""
87+
Sets the export LD_LIBRARY_PATH variable to the library paths
88+
"""
89+
library_paths = ":".join(self.config_dict['library_paths'])
90+
self.logger.debug("Setting LD_LIBRARY_PATH to: %s" % library_paths)
91+
return "export LD_LIBRARY_PATH=%s" % library_paths
92+
93+
94+
def _process_paths_multi(self, path):
95+
"""
96+
Converts the input to a Path if it is not one
97+
"""
98+
self.logger.log(5, "Processing path: %s" % path)
99+
if not isinstance(path, Path):
100+
path = Path(path)
101+
102+
self.logger.debug("Adding path: %s" % path)
103+
self['paths'].append(path)
104+
105+
85106
def _process_binaries_multi(self, binary):
86107
"""
87108
Processes binaries into the binaries list, adding dependencies along the way.
88109
"""
89110
self.logger.debug("Processing binary: %s" % binary)
90111

91112
dependencies = calculate_dependencies(self, binary)
92-
self['dependencies'] = dependencies
93-
113+
# The first dependency will be the path of the binary itself, don't add this to the library paths
114+
first_dep = True
115+
for dependency in dependencies:
116+
self['dependencies'] = dependency
117+
if first_dep:
118+
self.logger.debug("Skipping adding library path for first dependency: %s" % dependency)
119+
first_dep = False
120+
continue
121+
if dependency.parent not in self['library_paths']:
122+
self.logger.info("Adding library path: %s" % dependency.parent)
123+
# Make it a string so NoDupFlatList can handle it
124+
# It being derived from a path should ensure it's a proper path
125+
self['library_paths'] = str(dependency.parent)
126+
127+
self.logger.debug("Adding binary: %s" % binary)
94128
self['binaries'].append(binary)
95129

96130

@@ -104,6 +138,7 @@ def _process_dependencies_multi(self, dependency):
104138
if not dependency.exists():
105139
raise FileNotFoundError("Dependency does not exist: %s" % dependency)
106140

141+
self.logger.debug("Adding dependency: %s" % dependency)
107142
self['dependencies'].append(dependency)
108143

109144

@@ -112,12 +147,13 @@ def _process_copies_multi(self, copy_name, copy_parameters):
112147
Processes a copy from the copies parameter
113148
Ensures the source and target are defined in the parameters.
114149
"""
115-
self.logger.debug("[%s] Processing copy: %s" % (copy_name, copy_parameters))
150+
self.logger.log(5, "[%s] Processing copies: %s" % (copy_name, copy_parameters))
116151
if 'source' not in copy_parameters:
117152
raise ValueError("[%s] No source specified" % copy_name)
118153
if 'destination' not in copy_parameters:
119154
raise ValueError("[%s] No target specified" % copy_name)
120155

156+
self.logger.debug("[%s] Adding copies: %s" % (copy_name, copy_parameters))
121157
self['copies'][copy_name] = copy_parameters
122158

123159

@@ -126,12 +162,13 @@ def _process_symlinks_multi(self, symlink_name, symlink_parameters):
126162
Processes a symlink,
127163
Ensures the source and target are defined in the parameters.
128164
"""
129-
self.logger.debug("[%s] Processing symlink: %s" % (symlink_name, symlink_parameters))
165+
self.logger.log(5, "[%s] Processing symlink: %s" % (symlink_name, symlink_parameters))
130166
if 'source' not in symlink_parameters:
131167
raise ValueError("[%s] No source specified" % symlink_name)
132168
if 'target' not in symlink_parameters:
133169
raise ValueError("[%s] No target specified" % symlink_name)
134170

171+
self.logger.debug("[%s] Adding symlink: %s -> %s" % (symlink_name, symlink_parameters['source'], symlink_parameters['target']))
135172
self['symlinks'][symlink_name] = symlink_parameters
136173

137174

@@ -152,6 +189,7 @@ def _process_nodes_multi(self, node_name, node_config):
152189
node_config['mode'] = 0o660
153190
self.logger.debug("[%s] No mode specified, assuming: %s" % (node_name, node_config['mode']))
154191

192+
self.logger.debug("[%s] Adding node: %s" % (node_name, node_config))
155193
self['nodes'][node_name] = node_config
156194

157195

ugrd/base/core.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ file_owner = "portage"
22
build_dir = "/tmp/initramfs"
33
out_dir = "/tmp/initramfs_out"
44
clean = true
5+
library_paths = [ "/lib64" ]
6+
old_count = 1
57

68
[nodes.console]
79
mode = 0o644
@@ -14,21 +16,27 @@ minor = 1
1416
"_process_copies_multi",
1517
"_process_symlinks_multi",
1618
"_process_file_owner",
17-
"_process_nodes_multi"
19+
"_process_nodes_multi",
20+
"_process_paths_multi",
1821
]
1922

2023
[imports.build_tasks]
2124
"ugrd.base.core" = [ "deploy_dependencies", "deploy_copies", "deploy_nodes", "deploy_symlinks" ]
2225

26+
[imports.init_pre]
27+
"ugrd.base.core" = [ "configure_library_paths" ]
28+
2329
[custom_parameters]
2430
binaries = "NoDupFlatList" # Binaries which should be included in the intiramfs, dependencies resolved with lddtree
2531
dependencies = "NoDupFlatList" # Add the dependencies property, used to define the dependencies of the initramfs
32+
library_paths = "NoDupFlatList" # Add the library_paths property, used to define the library paths to add to LD_LIBRARY_PATH
2633
symlinks = "dict" # Add the symlinks property, used to define the symlinks to be made in the initramfs
2734
copies = "dict" # Add the copies property, used to define the files to be copied to the initramfs
2835
nodes = "dict" # Add the nodes property, used to define the device nodes to be created
2936
paths = "NoDupFlatList" # Paths to be copied to the initramfs
3037
build_dir = "Path" # The directory where the initramfs is built
3138
out_dir = "Path" # The directory where the initramfs is packed/output. If no packer is used, this is the final output directory.
39+
old_count = "int" # The number of times to cycle old files before deleting
3240
clean = "bool" # Add the clean property, used to define if the mounts should be cleaned up after boot
3341
file_owner = "str" # Add the file_owner property, used to define who should own the copied initramfs files
3442
_file_owner_uid = "int" # Add the _file_owner_uid property, used to store the uid of the file owner

ugrd/base/cpio.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ def pack_cpio(self):
3838
self.logger.info("Creating CPIO file from packing list: %s" % packing_list)
3939

4040
out_cpio = self.out_dir / self.config_dict['out_file']
41+
if out_cpio.exists():
42+
self._rotate_old(out_cpio)
4143

4244
with open(out_cpio, 'wb') as cpio_file:
4345
cmd = run([str(cpio_path), packing_list], stdout=cpio_file)

ugrd/crypto/cryptsetup.py

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__author__ = 'desultory'
22

3-
__version__ = '0.8.1'
3+
__version__ = '0.8.2'
44

55

66
CRYPTSETUP_PARAMETERS = ['key_type', 'partuuid', 'uuid', 'key_file', 'header_file', 'retries', 'key_command', 'reset_command', 'try_nokey']
@@ -56,13 +56,6 @@ def _process_cryptsetup_multi(self, mapped_name, config):
5656
self['cryptsetup'][mapped_name] = config
5757

5858

59-
def configure_library_dir(self):
60-
"""
61-
exports the libtary path for cryptsetup
62-
"""
63-
return 'export LD_LIBRARY_PATH=/lib64'
64-
65-
6659
def get_crypt_sources(self):
6760
"""
6861
Goes through each cryptsetup device, sets $CRYPTSETUP_SOURCE_NAME to the source device
@@ -166,14 +159,3 @@ def crypt_init(self):
166159
out += ['fi']
167160
return out
168161

169-
170-
def find_libgcc(self):
171-
"""
172-
Finds libgcc.so, adds a copies item for it.
173-
"""
174-
ldconfig = self._run(['ldconfig', '-p']).stdout.decode().split("\n")
175-
libgcc = [lib for lib in ldconfig if 'libgcc_s' in lib and 'libc6,x86-64' in lib][0]
176-
source_path = libgcc.partition('=> ')[-1]
177-
self.logger.debug("Source path for libgcc_s: %s" % source_path)
178-
179-
self.config_dict['copies']['libgcc_s'] = {'source': source_path, 'destination': '/lib64/'}

ugrd/crypto/cryptsetup.toml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,12 @@ cryptsetup_autoretry = true
1010
[imports.config_processing]
1111
"ugrd.crypto.cryptsetup" = [ "_process_cryptsetup_multi", "_process_cryptsetup_key_types_multi" ]
1212

13-
[imports.init_pre]
14-
"ugrd.crypto.cryptsetup" = [ "configure_library_dir" ]
15-
1613
[imports.init_early]
1714
"ugrd.crypto.cryptsetup" = [ "get_crypt_sources" ]
1815

1916
[imports.init_main]
2017
"ugrd.crypto.cryptsetup" = [ "crypt_init" ]
2118

22-
[imports.build_pre]
23-
"ugrd.crypto.cryptsetup" = [ "find_libgcc" ]
24-
2519
[cryptsetup_key_types.keyfile]
2620
key_command = "cat {key_file} >"
2721

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.8.2"
3+
__version__ = "0.8.3"
44

55
from tomllib import load
66
from pathlib import Path
@@ -43,6 +43,7 @@ def import_args(self, args: dict):
4343
def __setitem__(self, key, value):
4444
# If the type is registered, use the appropriate update function
4545
if expected_type := self.builtin_parameters.get(key, self['custom_parameters'].get(key)):
46+
self.logger.log(5, "[%s] Expected type: %s" % (key, expected_type))
4647
if hasattr(self, f"_process_{key}"):
4748
self.logger.debug("Using builtin setitem for: %s" % key)
4849
getattr(self, f"_process_{key}")(value)
@@ -66,6 +67,8 @@ def __setitem__(self, key, value):
6667
else:
6768
super().__setitem__(key, expected_type(value))
6869
else: # Otherwise set it like a normal dict item
70+
self.logger.debug("[%s] Unable to determine expected type, valid builtin types: %s" % (key, self.builtin_parameters.keys()))
71+
self.logger.debug("[%s] Custom types: %s" % (key, self['custom_parameters'].keys()))
6972
if key.startswith('_'):
7073
self.logger.warning("Setting unknown internal paramaters '%s' with value: %s" % (key, value))
7174
else:
@@ -97,6 +100,8 @@ def _process_custom_parameters(self, parameter_name, parameter_type):
97100
super().__setitem__(parameter_name, eval(parameter_type)())
98101
elif parameter_type == "bool":
99102
super().__setitem__(parameter_name, False)
103+
elif parameter_type == "int":
104+
super().__setitem__(parameter_name, 0)
100105

101106
@handle_plural
102107
def _process_imports(self, import_type: str, import_value: dict):

ugrd/initramfs_generator.py

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

22
__author__ = "desultory"
3-
__version__ = "0.8.0"
3+
__version__ = "0.8.1"
44

55
from tomllib import load
66
from pathlib import Path
@@ -42,7 +42,7 @@ def load_config(self):
4242

4343
self.logger.debug("Loaded config: %s" % self.config_dict)
4444

45-
for parameter in ['build_dir', 'out_dir', 'clean']:
45+
for parameter in ['build_dir', 'out_dir', 'clean', 'old_count']:
4646
dict_value = self.config_dict[parameter]
4747
if dict_value is not None:
4848
setattr(self, parameter, dict_value)
@@ -192,8 +192,7 @@ def generate_structure(self):
192192
self._mkdir(self.build_dir)
193193

194194
for subdir in set(self.config_dict['paths']):
195-
subdir_path = Path(subdir)
196-
subdir_relative_path = subdir_path.relative_to(subdir_path.anchor)
195+
subdir_relative_path = subdir.relative_to(subdir.anchor)
197196
target_dir = self.build_dir / subdir_relative_path
198197

199198
self._mkdir(target_dir)
@@ -266,6 +265,12 @@ def _write(self, file_name, contents, chmod_mask=0o644, in_build_dir=True):
266265
self.logger.debug("Parent directory for '%s' does not exist: %s" % (file_path.name, file_path))
267266
self._mkdir(file_path.parent)
268267

268+
if file_path.is_file():
269+
self.logger.warning("File already exists: %s" % file_path)
270+
if self.clean:
271+
self.logger.info("Deleting file: %s" % file_path)
272+
file_path.unlink()
273+
269274
self.logger.debug("[%s] Writing contents:\n%s" % (file_path, pretty_print(contents)))
270275
with open(file_path, 'w') as file:
271276
file.writelines("\n".join(contents))
@@ -311,6 +316,51 @@ def _copy(self, source, dest=None, in_build_dir=True):
311316

312317
self._chown(dest_path)
313318

319+
def _rotate_old(self, file_name: Path, sequence=0):
320+
"""
321+
Copies a file to file_name.old then file_nane.old.n, where n is the next number in the sequence
322+
"""
323+
# Nothing to do if the file doesn't exist
324+
if not file_name.is_file():
325+
self.logger.debug("File does not exist: %s" % file_name)
326+
return
327+
328+
# If the cycle count is not set, attempt to clean
329+
if not self.old_count:
330+
if self.clean:
331+
self.logger.info("Deleting file: %s" % file_name)
332+
file_name.unlink()
333+
return
334+
else:
335+
# Fail if the cycle count is not set and clean is disabled
336+
raise RuntimeError("Unable to cycle file, as cycle count is not set and clean is disabled: %s" % file_name)
337+
338+
self.logger.debug("[%d] Cycling file: %s" % (sequence, file_name))
339+
340+
# If the sequence is 0, we're cycling the file for the first time, just rename it to .old
341+
suffix = '.old' if sequence == 0 else '.old.%d' % sequence
342+
target_file = file_name.with_suffix(suffix)
343+
344+
self.logger.debug("[%d] Target file: %s" % (sequence, target_file))
345+
# If the target file exists, cycle again
346+
if target_file.is_file():
347+
# First check if we've reached the cycle limit
348+
if sequence >= self.old_count:
349+
# Clean the last file in the sequence if clean is enabled
350+
if self.clean:
351+
self.logger.info("Deleting old file: %s" % target_file)
352+
target_file.unlink()
353+
else:
354+
self.logger.debug("Cycle limit reached")
355+
return
356+
else:
357+
self.logger.debug("[%d] Target file exists, cycling again" % sequence)
358+
self._rotate_old(target_file, sequence + 1)
359+
360+
# Finally, rename the file
361+
self.logger.info("[%d] Cycling file: %s -> %s" % (sequence, file_name, target_file))
362+
file_name.rename(target_file)
363+
314364
def _get_build_path(self, path):
315365
"""
316366
Returns the build path

ugrd/main.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ def main():
1717
# Add arguments for dracut compatibility
1818
argparser.add_argument('-c', '--config', action='store', help='Config file location')
1919
argparser.add_argument('--kver', action='store', help='Kernel version')
20+
argparser.add_argument('--force', action='store_true', help='Enable build cleaning', default=True)
2021

2122
# Add and ignore arguments for dracut compatibility
22-
argparser.add_argument('--force', action='store_true', help='Not used, for dracut compatibility')
2323
argparser.add_argument('--kernel-image', action='store', help='Kernel image')
2424

2525
# Add the argument for the output file
@@ -36,14 +36,10 @@ def main():
3636
logger.setLevel(20)
3737

3838
kwargs = {'logger': logger}
39-
if config := args.config:
40-
kwargs['config'] = config
4139

42-
if config := args.kver:
43-
kwargs['kernel_version'] = config
44-
45-
if config := args.output_file:
46-
kwargs['out_file'] = config
40+
for config, arg in {'clean': 'force', 'kernel_version': 'kver', 'config': 'config', 'out_file': 'output_file'}.items():
41+
if arg := getattr(args, arg):
42+
kwargs[config] = arg
4743

4844
generator = InitramfsGenerator(**kwargs)
4945
try:

ugrd/zen_custom.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
A collection of classes and decorators
33
"""
4-
__version__ = '3.1.0'
4+
__version__ = '3.1.1'
55
__author__ = 'desultory'
66

77
import logging
@@ -108,7 +108,7 @@ def wrapper(self, *args):
108108
for key, value in focus_arg.items():
109109
function(self, *(other_args + (key, value,)))
110110
else:
111-
self.logger.debug("Arguments were not expanded: %s" % args)
111+
self.logger.log(5, "Arguments were not expanded: %s" % args)
112112
return function(self, *args)
113113
return wrapper
114114

0 commit comments

Comments
 (0)