Initial commit and creation of setup script
This commit is contained in:
commit
cd67a505db
10 changed files with 2041 additions and 0 deletions
86
setup_dotfiles.py
Executable file
86
setup_dotfiles.py
Executable file
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Syncronizes dotfiles from a source dir that mimics a homedir tree to a homedir,
|
||||
removing old symlinks as necessary as well as optionally files.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
FORCE = False
|
||||
HOMEDIR = os.path.expanduser("~")
|
||||
SOURCEDIR = os.path.dirname(os.path.join(os.path.realpath(__file__)))
|
||||
|
||||
EXCLUSIONS = [
|
||||
".git",
|
||||
"setup_dotfiles.py",
|
||||
"README.md"
|
||||
]
|
||||
|
||||
def check_and_remove(source, destination, force=False):
|
||||
"""
|
||||
Checks if a file exists and removes it if appropriate.
|
||||
|
||||
If it's a symlink we check it points the right place and remove it if not.
|
||||
|
||||
If it's a file, we remove it if --force is provided, or error if not.
|
||||
|
||||
If we need to re-deply the symlink, return True, else return False.
|
||||
"""
|
||||
pathlib.Path(os.path.dirname(destination)).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Destination exists as a symlink
|
||||
if os.path.islink(destination):
|
||||
# Symlink is correct, return
|
||||
if os.readlink(destination) == source:
|
||||
return False
|
||||
# Symlink is incorrect, remove it
|
||||
os.unlink(destination)
|
||||
# Destination exists as a file
|
||||
elif os.path.exists(destination):
|
||||
# Force mode enabled, remove it (Data loss risk!!)
|
||||
if force:
|
||||
os.remove(destination)
|
||||
# Force mode diseabled, error out
|
||||
else:
|
||||
raise OSError(f"{destination} exists as a file and --force not provided")
|
||||
|
||||
# File doesn't exists or undefined "thing" happened, return True to try to
|
||||
# write, and if something goes wrong, we'll see the OSError
|
||||
return True
|
||||
|
||||
|
||||
def install_dotfiles(source_dir, dest_dir, exclusions, force=False):
|
||||
"""
|
||||
Iterates the files present in source_dir, excluding EXCLUSIONS, and syncs
|
||||
them to dest_dir, overwriting files that exist if force is true.
|
||||
"""
|
||||
# source_dir needs to end in an / to make replacements work
|
||||
if not source_dir.endswith("/"):
|
||||
source_dir = source_dir + "/"
|
||||
|
||||
for root, dir_names, file_names in os.walk(source_dir):
|
||||
# Remove exclusions from the walk list so we don't touch them
|
||||
for exclusion in exclusions:
|
||||
if exclusion in dir_names:
|
||||
dir_names.remove(exclusion)
|
||||
if exclusion in file_names:
|
||||
file_names.remove(exclusion)
|
||||
|
||||
for file_name in file_names:
|
||||
# Get the full path for the source file
|
||||
source = os.path.join(root, file_name)
|
||||
|
||||
# Get the full path for where the symlink should go
|
||||
# We remove the source_dir to get a dotfile dir relative path
|
||||
destination = os.path.join(dest_dir, source.replace(source_dir, ''))
|
||||
|
||||
# Check for and remove the destination file if it exists
|
||||
# If a removal occurs, catch True and deploy the symlink
|
||||
if check_and_remove(source, destination, force):
|
||||
print(f"Symlinking {source} => {destination}")
|
||||
os.symlink(source, destination)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
install_dotfiles(SOURCEDIR, HOMEDIR, EXCLUSIONS, False)
|
Loading…
Add table
Add a link
Reference in a new issue