diff --git a/README.md b/README.md index 00c654d..3ed74f5 100644 --- a/README.md +++ b/README.md @@ -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: ~/.config/terminator: create: true - path: config/terminator/ - ~/.vim: vim/ + path: config/terminator + ~/.vim: vim ~/.vimrc: relink: true path: vimrc diff --git a/plugins/link.py b/plugins/link.py index 429158d..3bb5686 100644 --- a/plugins/link.py +++ b/plugins/link.py @@ -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) else: + relative = False path = source - success &= self._link(path, destination) + success &= self._link(path, destination, relative) if success: self._log.info('All links have been set up') else: @@ -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): try: - 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)) else: diff --git a/test/tests/link-relative.bash b/test/tests/link-relative.bash new file mode 100644 index 0000000..ac55c17 --- /dev/null +++ b/test/tests/link-relative.bash @@ -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 <