rewrite autolink script

Finally updated script to python3. Changed how the script works.
The old version made a symlink for each directory in the dot-files.
The new version:
 • makes directories for each folder in the dot-files in home directory
   • a folder [dot-files]/foo/bar will make folder ~/.foo/bar
 • makes symlinks for each file in the dot-files
   • a file [dot-files]/foo/bar/baz will make symlink
    ~/.foo/bar/baz → [dot-files]/foo/bar/baz
This commit is contained in:
Buddy Sandidge 2018-08-21 01:35:21 -07:00
parent 4a7f7bd422
commit b2e14a89f5
2 changed files with 68 additions and 50 deletions

118
autolink
View File

@ -1,62 +1,80 @@
#!/usr/bin/env python2
"""
A simple script to create a symlinks in your home directory for every filename
in this directory.
#!/usr/bin/env python3
For example:
~/.bashrc -> dot-files/bashrc
"""
import os
from os import path
from os import getcwd, listdir, getenv, symlink, remove
from os.path import (dirname, basename, join, expanduser, lexists, exists,
relpath, normpath, isfile, islink, realpath, abspath)
SCRIPT_ABS_PATH = path.abspath(__file__)
SCRIPT_NAME = path.basename(SCRIPT_ABS_PATH)
DOT_FILES_DIR = path.dirname(SCRIPT_ABS_PATH)
HOME_DIR = path.expanduser('~')
def log(filename, message):
"""Simple logging function"""
name = "'{0}':".format(filename).ljust(30, ' ')
print "{0}\t{0}".format(name, message)
class ExistingFileError(OSError):
pass
def dir_filter(file_name):
return file_name != basename(__file__) and \
file_name != 'README.md' and \
file_name[0] != '.'
class ExistingSymlinkError(OSError):
pass
def main():
"""Create the symlinks"""
dir_path = dirname(__file__)
base_name = dirname(normpath(join(getenv('PWD'), __file__)))
home_dir = expanduser('~')
rel_path = normpath(relpath(base_name, home_dir))
def main(*, dot_files=DOT_FILES_DIR, home_dir=HOME_DIR):
for directory in walk_directories(dot_files):
hidden_dir = path.join(home_dir, '.' + directory)
make_directory(hidden_dir)
for filename in filter(dir_filter, listdir(dirname(abspath(__file__)))):
config_path = join(home_dir, ".{0}".format(filename))
file_path = join(rel_path, filename)
for filename in walk_files(dot_files):
dot_file = path.join(dot_files, filename)
new_file = path.join(home_dir, '.' + filename)
link_to(dot_file, new_file)
# If the current file is going to be linked deeper in the
# home directory, for example, we want to link
# `~/.ssh/config` instead of the whole `~/.ssh` directory.
if filename[0] == '_':
deep_dirs = filename[1:].split('_')
link_file = deep_dirs[-1]
dir_name = join(*deep_dirs[:-1])
config_path = join(home_dir, ".{0}".format(dir_name), link_file)
file_path = join("..", file_path)
if lexists(config_path):
if not exists(config_path):
# If it does not exists but lexists is true, that means this
# is a broken symlink
remove(config_path)
elif islink(config_path):
if realpath(config_path) != file_path:
continue
elif isfile(config_path):
log(config_path, 'existing file, consider merge')
def walk_directories(directory):
visited = set()
for root, dirs, _ in os.walk(directory):
for d in (path.join(root, d) for d in dirs):
rel_dir = path.join(root, d).replace(directory + os.sep, '')
if rel_dir in visited:
continue
if path_contains(rel_dir, '.git'):
continue
yield rel_dir
visited.add(rel_dir)
log(config_path, "now linking to '{0}'".format(file_path))
symlink(file_path, config_path)
def walk_files(directory):
visited = set()
for root, _, files in os.walk(directory):
for f in (path.join(root, f) for f in files if not f.startswith('.')):
relative_file = path.join(root, f).replace(directory + os.sep, '')
if relative_file in visited:
continue
if path_contains(relative_file, '.git', 'README.md', SCRIPT_NAME):
continue
yield relative_file
visited.add(relative_file)
def make_directory(directory):
if path.isdir(directory):
return
if path.exists(directory):
raise ExistingFileError('expected no file or directory: {0}'.format(directory))
os.mkdir(directory, mode=0o755)
def link_to(src, dest):
if path.islink(dest):
if path.realpath(src) == path.realpath(dest):
return
if path.exists(dest):
raise ExistingSymlinkError('found unexpected symlink: {0}'.format(dest))
# we have a broken symlink, remove it
os.remove(dest)
if path.isfile(dest):
raise ExistingSymlinkError('found unexpected file: {0}'.format(dest))
src_rel = path.relpath(src, start=path.dirname(dest))
dir_fd = os.open(path.dirname(dest), os.O_RDONLY)
os.symlink(src_rel, dest, dir_fd=dir_fd)
def path_contains(directory, *strings):
directories = directory.split(os.sep)
for s in strings:
if s in directories:
return True
return False
if __name__ == '__main__':
main()