Add functionality to forcibly link items
This commit introduces an extended configuration syntax for linking files and directories. Currently, this syntax allows for specifying items to be forcibly linked, overwriting existing files or directories if necessary. The extended configuration syntax was proposed by Travers McInerney <travers@mcinerney.me>.
This commit is contained in:
parent
58e4fb50b1
commit
13c925be87
2 changed files with 39 additions and 3 deletions
14
README.md
14
README.md
|
@ -91,6 +91,8 @@ have a defined ordering.
|
||||||
### Link
|
### Link
|
||||||
|
|
||||||
Link commands specify how files and directories should be symbolically linked.
|
Link commands specify how files and directories should be symbolically linked.
|
||||||
|
If desired, items can be specified to be forcibly linked, overwriting existing
|
||||||
|
files if necessary.
|
||||||
|
|
||||||
#### Format
|
#### Format
|
||||||
|
|
||||||
|
@ -99,13 +101,23 @@ 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). Source directory names should contain
|
||||||
a trailing "/" character.
|
a trailing "/" character.
|
||||||
|
|
||||||
|
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, and specify "force" as true if the file or directory should be
|
||||||
|
forcibly linked.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"link": {
|
"link": {
|
||||||
"~/.vimrc": "vimrc",
|
"~/.vimrc": "vimrc",
|
||||||
"~/.vim": "vim/"
|
"~/.vim": "vim/",
|
||||||
|
"~/.zshrc": {
|
||||||
|
"path": "zshrc",
|
||||||
|
"force": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import os
|
import os, shutil
|
||||||
from . import Executor
|
from . import Executor
|
||||||
|
|
||||||
class Linker(Executor):
|
class Linker(Executor):
|
||||||
|
@ -19,7 +19,15 @@ class Linker(Executor):
|
||||||
def _process_links(self, links):
|
def _process_links(self, links):
|
||||||
success = True
|
success = True
|
||||||
for destination, source in links.items():
|
for destination, source in links.items():
|
||||||
success &= self._link(source, destination)
|
if isinstance(source, dict):
|
||||||
|
# extended config
|
||||||
|
path = source['path']
|
||||||
|
force = source.get('force', False)
|
||||||
|
if force:
|
||||||
|
success &= self._delete(destination)
|
||||||
|
else:
|
||||||
|
path = source
|
||||||
|
success &= self._link(path, destination)
|
||||||
if success:
|
if success:
|
||||||
self._log.info('All links have been set up')
|
self._log.info('All links have been set up')
|
||||||
else:
|
else:
|
||||||
|
@ -47,6 +55,22 @@ class Linker(Executor):
|
||||||
path = os.path.expanduser(path)
|
path = os.path.expanduser(path)
|
||||||
return os.path.exists(path)
|
return os.path.exists(path)
|
||||||
|
|
||||||
|
def _delete(self, path):
|
||||||
|
success = True
|
||||||
|
if self._exists(path) and not self._is_link(path):
|
||||||
|
fullpath = os.path.expanduser(path)
|
||||||
|
try:
|
||||||
|
if os.path.isdir(fullpath):
|
||||||
|
shutil.rmtree(fullpath)
|
||||||
|
else:
|
||||||
|
os.remove(fullpath)
|
||||||
|
except OSError:
|
||||||
|
self._log.warning('Failed to remove %s' % path)
|
||||||
|
success = False
|
||||||
|
else:
|
||||||
|
self._log.lowinfo('Removing %s' % path)
|
||||||
|
return success
|
||||||
|
|
||||||
def _link(self, source, link_name):
|
def _link(self, source, link_name):
|
||||||
'''
|
'''
|
||||||
Links link_name to source.
|
Links link_name to source.
|
||||||
|
|
Loading…
Reference in a new issue