Merge branch 'ypid/add/link_real_path_option'
This commit is contained in:
commit
ec8498ffb8
7 changed files with 67 additions and 16 deletions
|
@ -176,6 +176,7 @@ Available extended configuration parameters:
|
||||||
| `relink` | Removes the old target if it's a symlink (default:false) |
|
| `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) |
|
| `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) |
|
| `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) |
|
| `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. |
|
| `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) |
|
| `ignore-missing` | Do not fail if the source is missing and create the link anyway (default:false) |
|
||||||
|
|
|
@ -73,10 +73,10 @@ def main():
|
||||||
if not isinstance(tasks, list):
|
if not isinstance(tasks, list):
|
||||||
raise ReadingError('Configuration file must be a list of tasks')
|
raise ReadingError('Configuration file must be a list of tasks')
|
||||||
if options.base_directory:
|
if options.base_directory:
|
||||||
base_directory = options.base_directory
|
base_directory = os.path.abspath(options.base_directory)
|
||||||
else:
|
else:
|
||||||
# default to directory of config file
|
# 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)
|
os.chdir(base_directory)
|
||||||
dispatcher = Dispatcher(base_directory)
|
dispatcher = Dispatcher(base_directory)
|
||||||
success = dispatcher.dispatch(tasks)
|
success = dispatcher.dispatch(tasks)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import copy
|
import copy
|
||||||
|
import os
|
||||||
|
|
||||||
class Context(object):
|
class Context(object):
|
||||||
'''
|
'''
|
||||||
|
@ -13,8 +14,11 @@ class Context(object):
|
||||||
def set_base_directory(self, base_directory):
|
def set_base_directory(self, base_directory):
|
||||||
self._base_directory = base_directory
|
self._base_directory = base_directory
|
||||||
|
|
||||||
def base_directory(self):
|
def base_directory(self, canonical_path=True):
|
||||||
return self._base_directory
|
base_directory = self._base_directory
|
||||||
|
if canonical_path:
|
||||||
|
base_directory = os.path.realpath(base_directory)
|
||||||
|
return base_directory
|
||||||
|
|
||||||
def set_defaults(self, defaults):
|
def set_defaults(self, defaults):
|
||||||
self._defaults = defaults
|
self._defaults = defaults
|
||||||
|
|
|
@ -10,8 +10,8 @@ class Dispatcher(object):
|
||||||
self._load_plugins()
|
self._load_plugins()
|
||||||
|
|
||||||
def _setup_context(self, base_directory):
|
def _setup_context(self, base_directory):
|
||||||
path = os.path.abspath(os.path.realpath(
|
path = os.path.abspath(
|
||||||
os.path.expanduser(base_directory)))
|
os.path.expanduser(base_directory))
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
raise DispatchError('Nonexistent base directory')
|
raise DispatchError('Nonexistent base directory')
|
||||||
self._context = Context(path)
|
self._context = Context(path)
|
||||||
|
|
|
@ -26,6 +26,7 @@ class Link(dotbot.Plugin):
|
||||||
for destination, source in links.items():
|
for destination, source in links.items():
|
||||||
destination = os.path.expandvars(destination)
|
destination = os.path.expandvars(destination)
|
||||||
relative = defaults.get('relative', False)
|
relative = defaults.get('relative', False)
|
||||||
|
canonical_path = defaults.get('canonicalize-path', True)
|
||||||
force = defaults.get('force', False)
|
force = defaults.get('force', False)
|
||||||
relink = defaults.get('relink', False)
|
relink = defaults.get('relink', False)
|
||||||
create = defaults.get('create', False)
|
create = defaults.get('create', False)
|
||||||
|
@ -36,6 +37,7 @@ class Link(dotbot.Plugin):
|
||||||
# extended config
|
# extended config
|
||||||
test = source.get('if', test)
|
test = source.get('if', test)
|
||||||
relative = source.get('relative', relative)
|
relative = source.get('relative', relative)
|
||||||
|
canonical_path = source.get('canonicalize-path', canonical_path)
|
||||||
force = source.get('force', force)
|
force = source.get('force', force)
|
||||||
relink = source.get('relink', relink)
|
relink = source.get('relink', relink)
|
||||||
create = source.get('create', create)
|
create = source.get('create', create)
|
||||||
|
@ -68,8 +70,8 @@ class Link(dotbot.Plugin):
|
||||||
if create:
|
if create:
|
||||||
success &= self._create(destination)
|
success &= self._create(destination)
|
||||||
if force or relink:
|
if force or relink:
|
||||||
success &= self._delete(path, destination, relative, force)
|
success &= self._delete(path, destination, relative, canonical_path, force)
|
||||||
success &= self._link(path, destination, relative, ignore_missing)
|
success &= self._link(path, destination, relative, canonical_path, ignore_missing)
|
||||||
else:
|
else:
|
||||||
self._log.lowinfo("Globs from '" + path + "': " + str(glob_results))
|
self._log.lowinfo("Globs from '" + path + "': " + str(glob_results))
|
||||||
glob_base = path[:glob_star_loc]
|
glob_base = path[:glob_star_loc]
|
||||||
|
@ -79,8 +81,8 @@ class Link(dotbot.Plugin):
|
||||||
if create:
|
if create:
|
||||||
success &= self._create(glob_link_destination)
|
success &= self._create(glob_link_destination)
|
||||||
if force or relink:
|
if force or relink:
|
||||||
success &= self._delete(glob_full_item, glob_link_destination, relative, force)
|
success &= self._delete(glob_full_item, glob_link_destination, relative, canonical_path, force)
|
||||||
success &= self._link(glob_full_item, glob_link_destination, relative, ignore_missing)
|
success &= self._link(glob_full_item, glob_link_destination, relative, canonical_path, ignore_missing)
|
||||||
else:
|
else:
|
||||||
if create:
|
if create:
|
||||||
success &= self._create(destination)
|
success &= self._create(destination)
|
||||||
|
@ -94,8 +96,8 @@ class Link(dotbot.Plugin):
|
||||||
(destination, path))
|
(destination, path))
|
||||||
continue
|
continue
|
||||||
if force or relink:
|
if force or relink:
|
||||||
success &= self._delete(path, destination, relative, force)
|
success &= self._delete(path, destination, relative, canonical_path, force)
|
||||||
success &= self._link(path, destination, relative, ignore_missing)
|
success &= self._link(path, destination, relative, canonical_path, ignore_missing)
|
||||||
if success:
|
if success:
|
||||||
self._log.info('All links have been set up')
|
self._log.info('All links have been set up')
|
||||||
else:
|
else:
|
||||||
|
@ -159,9 +161,9 @@ class Link(dotbot.Plugin):
|
||||||
self._log.lowinfo('Creating directory %s' % parent)
|
self._log.lowinfo('Creating directory %s' % parent)
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def _delete(self, source, path, relative, force):
|
def _delete(self, source, path, relative, canonical_path, force):
|
||||||
success = True
|
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)
|
fullpath = os.path.expanduser(path)
|
||||||
if relative:
|
if relative:
|
||||||
source = self._relative_path(source, fullpath)
|
source = self._relative_path(source, fullpath)
|
||||||
|
@ -195,7 +197,7 @@ class Link(dotbot.Plugin):
|
||||||
destination_dir = os.path.dirname(destination)
|
destination_dir = os.path.dirname(destination)
|
||||||
return os.path.relpath(source, destination_dir)
|
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.
|
Links link_name to source.
|
||||||
|
|
||||||
|
@ -203,7 +205,8 @@ class Link(dotbot.Plugin):
|
||||||
'''
|
'''
|
||||||
success = False
|
success = False
|
||||||
destination = os.path.expanduser(link_name)
|
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:
|
if relative:
|
||||||
source = self._relative_path(absolute_source, destination)
|
source = self._relative_path(absolute_source, destination)
|
||||||
else:
|
else:
|
||||||
|
|
20
test/tests/link-canonicalize.bash
Normal file
20
test/tests/link-canonicalize.bash
Normal file
|
@ -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" ]
|
||||||
|
'
|
23
test/tests/link-no-canonicalize.bash
Normal file
23
test/tests/link-no-canonicalize.bash
Normal file
|
@ -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" ]
|
||||||
|
'
|
Loading…
Reference in a new issue