diff options
Diffstat (limited to 'apply')
-rw-r--r-- | apply/__main__.py | 7 | ||||
-rw-r--r--[-rwxr-xr-x] | apply/apply_cmd.py (renamed from apply/apply.py) | 24 | ||||
-rw-r--r-- | apply/remove_cmd.py | 35 | ||||
-rw-r--r-- | apply/resolv.py | 20 | ||||
-rw-r--r-- | apply/state.py | 55 | ||||
-rw-r--r-- | apply/status_cmd.py (renamed from apply/status.py) | 0 | ||||
-rw-r--r-- | apply/writer.py | 23 |
7 files changed, 128 insertions, 36 deletions
diff --git a/apply/__main__.py b/apply/__main__.py index 4f7f6a4..c725fb5 100644 --- a/apply/__main__.py +++ b/apply/__main__.py @@ -1,8 +1,9 @@ import argparse import yaml -from . import apply as apply_cmd -from . import status +from . import apply_cmd +from . import status_cmd +from . import remove_cmd def parse_config(path): @@ -13,7 +14,7 @@ def parse_config(path): return config -sub_cmds = {"apply": apply_cmd, "status": status} +sub_cmds = {"apply": apply_cmd, "status": status_cmd, "remove": remove_cmd} parser = argparse.ArgumentParser() parser.add_argument("--apply-dir", "-a", default=None, diff --git a/apply/apply.py b/apply/apply_cmd.py index 974d800..4cffce4 100755..100644 --- a/apply/apply.py +++ b/apply/apply_cmd.py @@ -14,12 +14,12 @@ class DirReader: self.resolv = resolv self.config = config - def read_package(self, name): - package_root = name + def read_module(self, name): + module_root = name # Walk down and link dir og file - for root, dirs, files in os.walk(package_root): - rootrel = os.path.relpath(root, start=package_root) + for root, dirs, files in os.walk(module_root): + rootrel = os.path.relpath(root, start=module_root) # Check if we can just link this folder if rootrel not in self.config["do_not_link"]: @@ -36,7 +36,9 @@ class DirReader: def cmd_args(parser: argparse.ArgumentParser): - parser.add_argument("packages", nargs="*", help="Packages to apply") + parser.add_argument("modules", nargs="*", help="modules to apply") + parser.add_argument("-a", "--reapply", help="reapply modules", + action="store_true") def cmd_func(args, config): @@ -45,13 +47,17 @@ def cmd_func(args, config): resolv = Resolver(args.apply_dir, writer, state, args.override_existing) + writer.attach_hook(state.dump_state) + + if args.reapply: + args.modules = state.saved + reader = DirReader(config, resolv) - for pack in args.packages: - reader.read_package(pack) + for module in args.modules: + reader.read_module(module) + state.add_saved_module(module) writer.apply(dry_run=args.dry_run) - if not args.dry_run: - state.dump_state() cmd_help = "Apply modules from current directory" diff --git a/apply/remove_cmd.py b/apply/remove_cmd.py new file mode 100644 index 0000000..0b8411b --- /dev/null +++ b/apply/remove_cmd.py @@ -0,0 +1,35 @@ +import argparse +from .state import StateFile +from .writer import Writer +import copy + + +def cmd_args(parser: argparse.ArgumentParser): + parser.add_argument("-u", "--unused", + help="remove unused folders and links", + action="store_true") + parser.add_argument("-a", "--all", help="remove all modules", + action="store_true") + parser.add_argument("-m", "--modules", nargs="+", help="specific modules") + + +def cmd_func(args, config): + state = StateFile(args.apply_dir) + if args.all: + args.modules = copy.copy(state.saved) + + if args.unused: + def func(mod): return not state.is_saved(mod) + else: + def func(mod): return mod in args.modules + + writer = Writer() + state.remove_by_condition(func, writer) + if args.modules: + for module in args.modules: + state.remove_saved_module(module) + + writer.apply(args.dry_run) + + +cmd_help = "remove links and files" diff --git a/apply/resolv.py b/apply/resolv.py index 93d0566..0073273 100644 --- a/apply/resolv.py +++ b/apply/resolv.py @@ -15,24 +15,24 @@ class Resolver: self.override = override self.state = state - def check_parent(self, path: Path, packagename): + def check_parent(self, path: Path, modulename): """ Check if parents exists, and if we created them mark them - with package name + with module name """ parent = path.parent exists = parent.exists() if (not exists) or parent in self.state.dirs: - self.check_parent(parent, packagename) + self.check_parent(parent, modulename) # Add to state - self.state.add_dir(parent, packagename) + self.state.add_dir(parent, modulename) if not exists: self.writer.create_dir(parent) - def do_link(self, package, ppath: Path): + def do_link(self, module, ppath: Path): dest = Path(self.applydir, ppath) dest_state = FileState.check_location(dest) @@ -41,11 +41,11 @@ class Resolver: raise Exception(f"Destination {ppath} already exists") # Save the link in the statefile - self.state.add_link(dest, package) + self.state.add_link(dest, module) - self.check_parent(dest, package) + self.check_parent(dest, module) - target_abs = Path.cwd().joinpath(Path(package, ppath)) + target_abs = Path.cwd().joinpath(Path(module, ppath)) if dest_state == FileState.Owned and dest_state.link_intact()\ and dest_state.links_to() == target_abs: return @@ -54,6 +54,6 @@ class Resolver: self.writer.delete(dest) self.writer.create_link(target_abs, dest) - def do_folder_link(self, package, ppath: Path) -> bool: - self.do_link(package, ppath) + def do_folder_link(self, module, ppath: Path) -> bool: + self.do_link(module, ppath) return True diff --git a/apply/state.py b/apply/state.py index 1c05633..9dafe9d 100644 --- a/apply/state.py +++ b/apply/state.py @@ -4,6 +4,8 @@ from enum import Enum import hashlib import os +from .writer import Writer + def add_or_create(dictio, key, value): if key in dictio: @@ -66,7 +68,8 @@ class FileState(Enum): class StateFile: links = {} dirs = {} - attr_to_save = ["links", "applydir", "dirs"] + saved = [] + attr_to_save = ["links", "applydir", "dirs", "saved"] def __init__(self, applydir): # Generate unique string for each possible applydir @@ -86,6 +89,7 @@ class StateFile: self.links = state.get("links", {}) self.dirs = state.get("dirs", {}) self.applydir = state.get("applydir", self.applydir) + self.saved = state.get("saved", []) def save_to_dict(self): all_attr = self.__dict__ @@ -94,13 +98,52 @@ class StateFile: res[key] = all_attr[key] return res - def dump_state(self): + def dump_state(self, dry_run): + if dry_run: + return with self.statefile.open("w") as f: json.dump(self.save_to_dict(), f) - def add_dir(self, path: Path, packagename: str): + def add_dir(self, path: Path, modulename: str): # Add to state - add_or_create(self.dirs, str(path), packagename) + add_or_create(self.dirs, str(path), modulename) + + def add_link(self, dest, modulename): + self.links[str(dest)] = modulename + + def add_saved_module(self, modulename): + if modulename not in self.saved: + self.saved.append(modulename) + + def is_saved(self, modulename): + return modulename in self.saved + + def remove_saved_module(self, modulename): + if modulename in self.saved: + self.saved.remove(modulename) + + def __delete_dir(self, writer: Writer, path: str, module): + self.dirs[path].remove(module) + + if len(self.dirs[path]) == 0: + writer.remove(Path(path)) + + def __delete_link(self, writer: Writer, path: str): + del self.links[path] + + if FileState.check_location(Path(path)) == FileState.Owned: + writer.delete(Path(path)) + + def remove_by_condition(self, cond, writer: Writer): + writer.attach_hook(self.dump_state) + links = list(self.links.keys()) + for link in links: + if cond(self.links[link]): + self.__delete_link(writer, link) - def add_link(self, dest, packagename): - self.links[str(dest)] = packagename + dirs = list(self.dirs.keys()) + for directory in dirs: + modules = self.dirs[directory] + for module in modules: + if cond(module): + self.__delete_dir(writer, directory, module) diff --git a/apply/status.py b/apply/status_cmd.py index 514252b..514252b 100644 --- a/apply/status.py +++ b/apply/status_cmd.py diff --git a/apply/writer.py b/apply/writer.py index d6a5550..9c23128 100644 --- a/apply/writer.py +++ b/apply/writer.py @@ -7,6 +7,7 @@ class Writer: self.links_todo = {} self.dirs_todo = [] self.delete_todo = [] + self.apply_hook = [] def create_link(self, target: Path, linkpath: Path): if linkpath in self.links_todo: @@ -26,14 +27,17 @@ class Writer: self.delete_todo.append(path) - def apply_dir(self, path: Path, dry_run): + def attach_hook(self, hook): + self.apply_hook.append(hook) + + def __apply_dir(self, path: Path, dry_run): print(f"mkdir {path}") if not dry_run: path.mkdir() - def apply_delete(self, path: Path, dry_run): - if path.is_dir(): - print(f"rmtree {path}!!!") + def __apply_delete(self, path: Path, dry_run): + if not path.is_symlink() and path.is_dir(): + print(f"rmtree {path}") if not dry_run: shutil.rmtree(str(path)) else: @@ -41,17 +45,20 @@ class Writer: if not dry_run: path.unlink() - def apply_link(self, linkpath: Path, target: Path, dry_run): + def __apply_link(self, linkpath: Path, target: Path, dry_run): print(f"link {linkpath} -> {target}") if not dry_run: linkpath.symlink_to(target) def apply(self, dry_run=True): for d in self.delete_todo: - self.apply_delete(d, dry_run) + self.__apply_delete(d, dry_run) for d in self.dirs_todo: - self.apply_dir(d, dry_run) + self.__apply_dir(d, dry_run) for link, target in self.links_todo.items(): - self.apply_link(link, target, dry_run) + self.__apply_link(link, target, dry_run) + + for hook in self.apply_hook: + hook(dry_run) |