summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnish Athalye <me@anishathalye.com>2020-01-03 16:46:19 -0500
committerAnish Athalye <me@anishathalye.com>2020-01-03 16:46:19 -0500
commitec8498ffb88d43c7d0648033d3d758ebb96a9378 (patch)
treed0f4443ea7f55931a9df52e6a36c51cadd340fba
parent3fcc13d803f4f0190d997f71f3af693ecef3e4c5 (diff)
parent320d5d0123b045fe922cf576d8d65e2db0517910 (diff)
Merge branch 'ypid/add/link_real_path_option'
-rw-r--r--README.md1
-rw-r--r--dotbot/cli.py4
-rw-r--r--dotbot/context.py8
-rw-r--r--dotbot/dispatcher.py4
-rw-r--r--dotbot/plugins/link.py23
-rw-r--r--test/tests/link-canonicalize.bash20
-rw-r--r--test/tests/link-no-canonicalize.bash23
7 files changed, 67 insertions, 16 deletions
diff --git a/README.md b/README.md
index 20c69d2..1aa5fa8 100644
--- a/README.md
+++ b/README.md
@@ -176,6 +176,7 @@ Available extended configuration parameters:
| `relink` | Removes the old target if it's a symlink (default:false) |
| `force` | Force removes the old target, file or folder, and forces a new link (default:false) |
| `relative` | Use a relative path to the source when creating the symlink (default:false, absolute links) |
+| `canonicalize-path` | Resolve any symbolic links encountered in the source to symlink to the canonical path (default:true, real paths) |
| `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) |
diff --git a/dotbot/cli.py b/dotbot/cli.py
index 2680acf..77bd439 100644
--- a/dotbot/cli.py
+++ b/dotbot/cli.py
@@ -73,10 +73,10 @@ def main():
if not isinstance(tasks, list):
raise ReadingError('Configuration file must be a list of tasks')
if options.base_directory:
- base_directory = options.base_directory
+ base_directory = os.path.abspath(options.base_directory)
else:
# default to directory of config file
- base_directory = os.path.dirname(os.path.realpath(options.config_file))
+ base_directory = os.path.dirname(os.path.abspath(options.config_file))
os.chdir(base_directory)
dispatcher = Dispatcher(base_directory)
success = dispatcher.dispatch(tasks)
diff --git a/dotbot/context.py b/dotbot/context.py
index b2dbd6c..8c42d47 100644
--- a/dotbot/context.py
+++ b/dotbot/context.py
@@ -1,4 +1,5 @@
import copy
+import os
class Context(object):
'''
@@ -13,8 +14,11 @@ class Context(object):
def set_base_directory(self, base_directory):
self._base_directory = base_directory
- def base_directory(self):
- return self._base_directory
+ def base_directory(self, canonical_path=True):
+ base_directory = self._base_directory
+ if canonical_path:
+ base_directory = os.path.realpath(base_directory)
+ return base_directory
def set_defaults(self, defaults):
self._defaults = defaults
diff --git a/dotbot/dispatcher.py b/dotbot/dispatcher.py
index d1a4f95..36eac02 100644
--- a/dotbot/dispatcher.py
+++ b/dotbot/dispatcher.py
@@ -10,8 +10,8 @@ class Dispatcher(object):
self._load_plugins()
def _setup_context(self, base_directory):
- path = os.path.abspath(os.path.realpath(
- os.path.expanduser(base_directory)))
+ path = os.path.abspath(
+ os.path.expanduser(base_directory))
if not os.path.exists(path):
raise DispatchError('Nonexistent base directory')
self._context = Context(path)
diff --git a/dotbot/plugins/link.py b/dotbot/plugins/link.py
index d38c0ab..82a61ce 100644
--- a/dotbot/plugins/link.py
+++ b/dotbot/plugins/link.py
@@ -26,6 +26,7 @@ class Link(dotbot.Plugin):
for destination, source in links.items():
destination = os.path.expandvars(destination)
relative = defaults.get('relative', False)
+ canonical_path = defaults.get('canonicalize-path', True)
force = defaults.get('force', False)
relink = defaults.get('relink', False)
create = defaults.get('create', False)
@@ -36,6 +37,7 @@ class Link(dotbot.Plugin):
# extended config
test = source.get('if', test)
relative = source.get('relative', relative)
+ canonical_path = source.get('canonicalize-path', canonical_path)
force = source.get('force', force)
relink = source.get('relink', relink)
create = source.get('create', create)
@@ -68,8 +70,8 @@ class Link(dotbot.Plugin):
if create:
success &= self._create(destination)
if force or relink:
- success &= self._delete(path, destination, relative, force)
- success &= self._link(path, destination, relative, ignore_missing)
+ success &= self._delete(path, destination, relative, canonical_path, force)
+ success &= self._link(path, destination, relative, canonical_path, ignore_missing)
else:
self._log.lowinfo("Globs from '" + path + "': " + str(glob_results))
glob_base = path[:glob_star_loc]
@@ -79,8 +81,8 @@ class Link(dotbot.Plugin):
if create:
success &= self._create(glob_link_destination)
if force or relink:
- success &= self._delete(glob_full_item, glob_link_destination, relative, force)
- success &= self._link(glob_full_item, glob_link_destination, relative, ignore_missing)
+ success &= self._delete(glob_full_item, glob_link_destination, relative, canonical_path, force)
+ success &= self._link(glob_full_item, glob_link_destination, relative, canonical_path, ignore_missing)
else:
if create:
success &= self._create(destination)
@@ -94,8 +96,8 @@ class Link(dotbot.Plugin):
(destination, path))
continue
if force or relink:
- success &= self._delete(path, destination, relative, force)
- success &= self._link(path, destination, relative, ignore_missing)
+ success &= self._delete(path, destination, relative, canonical_path, force)
+ success &= self._link(path, destination, relative, canonical_path, ignore_missing)
if success:
self._log.info('All links have been set up')
else:
@@ -159,9 +161,9 @@ class Link(dotbot.Plugin):
self._log.lowinfo('Creating directory %s' % parent)
return success
- def _delete(self, source, path, relative, force):
+ def _delete(self, source, path, relative, canonical_path, force):
success = True
- source = os.path.join(self._context.base_directory(), source)
+ source = os.path.join(self._context.base_directory(canonical_path=canonical_path), source)
fullpath = os.path.expanduser(path)
if relative:
source = self._relative_path(source, fullpath)
@@ -195,7 +197,7 @@ class Link(dotbot.Plugin):
destination_dir = os.path.dirname(destination)
return os.path.relpath(source, destination_dir)
- def _link(self, source, link_name, relative, ignore_missing):
+ def _link(self, source, link_name, relative, canonical_path, ignore_missing):
'''
Links link_name to source.
@@ -203,7 +205,8 @@ class Link(dotbot.Plugin):
'''
success = False
destination = os.path.expanduser(link_name)
- absolute_source = os.path.join(self._context.base_directory(), source)
+ base_directory = self._context.base_directory(canonical_path=canonical_path)
+ absolute_source = os.path.join(base_directory, source)
if relative:
source = self._relative_path(absolute_source, destination)
else:
diff --git a/test/tests/link-canonicalize.bash b/test/tests/link-canonicalize.bash
new file mode 100644
index 0000000..34015c8
--- /dev/null
+++ b/test/tests/link-canonicalize.bash
@@ -0,0 +1,20 @@
+test_description='linking canonicalizes path by default'
+. '../test-lib.bash'
+
+test_expect_success 'setup' '
+echo "apple" > ${DOTFILES}/f &&
+ln -s dotfiles dotfiles-symlink
+'
+
+test_expect_success 'run' '
+cat > "${DOTFILES}/${INSTALL_CONF}" <<EOF
+- link:
+ ~/.f:
+ path: f
+EOF
+${DOTBOT_EXEC} -c dotfiles-symlink/${INSTALL_CONF}
+'
+
+test_expect_success 'test' '
+[ "$(readlink ~/.f | cut -d/ -f4-)" = "dotfiles/f" ]
+'
diff --git a/test/tests/link-no-canonicalize.bash b/test/tests/link-no-canonicalize.bash
new file mode 100644
index 0000000..f9ccb99
--- /dev/null
+++ b/test/tests/link-no-canonicalize.bash
@@ -0,0 +1,23 @@
+test_description='linking path canonicalization can be disabled'
+. '../test-lib.bash'
+
+test_expect_success 'setup' '
+echo "apple" > ${DOTFILES}/f &&
+ln -s dotfiles dotfiles-symlink
+'
+
+test_expect_success 'run' '
+cat > "${DOTFILES}/${INSTALL_CONF}" <<EOF
+- defaults:
+ link:
+ canonicalize-path: false
+- link:
+ ~/.f:
+ path: f
+EOF
+${DOTBOT_EXEC} -c ./dotfiles-symlink/${INSTALL_CONF}
+'
+
+test_expect_success 'test' '
+[ "$(readlink ~/.f | cut -d/ -f4-)" = "dotfiles-symlink/f" ]
+'