def test_serialize_deserialize(self): self.assertEqual( {v for k, v in si.ID_TO_ITEM.items() if k != '/'} | { # These come the inline features added above. MakeDirsItem( from_target='t1', into_dir='/a', path_to_make='b'), MakeDirsItem( from_target='t2', into_dir='/c', path_to_make='d'), }, self._items_for_features(), ) # Fail if some target fails to resolve to a path with self.assertRaisesRegex(RuntimeError, f'{si.T_BASE}:[^ ]* not in'): self._items_for_features(target_to_path={})
def test_foreign_layer_assert(self): foreign1 = ForeignLayerItem( from_target='t1', cmd=['x'], user='******', serve_rpm_snapshots=(), ) foreign2 = ForeignLayerItem( from_target='t2', cmd=['a'], user='******', serve_rpm_snapshots=(), ) # Good path: one FOREIGN_LAYER & default MAKE_SUBVOL DependencyGraph([foreign1], 'layer_t') # Too many foreign layers with self.assertRaises(AssertionError): DependencyGraph([foreign1, foreign2], 'layer_t') # Cannot mix foreign layer & depedency-sortable item with self.assertRaises(AssertionError): DependencyGraph([ foreign1, MakeDirsItem(from_target='', into_dir='a', path_to_make='b'), ], 'layer_t') # Cannot have other phase items with self.assertRaises(AssertionError): DependencyGraph([ foreign1, RemovePathItem(from_target='', path='x', action='if_exists'), ], 'layer_t')
def test_duplicate_paths_provided(self): with self.assertRaisesRegex( RuntimeError, '^Both .* and .* from .* provide the same path$'): ValidatedReqsProvs([ InstallFileItem(from_target='', source='x', dest='y/x'), MakeDirsItem(from_target='', into_dir='/', path_to_make='y/x'), ])
def test_cycle_detection(self): def requires_provides_directory_class(requires_dir, provides_dir): @dataclass(init=False, frozen=True) class RequiresProvidesDirectory(ImageItem): def requires(self): yield require_directory(requires_dir) def provides(self): yield ProvidesDirectory(path=provides_dir) return RequiresProvidesDirectory # `dg_ok`: dependency-sorting will work without a cycle first = FilesystemRootItem(from_target='') second = requires_provides_directory_class('/', 'a')(from_target='') third = MakeDirsItem(from_target='', into_dir='a', path_to_make='b/c') dg_ok = DependencyGraph([second, first, third], layer_target='t') self.assertEqual(_fs_root_phases(first), list(dg_ok.ordered_phases())) # `dg_bad`: changes `second` to get a cycle dg_bad = DependencyGraph([ requires_provides_directory_class('a/b', 'a')(from_target=''), first, third, ], layer_target='t') self.assertEqual(_fs_root_phases(first), list(dg_bad.ordered_phases())) with TempSubvolumes(sys.argv[0]) as temp_subvolumes: subvol = temp_subvolumes.create('subvol') provides_root = PhasesProvideItem(from_target='t', subvol=subvol) self.assertEqual( [second, third], list(dg_ok.gen_dependency_order_items(provides_root)), ) with self.assertRaisesRegex(AssertionError, '^Cycle in '): list(dg_bad.gen_dependency_order_items(provides_root))
def test_phase_order(self): class FakeRemovePaths: get_phase_builder = 'kittycat' def phase_order(self): return PhaseOrder.REMOVE_PATHS first = FilesystemRootItem(from_target='') second = FakeRemovePaths() third = MakeDirsItem(from_target='', into_dir='/', path_to_make='a/b') dg = DependencyGraph([second, first, third], layer_target='t') self.assertEqual( _fs_root_phases(first) + [ (FakeRemovePaths.get_phase_builder, (second, )), ], list(dg.ordered_phases()), ) with TempSubvolumes(sys.argv[0]) as temp_subvolumes: subvol = temp_subvolumes.create('subvol') self.assertEqual([third], list( dg.gen_dependency_order_items( PhasesProvideItem(from_target='t', subvol=subvol), )))
def mangle(feature_target): return feature_target + ( '_IF_YOU_REFER_TO_THIS_RULE_YOUR_DEPENDENCIES_WILL_BE_BROKEN_' 'SO_DO_NOT_DO_THIS_EVER_PLEASE_KTHXBAI') # This should be a faithful transcription of the `image_feature` # specifications in `test/TARGETS`. The IDs currently have no semantics, # existing only to give names to specific items. ID_TO_ITEM = { '/': FilesystemRootItem(from_target=None), # From `feature_dirs`: 'foo/bar': MakeDirsItem(from_target=T_DIRS, into_dir='/', path_to_make='/foo/bar'), 'foo/bar/baz': MakeDirsItem(from_target=T_DIRS, into_dir='/foo/bar', path_to_make='baz'), # From `feature_bad_dir`: 'foo/borf/beep': MakeDirsItem( from_target=T_BAD_DIR, into_dir='/foo', path_to_make='borf/beep', user_group='uuu:ggg', mode='mmm', ), # From `feature_symlinks`: 'foo/fighter':
from fs_image.compiler.items.make_dirs import MakeDirsItem from fs_image.compiler.items.make_subvol import FilesystemRootItem from fs_image.compiler.items.phases_provide import PhasesProvideItem from ..dep_graph import ( DependencyGraph, ItemProv, ItemReq, ItemReqsProvs, ValidatedReqsProvs, ) from ..provides import ProvidesDirectory, ProvidesDoNotAccess, ProvidesFile from ..requires import require_directory PATH_TO_ITEM = { '/a/b/c': MakeDirsItem(from_target='', into_dir='/', path_to_make='a/b/c'), '/a/d/e': MakeDirsItem(from_target='', into_dir='a', path_to_make='d/e'), '/a/b/c/F': InstallFileItem( from_target='', source='x', dest='a/b/c/F', ), '/a/d/e/G': InstallFileItem( from_target='', source='G', dest='a/d/e/G', ), } def _fs_root_phases(item):