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:
parent
4a7f7bd422
commit
b2e14a89f5
118
autolink
118
autolink
@ -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()
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user