dotfm

My dotfile manager
git clone git://src.gearsix.net/dotfm
Log | Files | Refs | Atom | README | LICENSE

commit a7e52bbd9d0f10445adc0b091fc70a89fbc7c3c9
Author: GeaRSiX <gearsix@tuta.io>
Date:   Thu, 30 Jan 2020 18:53:59 +0000

initial dev work; Makefile for install/uninstall

Diffstat:
AMakefile | 16++++++++++++++++
Asrc/dotfm.py | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 167 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,16 @@ +DESTDIR=/usr/bin +NAME=dotfm + +all: none + +none: + @echo 'nothing to do, just run "make install", or "make uninstall"' + +install: + install -vpDm755 src/${NAME}.py ${DESTDIR}/${NAME} + + +uninstall: + rm -f ${DESTDIR}/${NAME} + +.PHONY: all none install uninstall diff --git a/src/dotfm.py b/src/dotfm.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 + +#========================== +# dotfm - dot file manager +#========================== +# authors: gearsix +# created: 2020-01-15 +# updated: 2020-01-23 +# notes: +# - install: when new config location is set, modify binary with --config argument + +#--------- +# IMPORTS +#--------- +import sys +import os +import logging +import argparse +import configparser +import csv + +#--------- +# GLOBALS +#--------- +NAME = os.path.basename(__file__) # program name +USER = os.getenv('USER') # $USER calling dotfm +ARGS = sys.argv # parsed arguments +EDITOR = os.getenv('EDITOR') or 'nano' # text editor to modify dotfiles with +VERSION = 'v1.0.0' +DOTFILE_LOCATIONS = [ # recognised dotfile names & locations + # filename # location + ['.bashrc', '/home/$USER/'], + ['.profile', '/home/$USER/'], + ['.bash_profile', '/home/$USER/'], + ['.vim', '/home/$USER/'], + ['init.vim', '/home/$USER/.config/nvim'], + ['.tmux.conf', '/home/$USER/'], + ['user-dirs.dirs', '/home/$USER/.config/'], +] +SOURCE_DOTFILES = [ # dotfiles that need to be "source"-ed after editing + '.bashrc', + '.profile', + '.bash_profile', +] + +#----------- +# FUNCTIONS +#----------- +def error_exit(message): + LOGGER.error(message) + print('ERROR!\t| {}'.format(message)) + sys.exit() + +def parse_arguments(): + global ARGS + valid_commands = ['install', 'remove', 'edit', 'install-all'] + + parser = argparse.ArgumentParser(description='a simple tool to help you manage your dot files, see \"man dotfm\" for more') + parser.add_argument('cmd', metavar='COMMAND', choices=valid_commands, help='the dotfm COMMAND to execute: {}'.format(valid_commands)) + parser.add_argument('dotfile', metavar='DOTFILE', help='name of the dotfile dotfm will execute COMMAND on, for \"install\" this must be a path to the dotfile to install') + parser.add_argument('-d', '--debug', action='store_true', help='display debug logs') + parser.add_argument('-v', '--version', action='version', version='%(prog)s {}'.format(VERSION)) + ARGS = parser.parse_args() + +def validate_dotfile_path(dotfile, dotfile_path): + if not os.path.exists(dotfile_path): + error_exit('DOTFILE \"{}\" ({}) not found'.format(dotfile, dotfile_path)) + if not os.path.isfile(dotfile_path): + error_exit('DOTFILE \"{}\" ({}) should be a file, not a dir'.format(dotfile, dotfile_path)) + +def validate_dotfiledir_path(dirname, dotfiledir_path): + if not os.path.exists(dotfiledir_path): + error_exist('DOTFILE DIRECTORY \"{}\" ({}) not found'.format(dotfile, dotfiledir_path)) + if not os.path.isdir(dotfiledir_path): + error_exit('DOTFILE DIRECTORY \"{}\" ({}) is not a directory'.format(dotfile, dotfiledir_path)) + +def dotfm_install(dotfile): + LOGGER.info('installing {}...'.format(dotfile)) + + for dfl in DOTFILE_LOCATIONS: + name = dfl[0] + if os.path.basename(dotfile) == name: + dest = os.path.abspath(os.path.dirname(dfl[1])) + if not os.path.exists(dest): + os.system('mkdir -vp {}'.format(dest)) + os.system('ln -vfs {} {}'.format(dotfile, dest)) + if name in SOURCE_DOTFILES: + os.system('source {}/{}'.format(dest, name)) + +def dotfm_installall(dotfile_dir): + LOGGER.info('installing all dotfiles in {}'.format(dotfile)) + + for df in os.listdir(os.path.abspath(dotfile_dir)): + df = os.path.abspath('{}/{}'.format(dotfile_dir, df)) + LOGGER.debug('found {}'.format(df)) + if os.path.isfile(df): + dotfm_install(df) + elif os.path.isdir(df): + LOGGER.debug('found dir {}') + dotfm_installall(df) + +def dotfm_remove(dotfile): + LOGGER.info('removing {}...'.format(dotfile)) + + for dfl in DOTFILE_LOCATIONS: + name = dfl[0] + if os.path.basename(dotfile) == name: + target = '{}/{}'.format(os.path.abspath(os.path.dirname(dfl[1])), name) + os.system('rm -v {}'.format(target)) + +def dotfm_edit(dotfile): + LOGGER.info('editing {}...'.format(dotfile)) + + target = '' + for dfl in DOTFILE_LOCATIONS: + name = dfl[0] + if os.path.basename(dotfile) == name: + target = '{}/{}'.format(os.path.abspath(os.path.dirname(dfl[1])), name) + os.system('{} {}'.format(EDITOR, target)) + + if target == '': + error_exit('could not find {} in DOTFILE_LOCATIONS'.format(os.path.basename(dotfile))) + +#------ +# MAIN +#------ +if __name__ == '__main__': + parse_arguments() + command = ARGS.cmd + dotfile = ARGS.dotfile + + if ARGS.debug == True: + logging.basicConfig(level=logging.DEBUG, format='%(lineno)-4s {} | %(asctime)s | %(levelname)-7s | %(message)s'.format(NAME)) + LOGGER = logging.getLogger(__name__) + LOGGER.debug('displaying debug logs') + else: + logging.basicConfig(level=logging.INFO, format='%(lineno)-4s {} | %(asctime)s | %(levelname)-7s | %(message)s'.format(NAME)) + LOGGER = logging.getLogger(__name__) + + + if command == 'install': + validate_dotfile_path(dotfile, os.path.abspath(dotfile)) + dotfm_install(os.path.abspath(dotfile)) + elif command == 'remove': + validate_dotfile_path(dotfile) + dotfm_remove(os.path.abspath(dotfile)) + elif command == 'edit': + dotfm_edit(os.path.abspath(dotfile)) + elif command == 'install-all': + validate_dotfiledir_path(dotfile, os.path.abspath(dotfile)) + dotfm_installall(os.path.abspath(dotfile))