Skip to content

Commit 96670f2

Browse files
authored
Merge pull request #313 from desultory/dev
refactor, move hook sorter to generator_helpers to reduce noise
2 parents 30dbd87 + 6370d12 commit 96670f2

File tree

2 files changed

+85
-85
lines changed

2 files changed

+85
-85
lines changed

src/ugrd/generator_helpers.py

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from .exceptions import ValidationError
1111

12-
__version__ = "1.6.5"
12+
__version__ = "1.7.0"
1313
__author__ = "desultory"
1414

1515

@@ -288,3 +288,86 @@ def _rotate_old(self, file_name: Path, sequence=0) -> None:
288288
# Finally, rename the file
289289
self.logger.info("[%d] Cycling file: %s -> %s" % (sequence, file_name, target_file))
290290
file_name.rename(target_file)
291+
292+
def sort_hook_functions(self, hook: str) -> None:
293+
"""Sorts the functions for the specified hook based on the import order.
294+
"before" functions are moved before the target function,
295+
"after" functions' target function is moved before the current function.
296+
297+
Filters orders which do not contain functions or targets in the current hook.
298+
"""
299+
func_names = [func.__name__ for func in self["imports"].get(hook, [])]
300+
if not func_names:
301+
return self.logger.debug("No functions for hook: %s" % hook)
302+
303+
b = self["import_order"].get("before", {})
304+
before = {k: v for k, v in b.items() if k in func_names and any(subv in func_names for subv in b[k])}
305+
a = self["import_order"].get("after", {})
306+
after = {k: v for k, v in a.items() if k in func_names and any(subv in func_names for subv in a[k])}
307+
308+
if not before and not after:
309+
return self.logger.debug("No import order specified for hook: %s" % hook)
310+
311+
def iter_order(order, direction):
312+
"""Iterate over all functions in an import order list,
313+
using this information to move the order of function names in the import list.
314+
315+
Returns True if any changes were made, False otherwise."""
316+
changed = False
317+
318+
for func_name, other_funcs in order.items():
319+
func_index = func_names.index(func_name) # Get the index based on the current position
320+
assert func_index >= 0, "Function not found in import list: %s" % func_name
321+
for other_func in other_funcs:
322+
try:
323+
other_index = func_names.index(other_func)
324+
except ValueError:
325+
continue
326+
assert other_index >= 0, "Function not found in import list: %s" % other_func
327+
328+
def reorder_func(direction):
329+
"""Reorders the function based on the direction."""
330+
if direction == "before": # Move the function before the other function
331+
self.logger.debug("[%s] Moving function before: %s" % (func_name, other_func))
332+
func_names.insert(other_index, func_names.pop(func_index))
333+
self["imports"][hook].insert(other_index, self["imports"][hook].pop(func_index))
334+
elif direction == "after": # Move the other function before the current function
335+
self.logger.debug("[%s] Moving function before: %s" % (other_func, func_name))
336+
func_names.insert(func_index, func_names.pop(other_index))
337+
self["imports"][hook].insert(func_index, self["imports"][hook].pop(other_index))
338+
else:
339+
raise ValueError("Invalid direction: %s" % direction)
340+
341+
self.logger.log(5, "[%s] Imports:\n%s", hook, ", ".join(i.__name__ for i in self["imports"][hook]))
342+
if direction == "before": # func_index should be before other_index
343+
if func_index > other_index: # If the current function is after the other function
344+
reorder_func("before") # Move the current function before the other function)
345+
changed = True
346+
else: # Log otherwise
347+
self.logger.log(5, "Function %s already before: %s" % (func_name, other_func))
348+
elif direction == "after": # func_index should be after other_index
349+
if func_index < other_index: # If the current function is before the other function
350+
reorder_func("after") # Move the current function after the other function
351+
changed = True
352+
else:
353+
self.logger.log(5, "Function %s already after: %s" % (func_name, other_func))
354+
else:
355+
raise ValueError("Invalid direction: %s" % direction)
356+
func_index = func_names.index(func_name) # Update the index after moving
357+
return changed
358+
359+
max_iterations = len(func_names) * (len(before) + 1) * (len(after) + 1) # Prevent infinite loops
360+
iterations = max_iterations
361+
while iterations:
362+
iterations -= 1
363+
# Update the order based on the before and after lists
364+
if not any([iter_order(before, "before"), iter_order(after, "after")]):
365+
self.logger.debug(
366+
"[%s] Import order converged after %s iterations" % (hook, max_iterations - iterations)
367+
)
368+
break # Keep going until no changes are made
369+
else: # If the loop completes without breaking, raise an error
370+
self.logger.error("Import list: %s" % func_names)
371+
self.logger.error("Before: %s" % before)
372+
self.logger.error("After: %s" % after)
373+
raise ValueError("Import order did not converge after %s iterations" % max_iterations)

