summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnish Athalye <me@anishathalye.com>2015-05-02 22:27:05 -0400
committerAnish Athalye <me@anishathalye.com>2015-05-02 22:30:14 -0400
commit3725d216849f474ef627c708ac77c3cd15053fc4 (patch)
tree359fa4866cc79d04452e009e63cf5aa7a608e443
parentdb8364490da392b4225844ddfc32e5fa69aa3821 (diff)
Add functionality to overwrite broken links
This commit adds an option to the extended configuration syntax for linking files and directories. The relink option is a safe alternative to forcibly linking that only removes broken symbolic links, so it cannot result in data loss.
-rw-r--r--README.md9
-rw-r--r--dotbot/executor/linker.py23
2 files changed, 22 insertions, 10 deletions
diff --git a/README.md b/README.md
index 86f7686..c2c46f3 100644
--- a/README.md
+++ b/README.md
@@ -131,8 +131,9 @@ Link commands support an (optional) extended configuration. In this type of
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, and specify `force` as `true` if the file or directory
-should be forcibly linked.
+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.
#### Example
@@ -142,7 +143,9 @@ should be forcibly linked.
create: true
path: config/terminator/
~/.vim: vim/
- ~/.vimrc: vimrc
+ ~/.vimrc:
+ relink: true
+ path: vimrc
~/.zshrc:
force: true
path: zshrc
diff --git a/dotbot/executor/linker.py b/dotbot/executor/linker.py
index 9821fe7..f0e94bc 100644
--- a/dotbot/executor/linker.py
+++ b/dotbot/executor/linker.py
@@ -23,11 +23,14 @@ class Linker(Executor):
# extended config
path = source['path']
force = source.get('force', False)
+ relink = source.get('relink', False)
create = source.get('create', False)
if create:
success &= self._create(destination)
if force:
- success &= self._delete(path, destination)
+ success &= self._delete(path, destination, force=True)
+ elif relink:
+ success &= self._delete(path, destination, force=False)
else:
path = source
success &= self._link(path, destination)
@@ -71,24 +74,30 @@ class Linker(Executor):
self._log.lowinfo('Creating directory %s' % parent)
return success
- def _delete(self, source, path):
+ def _delete(self, source, path, force):
success = True
source = os.path.join(self._base_directory, source)
if ((self._is_link(path) and self._link_destination(path) != source) or
(self._exists(path) and not self._is_link(path))):
fullpath = os.path.expanduser(path)
+ removed = False
try:
if os.path.islink(fullpath):
os.unlink(fullpath)
- elif os.path.isdir(fullpath):
- shutil.rmtree(fullpath)
- else:
- os.remove(fullpath)
+ removed = True
+ elif force:
+ if os.path.isdir(fullpath):
+ shutil.rmtree(fullpath)
+ removed = True
+ else:
+ os.remove(fullpath)
+ removed = True
except OSError:
self._log.warning('Failed to remove %s' % path)
success = False
else:
- self._log.lowinfo('Removing %s' % path)
+ if removed:
+ self._log.lowinfo('Removing %s' % path)
return success
def _link(self, source, link_name):