From 2ec7a24129ce8c1fc12c4e557174297bcd4bf31a Mon Sep 17 00:00:00 2001 From: "E. Keys" Date: Sun, 22 Nov 2020 12:59:30 -0500 Subject: [PATCH] Add exclude parameter for link globbing - Added `exclude` parameter to _link_. Now, an array of glob patterns can be given that will be used to remove items from a glob match. This parameter will only have an effect when `glob` is `true`. - Updated README to add description for `exclude` and add in examples. Resolves #247 --- README.md | 13 ++++ dotbot/plugins/link.py | 16 +++- test/tests/link-glob-exclude.bash | 123 ++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 test/tests/link-glob-exclude.bash diff --git a/README.md b/README.md index ae7e570..3b0aae0 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,7 @@ mapped to extended configuration dictionaries. | `glob` | Treat a `*` character as a wildcard, and perform link operations on all of those matches (default: false) | | `if` | Execute this in your `$SHELL` and only link if it is successful. | | `ignore-missing` | Do not fail if the source is missing and create the link anyway (default: false) | +| `exclude` | Array of paths to remove from glob matches. Uses same syntax as `path`. Ignored if `glob` is `false`. (default: empty, keep all matches) | #### Example @@ -218,6 +219,12 @@ Explicit sources: glob: true path: config/* relink: true + exclude: [ config/Code ] + ~/.config/Code/User/: + create: true + glob: true + path: config/Code/User/* + relink: true ``` Implicit sources: @@ -234,6 +241,12 @@ Implicit sources: glob: true path: config/* relink: true + exclude: [ config/Code ] + ~/.config/Code/User/: + create: true + glob: true + path: config/Code/User/* + relink: true ``` ### Create diff --git a/dotbot/plugins/link.py b/dotbot/plugins/link.py index 6f2b562..fd2d14d 100644 --- a/dotbot/plugins/link.py +++ b/dotbot/plugins/link.py @@ -34,6 +34,7 @@ class Link(dotbot.Plugin): use_glob = defaults.get('glob', False) test = defaults.get('if', None) ignore_missing = defaults.get('ignore-missing', False) + exclude_paths = defaults.get('exclude', []) if isinstance(source, dict): # extended config test = source.get('if', test) @@ -44,6 +45,7 @@ class Link(dotbot.Plugin): create = source.get('create', create) use_glob = source.get('glob', use_glob) ignore_missing = source.get('ignore-missing', ignore_missing) + exclude_paths = source.get('exclude', exclude_paths) path = self._default_source(destination, source.get('path')) else: path = self._default_source(destination, source) @@ -52,8 +54,7 @@ class Link(dotbot.Plugin): continue path = os.path.expandvars(os.path.expanduser(path)) if use_glob: - self._log.debug("Globbing with path: " + str(path)) - glob_results = glob.glob(path) + glob_results = self._create_glob_results(path, exclude_paths) if len(glob_results) == 0: self._log.warning("Globbing couldn't find anything matching " + str(path)) success = False @@ -120,6 +121,17 @@ class Link(dotbot.Plugin): return basename else: return source + + def _create_glob_results(self, path, exclude_paths): + self._log.debug("Globbing with path: " + str(path)) + base_include = glob.glob(path) + to_exclude = [] + for expath in exclude_paths: + self._log.debug("Excluding globs with path: " + str(expath)) + to_exclude.extend(glob.glob(expath)) + self._log.debug("Excluded globs from '" + path + "': " + str(to_exclude)) + ret = set(base_include) - set(to_exclude) + return list(ret) def _is_link(self, path): ''' diff --git a/test/tests/link-glob-exclude.bash b/test/tests/link-glob-exclude.bash new file mode 100644 index 0000000..bb6fb76 --- /dev/null +++ b/test/tests/link-glob-exclude.bash @@ -0,0 +1,123 @@ +test_description='link glob exclude' +. '../test-lib.bash' + +test_expect_success 'setup 1' ' +mkdir -p ${DOTFILES}/config/{foo,bar,baz} && +echo "apple" > ${DOTFILES}/config/foo/a && +echo "banana" > ${DOTFILES}/config/bar/b && +echo "cherry" > ${DOTFILES}/config/bar/c && +echo "donut" > ${DOTFILES}/config/baz/d +' + +test_expect_success 'run 1' ' +run_dotbot -v < ${DOTFILES}/config/baz/buzz/e +' + +test_expect_success 'run 2' ' +run_dotbot -v < ${DOTFILES}/config/baz/bizz/g +' + +test_expect_success 'run 3' ' +run_dotbot -v < ${DOTFILES}/config/fiz/f +' + +test_expect_success 'run 4' ' +run_dotbot -v <