mirror of
1
0
Fork 0

Add option to clean recursively

This commit is contained in:
Anish Athalye 2019-12-31 19:14:23 -05:00
parent 81f0d74955
commit e38e021ab3
3 changed files with 49 additions and 4 deletions

View File

@ -303,7 +303,9 @@ Clean commands are specified as an array of directories to be cleaned.
Clean commands support an extended configuration syntax. In this type of Clean commands support an extended configuration syntax. In this type of
configuration, commands are specified as directory paths mapping to options. If configuration, commands are specified as directory paths mapping to options. If
the `force` option is set to `true`, dead links are removed even if they don't the `force` option is set to `true`, dead links are removed even if they don't
point to a file inside the dotfiles directory. point to a file inside the dotfiles directory. If `recursive` is set to `true`,
the directory is traversed recursively (not recommended for `~` because it will
be slow).
#### Example #### Example
@ -311,8 +313,10 @@ point to a file inside the dotfiles directory.
- clean: ['~'] - clean: ['~']
- clean: - clean:
~/.config: ~/:
force: true force: true
~/.config:
recursive: true
``` ```
### Defaults ### Defaults

View File

@ -20,16 +20,18 @@ class Clean(dotbot.Plugin):
defaults = self._context.defaults().get(self._directive, {}) defaults = self._context.defaults().get(self._directive, {})
for target in targets: for target in targets:
force = defaults.get('force', False) force = defaults.get('force', False)
recursive = defaults.get('recursive', False)
if isinstance(targets, dict) and isinstance(targets[target], dict): if isinstance(targets, dict) and isinstance(targets[target], dict):
force = targets[target].get('force', force) force = targets[target].get('force', force)
success &= self._clean(target, force) recursive = targets[target].get('recursive', recursive)
success &= self._clean(target, force, recursive)
if success: if success:
self._log.info('All targets have been cleaned') self._log.info('All targets have been cleaned')
else: else:
self._log.error('Some targets were not successfully cleaned') self._log.error('Some targets were not successfully cleaned')
return success return success
def _clean(self, target, force): def _clean(self, target, force, recursive):
''' '''
Cleans all the broken symbolic links in target if they point to Cleans all the broken symbolic links in target if they point to
a subdirectory of the base directory or if forced to clean. a subdirectory of the base directory or if forced to clean.
@ -39,6 +41,11 @@ class Clean(dotbot.Plugin):
return True return True
for item in os.listdir(os.path.expandvars(os.path.expanduser(target))): for item in os.listdir(os.path.expandvars(os.path.expanduser(target))):
path = os.path.join(os.path.expandvars(os.path.expanduser(target)), item) path = os.path.join(os.path.expandvars(os.path.expanduser(target)), item)
if recursive and os.path.isdir(path):
# isdir implies not islink -- we don't want to descend into
# symlinked directories. okay to do a recursive call here
# because depth should be fairly limited
self._clean(path, force, recursive)
if not os.path.exists(path) and os.path.islink(path): if not os.path.exists(path) and os.path.islink(path):
points_at = os.path.join(os.path.dirname(path), os.readlink(path)) points_at = os.path.join(os.path.dirname(path), os.readlink(path))
if self._in_directory(path, self._context.base_directory()) or force: if self._in_directory(path, self._context.base_directory()) or force:

View File

@ -0,0 +1,34 @@
test_description='clean removes recursively'
. '../test-lib.bash'
test_expect_success 'setup' '
mkdir -p ~/a/b
ln -s /nowhere ~/c
ln -s /nowhere ~/a/d
ln -s /nowhere ~/a/b/e
'
test_expect_success 'run' '
run_dotbot <<EOF
- clean:
~/:
force: true
EOF
'
test_expect_success 'test' '
! test -h ~/c && test -h ~/a/d && test -h ~/a/b/e
'
test_expect_success 'run 2' '
run_dotbot <<EOF
- clean:
~/:
force: true
recursive: true
EOF
'
test_expect_success 'test 2' '
! test -h ~/a/d && ! test -h ~/a/b/e
'