1
0
mirror of https://github.com/deadc0de6/dotdrop.git synced 2026-02-09 21:04:15 +00:00

implement upignore for #79

This commit is contained in:
deadc0de6
2019-01-17 21:22:12 +01:00
parent f78e3126f5
commit 0162412d4c
8 changed files with 199 additions and 28 deletions

View File

@@ -7,7 +7,6 @@ handle the comparison of dotfiles and local deployment
import os
import filecmp
import fnmatch
# local imports
from dotdrop.logger import Logger
@@ -34,7 +33,7 @@ class Comparator:
def _comp_file(self, left, right, ignore):
"""compare a file"""
if self._ignore([left, right], ignore):
if utils.must_ignore([left, right], ignore, debug=self.debug):
if self.debug:
self.log.dbg('ignoring diff {} and {}'.format(left, right))
return ''
@@ -44,7 +43,7 @@ class Comparator:
"""compare a directory"""
if not os.path.exists(right):
return ''
if self._ignore([left, right], ignore):
if utils.must_ignore([left, right], ignore, debug=self.debug):
if self.debug:
self.log.dbg('ignoring diff {} and {}'.format(left, right))
return ''
@@ -54,11 +53,13 @@ class Comparator:
comp = filecmp.dircmp(left, right)
# handle files only in deployed file
for i in comp.left_only:
if self._ignore([os.path.join(left, i)], ignore):
if utils.must_ignore([os.path.join(left, i)],
ignore, debug=self.debug):
continue
ret.append('=> \"{}\" does not exist on local\n'.format(i))
for i in comp.right_only:
if self._ignore([os.path.join(right, i)], ignore):
if utils.must_ignore([os.path.join(right, i)],
ignore, debug=self.debug):
continue
ret.append('=> \"{}\" does not exist in dotdrop\n'.format(i))
@@ -92,15 +93,3 @@ class Comparator:
rshort = os.path.basename(right)
diff = '=> diff \"{}\":\n{}'.format(lshort, diff)
return diff
def _ignore(self, paths, ignore):
'''return True if any paths is ignored - not very efficient'''
if not ignore:
return False
for p in paths:
for i in ignore:
if fnmatch.fnmatch(p, i):
if self.debug:
self.log.dbg('ignore match {}'.format(p))
return True
return False

View File

@@ -57,6 +57,7 @@ class Cfg:
key_dotfiles_actions = 'actions'
key_dotfiles_trans_r = 'trans'
key_dotfiles_trans_w = 'trans_write'
key_dotfiles_upignore = 'upignore'
# profiles keys
key_profiles = 'profiles'
@@ -272,15 +273,20 @@ class Cfg:
trans_r = None
trans_w = None
# parse ignore pattern
ignores = v[self.key_dotfiles_cmpignore] if \
# parse cmpignore pattern
cmpignores = v[self.key_dotfiles_cmpignore] if \
self.key_dotfiles_cmpignore in v else []
# parse upignore pattern
upignores = v[self.key_dotfiles_upignore] if \
self.key_dotfiles_upignore in v else []
# create new dotfile
self.dotfiles[k] = Dotfile(k, dst, src,
link=link, actions=actions,
trans_r=trans_r, trans_w=trans_w,
cmpignore=ignores, noempty=noempty)
cmpignore=cmpignores, noempty=noempty,
upignore=upignores)
# assign dotfiles to each profile
for k, v in self.lnk_profiles.items():

View File

@@ -44,7 +44,8 @@ Usage:
dotdrop import [-ldVb] [-c <path>] [-p <profile>] <path>...
dotdrop compare [-Vb] [-c <path>] [-p <profile>]
[-o <opts>] [-C <file>...] [-i <pattern>...]
dotdrop update [-fdVbk] [-c <path>] [-p <profile>] [<path>...]
dotdrop update [-fdVbk] [-c <path>] [-p <profile>]
[-i <pattern>...] [<path>...]
dotdrop listfiles [-VTb] [-c <path>] [-p <profile>]
dotdrop detail [-Vb] [-c <path>] [-p <profile>] [<key>...]
dotdrop list [-Vb] [-c <path>]
@@ -55,7 +56,7 @@ Options:
-p --profile=<profile> Specify the profile to use [default: {}].
-c --cfg=<path> Path to the config [default: config.yaml].
-C --file=<path> Path of dotfile to compare.
-i --ignore=<pattern> Pattern to ignore when diffing.
-i --ignore=<pattern> Pattern to ignore.
-o --dopts=<opts> Diff options [default: ].
-n --nodiff Do not diff when installing.
-t --temp Install to a temporary directory for review.
@@ -209,11 +210,12 @@ def cmd_compare(opts, conf, tmp, focus=[], ignore=[]):
return same
def cmd_update(opts, conf, paths, iskey=False):
def cmd_update(opts, conf, paths, iskey=False, ignore=[]):
"""update the dotfile(s) from path(s) or key(s)"""
ret = True
updater = Updater(conf, opts['dotpath'], opts['dry'],
opts['safe'], iskey=iskey, debug=opts['debug'])
opts['safe'], iskey=iskey,
debug=opts['debug'], ignore=[])
if not iskey:
# update paths
if opts['debug']:
@@ -494,7 +496,8 @@ def main():
if opts['debug']:
LOG.dbg('running cmd: update')
iskey = args['--key']
ret = cmd_update(opts, conf, args['<path>'], iskey=iskey)
ret = cmd_update(opts, conf, args['<path>'], iskey=iskey,
ignore=args['--ignore'])
elif args['detail']:
# detail files

