Add functionality to create relative links

This commit adds an option to the extended configuration syntax for
linking files and directories. Enabling the relative option makes it so
that symbolic links are created with relative paths instead of absolute
pull/77/merge v1.8.0
Anish Athalye 8 years ago
parent c402396c58
commit daf8d82e02
  1. 15
  2. 12
  3. 36

@ -83,7 +83,7 @@ The conventional name for the configuration file is `install.conf.yaml`.
- link:
~/.dotfiles: ''
~/.tmux.conf: tmux.conf
~/.vim: vim/
~/.vim: vim
~/.vimrc: vimrc
- shell:
@ -104,7 +104,7 @@ The conventional name for this file is `install.conf.json`.
"link": {
"~/.dotfiles": "",
"~/.tmux.conf": "tmux.conf",
"~/.vim": "vim/",
"~/.vim": "vim",
"~/.vimrc": "vimrc"
@ -147,7 +147,7 @@ files if necessary. Environment variables in paths are automatically expanded.
Link commands are specified as a dictionary mapping targets to source
locations. Source locations are specified relative to the base directory (that
is specified when running the installer). Source directory names should contain
is specified when running the installer). Directory names should *not* contain
a trailing "/" character.
Link commands support an (optional) extended configuration. In this type of
@ -155,8 +155,9 @@ configuration, instead of specifying source locations directly, targets are
mapped to extended configuration dictionaries. These dictionaries map `path` to
the source path, specify `create` as `true` if the parent directory should be
created if necessary, specify `relink` as `true` if incorrect symbolic links
should be automatically overwritten, and specify `force` as `true` if the file
or directory should be forcibly linked.
should be automatically overwritten, specify `force` as `true` if the file or
directory should be forcibly linked, and specify `relative` as `true` if the
symbolic link should have a relative path.
#### Example
@ -164,8 +165,8 @@ or directory should be forcibly linked.
- link:
create: true
path: config/terminator/
~/.vim: vim/
path: config/terminator
~/.vim: vim
relink: true
path: vimrc

@ -23,6 +23,7 @@ class Link(dotbot.Plugin):
if isinstance(source, dict):
# extended config
path = source['path']
relative = source.get('relative', False)
force = source.get('force', False)
relink = source.get('relink', False)
create = source.get('create', False)
@ -33,8 +34,9 @@ class Link(dotbot.Plugin):
elif relink:
success &= self._delete(path, destination, force=False)
relative = False
path = source
success &= self._link(path, destination)
success &= self._link(path, destination, relative)
if success:'All links have been set up')
@ -101,7 +103,7 @@ class Link(dotbot.Plugin):
self._log.lowinfo('Removing %s' % path)
return success
def _link(self, source, link_name):
def _link(self, source, link_name, relative):
Links link_name to source.
@ -115,7 +117,11 @@ class Link(dotbot.Plugin):
(link_name, self._link_destination(link_name)))
elif not self._exists(link_name) and self._exists(source):
os.symlink(source, os.path.expanduser(link_name))
destination = os.path.expanduser(link_name)
if relative:
destination_dir = os.path.dirname(destination)
source = os.path.relpath(source, destination_dir)
os.symlink(source, destination)
except OSError:
self._log.warning('Linking failed %s -> %s' % (link_name, source))

@ -0,0 +1,36 @@
test_description='relative linking works'
. '../test-lib.bash'
test_expect_success 'setup' '
echo "apple" > ${DOTFILES}/f &&
mkdir ${DOTFILES}/d &&
echo "grape" > ${DOTFILES}/d/e
test_expect_success 'run' '
run_dotbot <<EOF
- link:
path: f
path: f
relative: true
path: f
create: true
relative: true
path: d
relative: true
test_expect_success 'test' '
grep "apple" ~/.f &&
grep "apple" ~/.frel &&
[[ "$(readlink ~/.f)" == "$(readlink -f dotfiles/f)" ]] &&
[[ "$(readlink ~/.frel)" == "dotfiles/f" ]] &&
[[ "$(readlink ~/nested/.frel)" == "../dotfiles/f" ]] &&
grep "grape" ~/.d/e &&
[[ "$(readlink ~/.d)" == "dotfiles/d" ]]