src/ugrd/initramfs_generator.py

Lines changed: 1 addition & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -143,95 +143,12 @@ def run_func(self, function, force_include=False, force_exclude=False) -> list[s
143143
else:
144144
self.logger.debug("[%s] Function returned no output" % function.__name__)
145145

146-
def sort_hook_functions(self, hook: str) -> None:
147-
"""Sorts the functions for the specified hook based on the import order.
148-
"before" functions are moved before the target function,
149-
"after" functions' target function is moved before the current function.
150-
151-
Filters orders which do not contain functions or targets in the current hook.
152-
"""
153-
func_names = [func.__name__ for func in self["imports"].get(hook, [])]
154-
if not func_names:
155-
return self.logger.debug("No functions for hook: %s" % hook)
156-
157-
b = self["import_order"].get("before", {})
158-
before = {k: v for k, v in b.items() if k in func_names and any(subv in func_names for subv in b[k])}
159-
a = self["import_order"].get("after", {})
160-
after = {k: v for k, v in a.items() if k in func_names and any(subv in func_names for subv in a[k])}
161-
162-
if not before and not after:
163-
return self.logger.debug("No import order specified for hook: %s" % hook)
164-
165-
def iter_order(order, direction):
166-
""" Iterate over all functions in an import order list,
167-
using this information to move the order of function names in the import list.
168-
169-
Returns True if any changes were made, False otherwise."""
170-
changed = False
171-
172-
for func_name, other_funcs in order.items():
173-
func_index = func_names.index(func_name) # Get the index based on the current position
174-
assert func_index >= 0, "Function not found in import list: %s" % func_name
175-
for other_func in other_funcs:
176-
try:
177-
other_index = func_names.index(other_func)
178-
except ValueError:
179-
continue
180-
assert other_index >= 0, "Function not found in import list: %s" % other_func
181-
182-
def reorder_func(direction):
183-
"""Reorders the function based on the direction."""
184-
if direction == "before": # Move the function before the other function
185-
self.logger.debug("[%s] Moving function before: %s" % (func_name, other_func))
186-
func_names.insert(other_index, func_names.pop(func_index))
187-
self["imports"][hook].insert(other_index, self["imports"][hook].pop(func_index))
188-
elif direction == "after": # Move the other function before the current function
189-
self.logger.debug("[%s] Moving function before: %s" % (other_func, func_name))
190-
func_names.insert(func_index, func_names.pop(other_index))
191-
self["imports"][hook].insert(func_index, self["imports"][hook].pop(other_index))
192-
else:
193-
raise ValueError("Invalid direction: %s" % direction)
194-
195-
self.logger.log(5, "[%s] Imports:\n%s", hook, ", ".join(i.__name__ for i in self["imports"][hook]))
196-
if direction == "before": # func_index should be before other_index
197-
if func_index > other_index: # If the current function is after the other function
198-
reorder_func("before") # Move the current function before the other function)
199-
changed = True
200-
else: # Log otherwise
201-
self.logger.log(5, "Function %s already before: %s" % (func_name, other_func))
202-
elif direction == "after": # func_index should be after other_index
203-
if func_index < other_index: # If the current function is before the other function
204-
reorder_func("after") # Move the current function after the other function
205-
changed = True
206-
else:
207-
self.logger.log(5, "Function %s already after: %s" % (func_name, other_func))
208-
else:
209-
raise ValueError("Invalid direction: %s" % direction)
210-
func_index = func_names.index(func_name) # Update the index after moving
211-
return changed
212-
213-
max_iterations = len(func_names) * (len(before) + 1) * (len(after) + 1) # Prevent infinite loops
214-
iterations = max_iterations
215-
while iterations:
216-
iterations -= 1
217-
# Update the order based on the before and after lists
218-
if not any([iter_order(before, "before"), iter_order(after, "after")]):
219-
self.logger.debug(
220-
"[%s] Import order converged after %s iterations" % (hook, max_iterations - iterations)
221-
)
222-
break # Keep going until no changes are made
223-
else: # If the loop completes without breaking, raise an error
224-
self.logger.error("Import list: %s" % func_names)
225-
self.logger.error("Before: %s" % before)
226-
self.logger.error("After: %s" % after)
227-
raise ValueError("Import order did not converge after %s iterations" % max_iterations)
228-
229146
def run_hook(self, hook: str, *args, **kwargs) -> list[str]:
230147
"""Runs all functions for the specified hook.
231148
If the function is masked, it will be skipped.
232149
If the function is in import_order, handle the ordering
233150
"""
234-
self.sort_hook_functions(hook)
151+
self.sort_hook_functions(hook) # This is in generator_helpers.py
235152
out = []
236153
for function in self["imports"].get(hook, []):
237154
if function.__name__ in self["masks"].get(hook, []):

0 commit comments

Comments
 (0)