#!/usr/bin/env python3 import argparse import coloredlogs import logging import os import sys coloredlogs.install(level="DEBUG", fmt="%(levelname)s %(message)s") log = logging.getLogger() # Coding conventions: # No leading or trailing slashes. Let os.path.join do its job # TODO Config arparse and pass args to the functions. No globals # Finding directories assert "HOME" in os.environ, "Home directory unknown" DOCS = os.path.realpath(os.path.join(os.environ["HOME"], "Documents")) assert os.path.isdir(DOCS), "Documents folder not found" ARCS = os.path.realpath(os.path.join(os.environ["HOME"], "Archives")) assert os.path.isdir(ARCS), "Archives folder not found" def dirRange(relpath): splits = relpath.split(os.path.sep) res = list() for p in range(len(splits)): partPath = os.path.join(*splits[: p + 1]) arcPath = os.path.join(os.path.join(ARCS, partPath)) docPath = os.path.join(os.path.join(DOCS, partPath)) res.append((docPath, arcPath)) return res def travel(relpath): """ Dunno what this will do, let's write code and see. """ wholeRange = dirRange(relpath) for tup in wholeRange: isLast = wholeRange[-1] == tup docPath, arcPath = tup linkPath = os.path.relpath(arcPath, start=docPath) log.debug(f"47 {tup}") if not os.path.exists(docPath) and not os.path.exists(arcPath): log.error("Not existing") sys.exit(1) elif os.path.isdir(docPath) and os.path.isdir(arcPath) and not isLast: log.debug("Both folder") continue elif os.path.isdir(docPath) and os.path.isdir(arcPath) and isLast: log.error("This should fail for some reason, maybe") sys.exit(1) elif os.path.islink(docPath) and os.path.exists(arcPath): currentLink = os.readlink(docPath) if currentLink != linkPath: log.warning( f"'{docPath}' is pointing to '{currentLink}' " + f"but should point to '{linkPath}'." ) # TODO Fixing if asked for sys.exit(1) log.debug("Early link already exists {docPath} → {arcPath}") return elif not os.path.exists(docPath) and os.path.exists(arcPath): log.debug("Only existing on archive side, linking") print(f"ln -s {linkPath} {docPath}") elif os.path.exists(docPath) and not os.path.exists(arcPath) and isLast: log.debug("Only existing on doc side, moving and linking") print(f"mv {docPath} {arcPath}") print(f"ln -s {linkPath} {docPath}") elif os.path.exists(docPath) and not os.path.exists(arcPath) and not isLast: raise NotImplementedError("Here comes the trouble") else: log.error("Unhandled case") sys.exit(1) def ensureLink(relpath): """ Ensure that ~/Documents/$relpath points to ~/Archives/$relpath """ arcPath = os.path.join(os.path.join(ARCS, relpath)) docPath = os.path.join(os.path.join(DOCS, relpath)) assert os.path.exists(arcPath) # For each tree element of the path for docPath, arcPath in dirRange(relpath): linkPath = os.path.relpath(arcPath, start=docPath) def installLink(): if args.dry: print(f"ln -s {linkPath} {docPath}") else: os.symlink(linkPath, docPath) if os.path.islink(docPath): currentLink = os.readlink(docPath) if currentLink != linkPath: log.warning( f"'{docPath}' is pointing to '{currentLink}' " + f"but should point to '{linkPath}'. Fixing" ) if args.dry: print(f"rm {docPath}") else: os.unlink(docPath) installLink() return elif not os.path.exists(docPath): installLink() return elif os.path.isdir(docPath): continue else: raise RuntimeError( f"'{docPath}' exists and is not a directory " + f"or a link. Unable to link it to '{linkPath}'" ) raise RuntimeError( f"'{docPath}' is a directory. Unable to link it to " + f"'{linkPath}'" ) def archive(docdir): docdir = os.path.realpath(args.dir) assert os.path.isdir(docdir), docdir + " must be a directory" assert docdir.startswith(DOCS), "Directory is not in the document folder" assert not docdir.startswith(ARCS), "Directory is already in the archive folder" reldir = os.path.relpath(docdir, DOCS) print("ARC", reldir) arcdir = os.path.join(ARCS, reldir) parentArcdir = os.path.realpath(os.path.join(arcdir, "..")) parentDocdir = os.path.realpath(os.path.join(docdir, "..")) linkDest = os.path.relpath(arcdir, parentDocdir) # BULLSHIT # If the directory exists if os.path.isdir(arcdir): return # for f in os.listdir(arcdir): # assert os.path.isdir(f), "Something unknown in Archive dir") # archive(os.path.join(arcdir, f)) # If the directory doesn't exist, create the directories under it and move all the folder else: if args.dry: print("mkdir -p", parentArcdir) else: os.makedirs(parentArcdir, exist_ok=True) if args.dry: print("mv", docdir, arcdir) else: os.rename(docdir, arcdir) if args.dry: print("ln -s", linkDest, docdir) else: os.symlink(linkDest, docdir) def unarchive(arcdir): pass if __name__ == "__main__": parser = argparse.ArgumentParser( description="Place a folder in ~/Documents in ~/Documents/Archives and symlink it" ) parser.add_argument( "dir", metavar="DIRECTORY", type=str, help="The directory to archive" ) parser.add_argument("-d", "--dry", action="store_true") args = parser.parse_args() args.dry = True # DEBUG # archive(args.dir) ensureLink(args.dir)