Support DOTFILEMANAGER_HOSTNAME environment variable.

Fix bug with relative paths: always convert paths retrieved from the
command line args or from reading a link to absolute paths and expand
~'s.

Silence some print statements unless doing the report action.

Delete an unnecessary `path = os.path.join(to_dir,filename)` line.
This commit is contained in:
Sean Hammond 2010-03-07 23:26:18 +00:00
parent e2fce1a2fb
commit 24c0732753

View File

@ -40,7 +40,7 @@ linked to. On other hosts _muttrc will be linked to.
(To discover the hostname of your machine run `uname -n`.) (To discover the hostname of your machine run `uname -n`.)
`dotfilemanager tidy` will remove any dangling symlinks in FROM_DIR, and `dotfilemanager tidy` will remove any dangling symlinks in FROM_DIR, and
`dotfilemanager report` will just report on what link or tidy would do `dotfilemanager report` will just report on what link and tidy would do
without actually making any changes to the filesystem. without actually making any changes to the filesystem.
Tip: handle directories like ~/.config separately Tip: handle directories like ~/.config separately
@ -65,20 +65,24 @@ commands:
dotfilemanager.py link ~ ~/.dotfiles dotfilemanager.py link ~ ~/.dotfiles
dotfilemanager.py link ~/.config ~/config dotfilemanager.py link ~/.config ~/config
TODO Tip: override hostname with DOTFILEMANAGER_HOSTNAME environment variable
---- ------------------------------------------------------------------------
Support hostname as a command-line argument, overriding the system If the DOTFILEMANAGER_HOSTNAME environment variable is set then it is used
hostname. This might be useful for accounts on networked systems where instead of your real hostname to resolve hostname-specific files in TO_DIR.
you login to the same user account from different computers, the system This is useful for accounts on networked systems where you login to the same
hostname will be different each time you switch computers but you want user account from different computers, the system hostname will be different
to use the same config files whenever you login to this account. So just each time you switch computers but you want to use the same config files
make up a name for the account and pass it as a command-line argument whenever you login to this account. So just make up a name for the account and
overriding the system hostname. set it as the value of DOTFILEMANAGER_HOSTNAME.
""" """
import os,sys,platform import os,sys,platform
# TODO: allow setting hostname as a command-line argument also?
try:
HOSTNAME = os.environ['DOTFILEMANAGER_HOSTNAME']
except KeyError:
HOSTNAME = platform.node() HOSTNAME = platform.node()
HOSTNAME_SEPARATOR = '__' HOSTNAME_SEPARATOR = '__'
@ -97,9 +101,7 @@ def tidy(d,report=False):
path = os.path.join(d,f) path = os.path.join(d,f)
if os.path.islink(path): if os.path.islink(path):
target_path = os.readlink(path) target_path = os.readlink(path)
if not os.path.isabs(target_path): target_path = os.path.abspath(os.path.expanduser(target_path))
# This is a relative symlink, resolve it.
target_path = os.path.join(os.path.dirname(path),target_path)
if not os.path.exists(target_path): if not os.path.exists(target_path):
# This is a broken symlink. # This is a broken symlink.
if report: if report:
@ -108,7 +110,7 @@ def tidy(d,report=False):
print 'Deleting broken symlink: %s->%s' % (path,target_path) print 'Deleting broken symlink: %s->%s' % (path,target_path)
os.remove(path) os.remove(path)
def get_target_paths(to_dir): def get_target_paths(to_dir,report=False):
"""Return the list of absolute paths to link to for a given to_dir. """Return the list of absolute paths to link to for a given to_dir.
This handles skipping various types of filename in to_dir and This handles skipping various types of filename in to_dir and
@ -120,12 +122,15 @@ def get_target_paths(to_dir):
for filename in filenames: for filename in filenames:
path = os.path.join(to_dir,filename) path = os.path.join(to_dir,filename)
if filename.endswith('~'): if filename.endswith('~'):
if report:
print 'Skipping %s' % filename print 'Skipping %s' % filename
continue continue
elif (not os.path.isfile(path)) and (not os.path.isdir(path)): elif (not os.path.isfile(path)) and (not os.path.isdir(path)):
if report:
print 'Skipping %s (not a file or directory)' % filename print 'Skipping %s (not a file or directory)' % filename
continue continue
elif filename.startswith('.'): elif filename.startswith('.'):
if report:
print 'Skipping %s (filename has a leading dot)' % filename print 'Skipping %s (filename has a leading dot)' % filename
continue continue
else: else:
@ -136,15 +141,16 @@ def get_target_paths(to_dir):
# link to it. # link to it.
hostname = filename.split(HOSTNAME_SEPARATOR)[-1] hostname = filename.split(HOSTNAME_SEPARATOR)[-1]
if hostname == HOSTNAME: if hostname == HOSTNAME:
path = os.path.join(to_dir,filename)
paths.append(path) paths.append(path)
else: else:
if report:
print 'Skipping %s (different hostname)' % filename print 'Skipping %s (different hostname)' % filename
continue continue
else: else:
# This appears to be a filename without a trailing # This appears to be a filename without a trailing
# hostname. # hostname.
if filename + HOSTNAME_SEPARATOR + HOSTNAME in filenames: if filename + HOSTNAME_SEPARATOR + HOSTNAME in filenames:
if report:
print 'Skipping %s (there is a host-specific version of this file for this host)' % filename print 'Skipping %s (there is a host-specific version of this file for this host)' % filename
continue continue
else: else:
@ -170,7 +176,7 @@ def link(from_dir,to_dir,report=False):
""" """
# The paths in to_dir that we will be symlinking to. # The paths in to_dir that we will be symlinking to.
to_paths = get_target_paths(to_dir) to_paths = get_target_paths(to_dir,report)
# Dictionary of symlinks we will be creating, from_path->to_path # Dictionary of symlinks we will be creating, from_path->to_path
symlinks = {} symlinks = {}
@ -194,6 +200,7 @@ def link(from_dir,to_dir,report=False):
if os.path.islink(from_path): if os.path.islink(from_path):
# A link already exists. # A link already exists.
existing_to_path = os.readlink(from_path) existing_to_path = os.readlink(from_path)
existing_to_path = os.path.abspath(os.path.expanduser(existing_to_path))
if existing_to_path == to_path: if existing_to_path == to_path:
# It's already a link to the intended target. All is # It's already a link to the intended target. All is
# well. # well.
@ -237,7 +244,7 @@ if __name__ == "__main__":
try: try:
FROM_DIR = sys.argv[2] FROM_DIR = sys.argv[2]
except IndexError: except IndexError:
FROM_DIR = os.path.expanduser('~') FROM_DIR = '~'
if not os.path.isdir(FROM_DIR): if not os.path.isdir(FROM_DIR):
print "FROM_DIR %s is not a directory!" % FROM_DIR print "FROM_DIR %s is not a directory!" % FROM_DIR
print usage() print usage()
@ -245,12 +252,15 @@ if __name__ == "__main__":
try: try:
TO_DIR = sys.argv[3] TO_DIR = sys.argv[3]
except IndexError: except IndexError:
TO_DIR = os.path.join(os.path.expanduser('~'),'.dotfiles') TO_DIR = os.path.join('~','.dotfiles')
if not os.path.isdir(TO_DIR): if not os.path.isdir(TO_DIR):
print "TO_DIR %s is not a directory!" % TO_DIR print "TO_DIR %s is not a directory!" % TO_DIR
print usage() print usage()
sys.exit(2) sys.exit(2)
TO_DIR = os.path.abspath(os.path.expanduser(TO_DIR))
FROM_DIR = os.path.abspath(os.path.expanduser(FROM_DIR))
if ACTION == 'link': if ACTION == 'link':
link(FROM_DIR,TO_DIR) link(FROM_DIR,TO_DIR)
elif ACTION == 'tidy': elif ACTION == 'tidy':