mirror of
1
0
Fork 0

Add Cleaner executor

This commit is contained in:
Anish Athalye 2014-06-08 11:30:10 -07:00
parent 24f49603c8
commit abb825048b
3 changed files with 58 additions and 3 deletions

View File

@ -88,8 +88,9 @@ Configuration
-------------
Dotbot uses json-formatted configuration files to let you specify how to set up
your dotfiles. Currently, Dotbot knows how to `link` files and execute `shell`
commands. Dotbot executes tasks in the order that they are specified in.
your dotfiles. Currently, Dotbot knows how to `link` files, execute `shell`
commands, and `clean` directories of broken symbolic links. Dotbot executes
tasks in the order that they are specified in.
**Ideally, bootstrap configurations should be idempotent. That is, the
installer should be able to be run multiple times without causing any
@ -100,7 +101,8 @@ dictionary that contains a command name mapping to data for that command. For
`link`, you specify how files should be linked in a dictionary. For `shell`,
you specify an array consisting of commands, where each command is an array
consisting of the shell command as the first element and a description as the
second.
second. For `clean`, you specify an array consisting of targets, where each
target is a path to a directory.
Dotbot is aware of a base directory (that is specified when running the
installer), so link targets can be specified relative to that, and shell
@ -111,6 +113,9 @@ started. The convention for configuration file names is `install.conf.json`.
```json
[
{
"clean": ["~"]
},
{
"link": {
"~/.tmux.conf": "tmux.conf",

View File

@ -1,3 +1,4 @@
from .executor import Executor
from .linker import Linker
from .cleaner import Cleaner
from .commandrunner import CommandRunner

View File

@ -0,0 +1,49 @@
import os
from . import Executor
class Cleaner(Executor):
'''
Cleans broken symbolic links.
'''
_directive = 'clean'
def can_handle(self, directive):
return directive == self._directive
def handle(self, directive, data):
if directive != self._directive:
raise ValueError('Cleaner cannot handle directive %s' % directive)
return self._process_clean(data)
def _process_clean(self, targets):
success = True
for target in targets:
success &= self._clean(target)
if success:
self._log.info('All targets have been cleaned')
else:
self._log.error('Some targets were not succesfully cleaned')
return success
def _clean(self, target):
'''
Cleans all the broken symbolic links in target that point to
a subdirectory of the base directory.
'''
for item in os.listdir(os.path.expanduser(target)):
path = os.path.join(os.path.expanduser(target), item)
if not os.path.exists(path) and os.path.islink(path):
if self._in_directory(path, self._base_directory):
self._log.lowinfo('Removing invalid link %s -> %s' %
(path, os.path.join(os.path.dirname(path), os.readlink(path))))
os.remove(path)
return True
def _in_directory(self, path, directory):
'''
Returns true if the path is in the directory.
'''
directory = os.path.join(os.path.realpath(directory), '')
path = os.path.realpath(path)
return os.path.commonprefix([path, directory]) == directory