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.
This commit is contained in:
parent
db8364490d
commit
3725d21684
2 changed files with 22 additions and 10 deletions
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in a new issue