You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			81 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			81 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Python
		
	
#!/usr/bin/env python3
 | 
						|
 | 
						|
import os
 | 
						|
from os import path
 | 
						|
 | 
						|
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('~')
 | 
						|
 | 
						|
class ExistingFileError(OSError):
 | 
						|
    pass
 | 
						|
 | 
						|
class ExistingSymlinkError(OSError):
 | 
						|
    pass
 | 
						|
 | 
						|
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 walk_files(dot_files):
 | 
						|
        dot_file = path.join(dot_files, filename)
 | 
						|
        new_file = path.join(home_dir, '.' + filename)
 | 
						|
        link_to(dot_file, new_file)
 | 
						|
 | 
						|
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)
 | 
						|
 | 
						|
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()
 |