View File

@@ -10,7 +10,8 @@ class Dotfile:
def __init__(self, key, dst, src,
actions={}, trans_r=None, trans_w=None,
link=False, cmpignore=[], noempty=False):
link=False, cmpignore=[], noempty=False,
upignore=[]):
# key of dotfile in the config
self.key = key
# path where to install this dotfile
@@ -29,6 +30,8 @@ class Dotfile:
self.cmpignore = cmpignore
# do not deploy empty file
self.noempty = noempty
# pattern to ignore when updating
self.upignore = upignore
def __str__(self):
msg = 'key:\"{}\", src:\"{}\", dst:\"{}\", link:\"{}\"'

View File

@@ -21,13 +21,14 @@ TILD = '~'
class Updater:
def __init__(self, conf, dotpath, dry, safe,
iskey=False, debug=False):
iskey=False, debug=False, ignore=[]):
self.conf = conf
self.dotpath = dotpath
self.dry = dry
self.safe = safe
self.iskey = iskey
self.debug = debug
self.ignore = ignore
self.log = Logger()
def update_path(self, path, profile):
@@ -58,9 +59,16 @@ class Updater:
"""update dotfile from file pointed by path"""
ret = False
new_path = None
self.ignores = list(set(self.ignore + dotfile.upignore))
if self.debug:
self.log.dbg('ignore pattern(s): {}'.format(self.ignores))
left = os.path.expanduser(path)
right = os.path.join(self.conf.abs_or_rel(self.dotpath), dotfile.src)
right = os.path.expanduser(right)
if self._ignore([left, right]):
return True
if dotfile.trans_w:
# apply write transformation if any
new_path = self._apply_trans_w(path, dotfile)
@@ -137,6 +145,8 @@ class Updater:
def _handle_file(self, left, right, compare=True):
"""sync left (deployed file) and right (dotdrop dotfile)"""
if self._ignore([left, right]):
return True
if self.debug:
self.log.dbg('update for file {} and {}'.format(left, right))
if self._is_template(right):
@@ -169,6 +179,8 @@ class Updater:
# paths must be absolute (no tildes)
left = os.path.expanduser(left)
right = os.path.expanduser(right)
if self._ignore([left, right]):
return True
# find the differences
diff = filecmp.dircmp(left, right, ignore=None)
# handle directories diff
@@ -179,6 +191,8 @@ class Updater:
left, right = diff.left, diff.right
if self.debug:
self.log.dbg('sync dir {} to {}'.format(left, right))
if self._ignore([left, right]):
return True
# create dirs that don't exist in dotdrop
for toadd in diff.left_only:
@@ -188,6 +202,8 @@ class Updater:
continue
# match to dotdrop dotpath
new = os.path.join(right, toadd)
if self._ignore([exist, new]):
continue
if self.dry:
self.log.dry('would cp -r {} {}'.format(exist, new))
continue
@@ -202,6 +218,8 @@ class Updater:
if not os.path.isdir(old):
# ignore files for now
continue
if self._ignore([old]):
continue
if self.dry:
self.log.dry('would rm -r {}'.format(old))
continue
@@ -219,6 +237,8 @@ class Updater:
for f in fdiff:
fleft = os.path.join(left, f)
fright = os.path.join(right, f)
if self._ignore([fleft, fright]):
continue
if self.dry:
self.log.dry('would cp {} {}'.format(fleft, fright))
continue
@@ -233,6 +253,8 @@ class Updater:
# ignore dirs, done above
continue
new = os.path.join(right, toadd)
if self._ignore([exist, new]):
continue
if self.dry:
self.log.dry('would cp {} {}'.format(exist, new))
continue
@@ -248,6 +270,8 @@ class Updater:
if os.path.isdir(new):
# ignore dirs, done above
continue
if self._ignore([new]):
continue
if self.dry:
self.log.dry('would rm {}'.format(new))
continue
@@ -275,3 +299,10 @@ class Updater:
if self.safe and not self.log.ask(msg):
return False
return True
def _ignore(self, paths):
if utils.must_ignore(paths, self.ignores, debug=self.debug):
if self.debug:
self.log.dbg('ignoring update for {}'.format(paths))
return True
return False

View File

@@ -10,6 +10,7 @@ import tempfile
import os
import uuid
import shlex
import fnmatch
from shutil import rmtree
# local import
@@ -109,3 +110,16 @@ def strip_home(path):
if path.startswith(home):
path = path[len(home):]
return path
def must_ignore(paths, ignores, debug=False):
"""return true if any paths in list matches any ignore patterns"""
if not ignores:
return False
for p in paths:
for i in ignores:
if fnmatch.fnmatch(p, i):
if debug:
LOG.dbg('ignore \"{}\" match: {}'.format(i, p))
return True
return False