summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apply/__main__.py7
-rw-r--r--[-rwxr-xr-x]apply/apply_cmd.py (renamed from apply/apply.py)24
-rw-r--r--apply/remove_cmd.py35
-rw-r--r--apply/resolv.py20
-rw-r--r--apply/state.py55
-rw-r--r--apply/status_cmd.py (renamed from apply/status.py)0
-rw-r--r--apply/writer.py23
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)