dotfm

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

commit e4cd4e1de1adc346f3a11d9a1d322bbf84146494
parent 903850faaa6a377ce75031b54171f7371bdd2ee3
Author: gearsix <gearsix@tuta.io>
Date:   Thu, 22 Apr 2021 13:11:44 +0100

2/? total refactor

Tidied update, moved some functions about to make them more reusable.

Diffstat:
Msrc/dotfm.py | 227++++++++++++++++++++++++++++++++++++++-----------------------------------------
1 file changed, 108 insertions(+), 119 deletions(-)

diff --git a/src/dotfm.py b/src/dotfm.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python #========================= # dotfm - dotfile manager @@ -96,6 +96,34 @@ def parseargs(): help='the target dotfile to execute COMMAND on') return parser.parse_args() +def writeinstalled(): + with open(INSTALLED_FILE, "w") as dotfm_csv_file: + dotfm_csv = csv.writer(dotfm_csv_file, lineterminator='\n') + for dfl in INSTALLED: + dotfm_csv.writerow(dfl) + dotfm_csv_file.close() + +def isdotfile(dotfile_list, query): + found = -1 + for d, dfl in enumerate(dotfile_list): + if query == dfl[0] or query == os.path.basename(dfl[0]): + found = 0 + for alias in dfl[1:]: + if query == alias: + found = d + break + if found != -1: + debug('dotfile {} matches known dotfile alias for {}', alias, dfl[0]) + break + +def clearduplicates(dotfile_list, id_index=0, keep_latest=True): + unique = [] + for d in data: + for i, u in enumerate(unique): + if d[id_index] == u[id_index]: + unique[i] = d # assume later entry = more recent + return unique + # main/init def init(): debug('init: loading dotfile locations') @@ -103,7 +131,7 @@ def init(): debug(INSTALLED_FILE, 'not found') init_createcsv() INSTALLED = init_loadcsv(INSTALLED_FILE) - INSTALLED = init_cleandups(INSTALLED, 0) + INSTALLED = clearduplicates(INSTALLED) def init_createcsv(default_location): location = default_location @@ -140,125 +168,86 @@ def init_loadcsv(location): dotfm_csv.close() return data -def init_cleandups(data, id_index): - unique = [] - for d in data: - for i, u in enumerate(unique): - if d[id_index] == u[id_index]: - unique[i] = d # assume later entry = more recent - return unique - # main/install -def dotfm_install(dotfile_source): - """ Check "KNOWN" to see if an alias matches "dotfile" basename, - if it does create a symbolic link from "dotfile" to the matching - "KNOWN" location (index 0). - - If file at matching "KNOWN" location exists, prompt user to - overwrite it. - - @param dotfile = filepath to the dotfile to install - """ - log_info('installing {}...'.format(dotfile_source)) - - # check if dotfile matches an alias in KNOWN - found = -1 - for d, dfl in enumerate(KNOWN): - for a, alias in enumerate(dfl[1:]): - if os.path.basename(dotfile_source) == alias: - found = d - - # prompt for location - dest = '' - if found != -1: - dest = os.path.abspath(KNOWN[found][0]) - if len(dest) == 0 or ARGS.skip == False: - default = dest - dest = '' - while dest == '': - dest = input('install location ({})? '.format('default: {}'.format(default) if len(default) > 0 else '')) - if len(dest) == 0 and len(default) > 0: - dest = default - elif dest.find('~') != -1: - dest = dest.replace('~', HOME) - # prompt for aliases - aliases = [] - if found != -1: - aliases = KNOWN[found][1:] - if len(aliases) == 0 or ARGS.skip == False: - default = aliases - aliases = [] - while len(aliases) == 0: - inp = input('aliases to call dotfile by ({})? '.format('default: {}'.format(default) if len(default) > 0 else '')) - if len(inp) > 0: - aliases = inp.split(' ') - elif len(default) > 0: - aliases = default - # make sure dotfile dir exists - if not os.path.exists(os.path.dirname(dest)): - os.system('mkdir -vp {}'.format(dest)) - # check if file already exists and prompt for action if it does - if os.path.lexists(dest): - oca = '' - while oca == '': - oca = input('{} already exists, [o]verwrite/[c]ompare/[a]bort? '.format(dest)) - if oca[0] == 'o': # overwrite existing file - log_info('overwriting {}'.format(dest)) - os.system('rm {}'.format(dest)) - elif oca[0] == 'c': # print diff between existing file & dotfile - log_info('comparing {} to {}'.format(dotfile_source, dest)) - os.system('diff -bys {} {}'.format(dotfile_source, dest)) # use vimdiff ? +def install(dotfile): + debug('installing', dotfile) + known = isdotfile(KNOWN, dotfile) + location = install_getlocation(known) + aliases = install_getaliases(known) + if not os.path.exists(os.path.dirname(location)): + os.system('mkdir -vp {}'.format(location)) + if os.path.lexists(location): + install_oca(dotfile, location) + os.system('ln -vs {} {}'.format(dotfile, location)) + info('appending to installed...') + dfl = aliases.insert(0, location) + INSTALLED.append(dfl) + clearduplicates(INSTALLED) + info('success - you might need to re-open the terminal to see changes take effect') + +def install_getlocation(known_index): + default = '' + if known_index != -1: + default = KNOWN[known_index][0] + if len(default) > 0 and ARGS.skip == True: + return default + location = '' + while location == '': + location = input('install location ({})? '.format( + ('default:', default) if len(default) > 0 else '')) + if len(location) == 0 and len(default) > 0: + return default + elif location.find('~') != -1: + return location.replace('~', HOME) + else: + location = '' + +def install_getaliases(known_index): + default = '' + if known_index != -1: + default = KNOWN[known][1:] + if len(default) > 0 and ARGS.skip == True: + return default + aliases = '' + while aliases == '': + aliases = input('aliases to call dotfile by (put a space between each alias) ({})? '.format( + ('default:', default) if len(default) > 0 else '')) + if len(aliases) > 0: + return aliases.split(' ') + elif len(default) > 0: + return default + +def install_oca(dotfile, location): + oca = '' + while oca == '': + oca = input(location 'already exists, [o]verwrite/[c]ompare/[a]bort? ') + if len(oca) > 0: + if oca[0] == 'o': # overwrite + debug('removing', location) + os.remove(location) + elif oca[0] == 'c': # compare + debug('comparing {} to {}'.format(dotfile, location)) + os.system('diff -bys {} {}'.format(dotfile, location)) oca = '' - elif oca[0] == 'a': # abort install - log_info('aborting install') + elif oca[0] == 'a': # abort + debug('aborting install') sys.exit() else: oca = '' - # create symbolic link to dotfile - os.system('ln -vs {} {}'.format(dotfile_source, dest)) - # append to DOTFILE_CSV_FILE and INSTALLED - log_info('appending to installed dotfiles...') - dfl = aliases - dfl.insert(0, dest) - with open(INSTALLED_FILE, "a") as dotfm_csv_file: - dotfm_csv = csv.writer(dotfm_csv_file, lineterminator='\n') - dotfm_csv.writerow(dfl) - dotfm_csv_file.close() - INSTALLED.append(dfl) - - log_info('success - you might need to re-open the terminal to see changes take effect') + return oca # main/update -def dotfm_update(dotfile_alias, new_source): - """ Update the source location that the dotfile symlink of an already - installed dotfile points to. If the dotfile_alias does not exist in - INSTALLED_FILE, dotfm_install is called instead. - - @param alias = an alias matching the known aliases of the dotfile to - update - @param new_source = the new filepath to point the dotfile symlink to - """ - - log_info('updating {} -> {}...'.format(dotfile_alias, new_source)) - - found = -1 - for i, dfl in enumerate(INSTALLED): - if dotfile_alias in dfl: - found = i - break - - if found != -1: - # stat new_source - if os.path.exists(new_source): - os.system('ln -isv {} {}'.format(new_source, dfl[0])) - else: - log_info('{} does not exist'.format(new_source)) +def update(alias, location): + debug('updating {} -> {}'.format(alias, location)) + known = isdotfile(INSTALLED, alias) + if known != -1: + os.system('ln -isv', location, INSTALLED[known][0]) else: - log_info('could not find dotfile matching alias "{}"'.format( - dotfile_alias)) + warn(dotfile, 'is unrecognised, installing') + install(location) # main/remove -def dotfm_remove(alias): +def remove(alias): """ Remove a dotfile (from it's known location) and remove it from INSTALLED_FILE @@ -287,7 +276,7 @@ def dotfm_remove(alias): log_info('could not find dotfile matching alias "{}"'.format(alias)) # main/edit -def dotfm_edit(dotfile_alias): +def edit(dotfile_alias): """ Open dotfile with alias matching "dotfm_alias" in EDITOR @param dotfile_alias = an alias of the dotfile to open """ @@ -316,7 +305,7 @@ def dotfm_edit(dotfile_alias): os.path.basename(dotfile_alias))) # main/list -def dotfm_list(dotfile_aliases): +def list(dotfile_aliases): """ List specified dotfile aliases and install location (displays all if none are specified). @param dotfile_aliases = an array of dotfile aliases to list, if @@ -354,15 +343,15 @@ if __name__ == '__main__': init() if ARGS.cmd == 'install': for d in ARGS.dotfile: - dotfm_install(os.path.abspath(d)) + install(os.path.abspath(d)) elif ARGS.cmd == 'update': - dotfm_update(ARGS.dotfile[0], ARGS.dotfile[1]) + update(ARGS.dotfile[0], ARGS.dotfile[1]) elif ARGS.cmd == 'remove': for d in ARGS.dotfile: - dotfm_remove(d) + remove(d) elif ARGS.cmd == 'edit': for d in ARGS.dotfile: - dotfm_edit(d) + edit(d) elif ARGS.cmd == 'list': - dotfm_list(ARGS.dotfile) - + list(ARGS.dotfile) + writeinstalled()