From 4b1a8982664434c1aa187a428685f63ff8747c99 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Thu, 8 Nov 2012 18:21:12 -0800 Subject: Progress on setup.py. Add README file. --- README.txt | 28 ++++++++++++++++++++++++++++ setup.py | 23 +++++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 README.txt diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..5b86774 --- /dev/null +++ b/README.txt @@ -0,0 +1,28 @@ +dotfiles +================================================================================ + +This is my collection of dotfiles. They are organized like this: + +base/ Files I want on every host. +host-overrides/ + jesterpm.net/ These files override those in base/ on hosts + with domains ending in jesterpm.net + + host-specific/ Files in this directory are typically + sourced from files in base to provide + host (or domain) specific extensions. + + bismuth.jesterpm.net/ These files override those in jesterpm.net/ + on bismuth.jesterpm.net in + +setup.py A script to setup links to the dot files. + + +setup.py +------------------------------------------------------------------------------- +The setup scripts makes the following links: + + * For every file X in base/, ~/.X is linked to base/X + +If a file already exists, it is deleted unless the --nice flag is given. + diff --git a/setup.py b/setup.py index 9c4e9a5..412afc9 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ class Usage(Exception): self.msg = msg """ Create links to dotfiles """ -def makeDots(home, nice): +def makeDots(home, nice = False, pretend = False): # First make a map of dot files to files in the repository. dotfiles = getMap("base/") @@ -30,7 +30,26 @@ def makeDots(home, nice): hostname = socket.getfqdn().split(".") for i in range(len(hostname)): name = string.join(hostname[-(i+1):], ".") - dotfiles = getMap("host-overrides/" + name, dotfiles) + dotfiles = dotfiles + getMap("host-overrides/" + name) + + if pretend: + print "I would make these links:" + else: + print "I am making these links:" + + for dst, src in dotfiles: + realDest = home + "/" + dst + if not pretend: + makeLink(src, realDest, nice) + + print "%s/.%s => %s" % (home, dst, src) + +def getMap(directory): + dots = dict() + for filename in LISTOFFILES: + if FILEXISTS: # directory + "/" + filename + "/.nolink" + dots += getChildMap(directory, filename) + dots["." + filename] = directory + "/" + filename -- cgit v1.2.3 From db166dafdfc91945828ec7c57f7369744898210c Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Thu, 8 Nov 2012 19:54:20 -0800 Subject: Just about finished setup.py --- setup.py | 53 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index 412afc9..14f4d0e 100644 --- a/setup.py +++ b/setup.py @@ -15,6 +15,7 @@ Usage: python setup.py [--nice] [--home=DIRECTORY] """ import os, sys, getopt, socket +import shutil import string class Usage(Exception): @@ -38,19 +39,55 @@ def makeDots(home, nice = False, pretend = False): print "I am making these links:" for dst, src in dotfiles: - realDest = home + "/" + dst + realDest = home + "/." + dst + success = True if not pretend: - makeLink(src, realDest, nice) + success = makeLink(src, realDest, nice) - print "%s/.%s => %s" % (home, dst, src) + if success: + print "%s => %s" % (realDest, dst, src) + else: + print "Not linking %s to %s because file exists" % (realDest, src) + +""" Return a map of dest => source dotfiles """ +def getMap(baseDirectory, directory=""): + if baseDirectory[-1] != "/": + baseDirectory = baseDirectory + "/" + + if directory != "" and directory[-1] != "/": + directory = directory + "/" -def getMap(directory): dots = dict() - for filename in LISTOFFILES: - if FILEXISTS: # directory + "/" + filename + "/.nolink" - dots += getChildMap(directory, filename) - dots["." + filename] = directory + "/" + filename + for filename in os.listdir(baseDirectory + directory): + if filename == ".nolink": + continue + + fullPath = baseDirectory + directory + filename + + if os.path.isdir(fullPath) and os.path.exists(fullPath + "/.nolink"): + # We will not make a link but will make sure this directory exists. + dots[directory + filename] = "" + dots += getMap(baseDirectory, directory + filename) + + else: + dots[directory + filename] = fullPath + +""" Make a link from src to realDest. + If nice is true, don't overwrite realDest. + If src is an empty string, just create a directory. """ +def makeLink(src, realDest, nice = False): + if os.path.exists(realDest): + if nice: + return False + else: + shutil.rmtree(realDest) + + if src == "": + os.mkdir(realDest) + + os.symlink(src, realDest) + return True """ Main Method """ -- cgit v1.2.3 From 656ac195f1c55392f4bb0ffd5cab690f7bfa0877 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Thu, 8 Nov 2012 22:20:30 -0800 Subject: Script seems to work. Still need to add relative symlinks and fix file deletion. --- setup.py | 65 ++++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/setup.py b/setup.py index 14f4d0e..283e3aa 100644 --- a/setup.py +++ b/setup.py @@ -23,31 +23,47 @@ class Usage(Exception): self.msg = msg """ Create links to dotfiles """ -def makeDots(home, nice = False, pretend = False): +def makeDots(base, home, nice = False, pretend = False): # First make a map of dot files to files in the repository. - dotfiles = getMap("base/") + dotfiles = getMap(base + "/base/") # Get host specific overrides hostname = socket.getfqdn().split(".") for i in range(len(hostname)): name = string.join(hostname[-(i+1):], ".") - dotfiles = dotfiles + getMap("host-overrides/" + name) + directory = base + "/host-overrides/" + name + if os.path.isdir(directory): + mergeDicts(dotfiles, getMap(directory)) if pretend: print "I would make these links:" else: print "I am making these links:" - for dst, src in dotfiles: - realDest = home + "/." + dst - success = True - if not pretend: - success = makeLink(src, realDest, nice) + makeLinks(dotfiles, home + "/.", nice, pretend) + +def makeLinks(dotfiles, prefix, nice, pretend): + keys = dotfiles.keys() + keys.sort() + for dst in keys: + src = dotfiles[dst] + realDest = prefix + dst + + if type(src) is dict: + if not pretend: + os.mkdir(realDest) + print "%50s => " % (realDest) + makeLinks(src, realDest + "/", nice, pretend) - if success: - print "%s => %s" % (realDest, dst, src) else: - print "Not linking %s to %s because file exists" % (realDest, src) + success = True + if not pretend: + success = makeLink(src, realDest, nice) + + if success: + print "%50s => %s" % (realDest, src) + else: + print "Not linking %s to %s because file exists" % (realDest, src) """ Return a map of dest => source dotfiles """ def getMap(baseDirectory, directory=""): @@ -66,29 +82,34 @@ def getMap(baseDirectory, directory=""): if os.path.isdir(fullPath) and os.path.exists(fullPath + "/.nolink"): # We will not make a link but will make sure this directory exists. - dots[directory + filename] = "" - dots += getMap(baseDirectory, directory + filename) + dots[directory + filename] = getMap(baseDirectory + directory + filename) else: dots[directory + filename] = fullPath + return dots + """ Make a link from src to realDest. If nice is true, don't overwrite realDest. If src is an empty string, just create a directory. """ def makeLink(src, realDest, nice = False): - if os.path.exists(realDest): + if os.path.lexists(realDest): if nice: return False else: shutil.rmtree(realDest) - if src == "": - os.mkdir(realDest) - os.symlink(src, realDest) return True +""" Recursively merge the second dictionary into the first. The latter takes precedence.""" +def mergeDicts(a, b): + for key, value in b.items(): + if key in a and type(value) is dict and type(a[key]) is dict: + mergeDicts(a[key], value) + else: + a[key] = value """ Main Method """ def main(argv=None): @@ -97,12 +118,13 @@ def main(argv=None): try: try: opts, args = getopt.getopt(argv[1:], - "hnd", ["help", "nice", "home"]) + "hnd:p", ["help", "nice", "home=", "pretend"]) except getopt.error, msg: raise Usage(msg) # Settings: nice = False + pretend = False home = os.environ["HOME"] for o, a in opts: @@ -113,10 +135,13 @@ def main(argv=None): if o in ("-n", "--nice"): nice = True - else if o in ("-d", "--home"): + elif o in ("-p", "--pretend"): + pretend = True + + elif o in ("-d", "--home"): home = a - makeDots(home, nice) + makeDots(os.getcwd(), home, nice, pretend) except Usage, err: print >>sys.stderr, err.msg -- cgit v1.2.3 From 2752587bd634246eba719c7fba2aa05fd30e38f7 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Fri, 9 Nov 2012 07:51:16 -0800 Subject: Directory creation fix. --- setup.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index 283e3aa..b1d2d47 100644 --- a/setup.py +++ b/setup.py @@ -50,20 +50,23 @@ def makeLinks(dotfiles, prefix, nice, pretend): realDest = prefix + dst if type(src) is dict: - if not pretend: - os.mkdir(realDest) - print "%50s => " % (realDest) - makeLinks(src, realDest + "/", nice, pretend) + try: + if not pretend and not os.path.isdir(realDest): + os.mkdir(realDest) + print "%50s => " % (realDest) + makeLinks(src, realDest + "/", nice, pretend) + except OSError,e: + print "Could not mkdir %s. Will not link subitems: %s" % (realDest, str(e)) else: - success = True - if not pretend: - success = makeLink(src, realDest, nice) + try: + if not pretend: + success = makeLink(src, realDest, nice) - if success: print "%50s => %s" % (realDest, src) - else: - print "Not linking %s to %s because file exists" % (realDest, src) + + except IOError,e + print "Not linking %s to %s because IOError: %s" % (realDest, src, str(e)) """ Return a map of dest => source dotfiles """ def getMap(baseDirectory, directory=""): -- cgit v1.2.3 From a7c3835854b77b9d258c6ebb323e41a42c35ae08 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Fri, 9 Nov 2012 08:05:41 -0800 Subject: setup.py seems to be functional --- setup.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index b1d2d47..6d72cac 100644 --- a/setup.py +++ b/setup.py @@ -51,8 +51,11 @@ def makeLinks(dotfiles, prefix, nice, pretend): if type(src) is dict: try: - if not pretend and not os.path.isdir(realDest): - os.mkdir(realDest) + if not pretend: + if os.path.islink(realDest): + os.unlink(realDest) # Only remove symlinks. Don't try to replace a file with a directory. + if not os.path.isdir(realDest): + os.mkdir(realDest) print "%50s => " % (realDest) makeLinks(src, realDest + "/", nice, pretend) except OSError,e: @@ -65,7 +68,7 @@ def makeLinks(dotfiles, prefix, nice, pretend): print "%50s => %s" % (realDest, src) - except IOError,e + except IOError,e: print "Not linking %s to %s because IOError: %s" % (realDest, src, str(e)) """ Return a map of dest => source dotfiles """ @@ -99,8 +102,10 @@ def makeLink(src, realDest, nice = False): if os.path.lexists(realDest): if nice: return False - else: + if os.path.isdir(realDest) and not os.path.islink(realDest): shutil.rmtree(realDest) + else: + os.unlink(realDest) os.symlink(src, realDest) -- cgit v1.2.3 From c58207b74254b29cae0888a2cd87618a9fecc62b Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Fri, 9 Nov 2012 08:09:15 -0800 Subject: Fixed setup.py mode --- setup.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 setup.py diff --git a/setup.py b/setup.py old mode 100644 new mode 100755 -- cgit v1.2.3 From 5c2d1528b81c4cc6d4018ea0b1d16dd98b14daa1 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Fri, 9 Nov 2012 08:19:11 -0800 Subject: Updated docstring --- setup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 6d72cac..0b65c44 100755 --- a/setup.py +++ b/setup.py @@ -9,8 +9,9 @@ create a better world. Usage: python setup.py [--nice] [--home=DIRECTORY] - --nice Don't trample existing dot files - --home=DIRECTORY Place links in DIRECTORY instead of $HOME + --nice Don't trample existing dot files. + --home=DIRECTORY Place links in DIRECTORY instead of $HOME. + --pretend Don't change anything, just say what would be done. """ -- cgit v1.2.3 From 173eab3c7370f4a35525c5949b8da44fab4ce841 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Fri, 9 Nov 2012 10:32:53 -0800 Subject: Updated README. Forced hostname to lowercase. --- README.txt | 31 ++++++++++++++++++++++++++----- setup.py | 2 +- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/README.txt b/README.txt index 5b86774..a1baaf5 100644 --- a/README.txt +++ b/README.txt @@ -13,16 +13,37 @@ host-overrides/ host (or domain) specific extensions. bismuth.jesterpm.net/ These files override those in jesterpm.net/ - on bismuth.jesterpm.net in + on bismuth.jesterpm.net. setup.py A script to setup links to the dot files. setup.py ------------------------------------------------------------------------------- -The setup scripts makes the following links: - - * For every file X in base/, ~/.X is linked to base/X -If a file already exists, it is deleted unless the --nice flag is given. +Usage: ./setup.py [--nice] [--pretend] [--home=DIRECTORY] + + --nice No destructive action. setup will not delete anything. + --pretend List the symlinks to make, but don't make them. + --home Place the links in DIRECTORY instead of $HOME. + +The setup script makes links from your home directory to the appropriate files +in the dotfiles repository. Unless --nice is specified, it will delete any +file that stands in its way. If it fails to make a link, it will report the +error and continue. + +Suppose your hostname was bismuth.jesterpm.net. The setup script will check +these directories for files in this order: + + * base/ + * host-overrides/net + * host-overrides/jesterpm.net + * host-overrides/bismuth.jesterpm.net + +Files found later supersede files found in previous directories, allowing you +to have specific files for specific hosts or domains. If the script finds a +directory and that directory contains a file called .nolink, then that +directory will be created in $HOME instead of linked, and the appropriate +links will be created inside that directory. This process continues +recursively. diff --git a/setup.py b/setup.py index 0b65c44..4f6cf0c 100755 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ def makeDots(base, home, nice = False, pretend = False): dotfiles = getMap(base + "/base/") # Get host specific overrides - hostname = socket.getfqdn().split(".") + hostname = socket.getfqdn().lower().split(".") for i in range(len(hostname)): name = string.join(hostname[-(i+1):], ".") directory = base + "/host-overrides/" + name -- cgit v1.2.3 From 4f2d90b74229a6aee0d179b8fee2c31a30666c99 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Fri, 23 Nov 2012 11:39:28 -0800 Subject: Change to skip over nested git repositories. --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index 4f6cf0c..00a7a51 100755 --- a/setup.py +++ b/setup.py @@ -84,6 +84,9 @@ def getMap(baseDirectory, directory=""): for filename in os.listdir(baseDirectory + directory): if filename == ".nolink": continue + + if filename == ".git": + continue # Skip over submodules. fullPath = baseDirectory + directory + filename -- cgit v1.2.3 From 2945ecf9cf217c7a462e52491bdf778aea617892 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Wed, 7 May 2014 08:21:26 -0700 Subject: Fixing exception if HOME is missing. --- setup.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 00a7a51..f075dcb 100755 --- a/setup.py +++ b/setup.py @@ -137,7 +137,7 @@ def main(argv=None): # Settings: nice = False pretend = False - home = os.environ["HOME"] + home = os.environ.get("HOME") for o, a in opts: if o in ("-h", "--help"): @@ -153,6 +153,9 @@ def main(argv=None): elif o in ("-d", "--home"): home = a + if not home: + raise Usage("No home provided") + makeDots(os.getcwd(), home, nice, pretend) except Usage, err: -- cgit v1.2.3 From 51e322fa92b973a0f45aa8bfd3d4c9a782c687a8 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Fri, 22 Mar 2013 13:40:03 -0700 Subject: Adding indicator for overwritten files. --- setup.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f075dcb..71f4fd2 100755 --- a/setup.py +++ b/setup.py @@ -64,10 +64,14 @@ def makeLinks(dotfiles, prefix, nice, pretend): else: try: + fileExists = os.path.lexists(realDest) if not pretend: success = makeLink(src, realDest, nice) - print "%50s => %s" % (realDest, src) + if fileExists: + print "%50s !=> %s" % (realDest, src) + else: + print "%50s => %s" % (realDest, src) except IOError,e: print "Not linking %s to %s because IOError: %s" % (realDest, src, str(e)) -- cgit v1.2.3