Add multiple targets
Allow the user to define multiple targets to execute a consistent group of tasks.
This commit is contained in:
parent
38c0f65801
commit
d4f744952e
3 changed files with 159 additions and 90 deletions
86
README.md
86
README.md
|
@ -33,7 +33,7 @@ without the annoyance of having to manually copy or link files.
|
|||
Dotbot itself is entirely self contained and requires no installation (it's
|
||||
self-bootstrapping), so it's not necessary to install any software before you
|
||||
provision a new machine! All you have to do is download your dotfiles and then
|
||||
run `./install`.
|
||||
run `./install -t <list of targets>`.
|
||||
|
||||
Template
|
||||
--------
|
||||
|
@ -94,10 +94,10 @@ installer should be able to be run multiple times without causing any
|
|||
problems.** This makes a lot of things easier to do (in particular, syncing
|
||||
updates between machines becomes really easy).
|
||||
|
||||
Dotbot configuration files are YAML (or JSON) arrays of tasks, where each task
|
||||
is a dictionary that contains a command name mapping to data for that command.
|
||||
Tasks are run in the order in which they are specified. Commands within a task
|
||||
do not have a defined ordering.
|
||||
Dotbot configuration files are YAML (or JSON) dictionaries of targets with
|
||||
arrays of tasks, where each task is a dictionary that contains a command name
|
||||
mapping to data for that command. Tasks are run in the order in which they are
|
||||
specified. Commands within a task do not have a defined ordering.
|
||||
|
||||
### Link
|
||||
|
||||
|
@ -122,7 +122,8 @@ should be forcibly linked.
|
|||
##### Example (YAML)
|
||||
|
||||
```yaml
|
||||
- link:
|
||||
work:
|
||||
- link:
|
||||
~/.config/terminator:
|
||||
create: true
|
||||
path: config/terminator/
|
||||
|
@ -136,7 +137,8 @@ should be forcibly linked.
|
|||
##### Example (JSON)
|
||||
|
||||
```json
|
||||
[{
|
||||
{
|
||||
"work": [{
|
||||
"link": {
|
||||
"~/.config/terminator": {
|
||||
"create": true,
|
||||
|
@ -149,7 +151,8 @@ should be forcibly linked.
|
|||
"path": "zshrc"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Shell
|
||||
|
@ -171,7 +174,8 @@ this syntax, all keys are optional except for the command itself.
|
|||
##### Example (YAML)
|
||||
|
||||
```yaml
|
||||
- shell:
|
||||
work:
|
||||
- shell:
|
||||
- mkdir -p ~/src
|
||||
- [mkdir -p ~/downloads, Creating downloads directory]
|
||||
-
|
||||
|
@ -186,7 +190,8 @@ this syntax, all keys are optional except for the command itself.
|
|||
##### Example (JSON)
|
||||
|
||||
```json
|
||||
[{
|
||||
{
|
||||
"work": [{
|
||||
"shell": [
|
||||
"mkdir -p ~/src",
|
||||
["mkdir -p ~/downloads", "Creating downloads directory"],
|
||||
|
@ -200,7 +205,8 @@ this syntax, all keys are optional except for the command itself.
|
|||
"stderr": true
|
||||
}
|
||||
]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Clean
|
||||
|
@ -216,15 +222,18 @@ Clean commands are specified as an array of directories to be cleaned.
|
|||
##### Example (YAML)
|
||||
|
||||
```yaml
|
||||
- clean: ['~']
|
||||
work:
|
||||
- clean: ['~']
|
||||
```
|
||||
|
||||
##### Example (JSON)
|
||||
|
||||
```json
|
||||
[{
|
||||
{
|
||||
"work": [{
|
||||
"clean": ["~"]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Full Example
|
||||
|
@ -234,16 +243,26 @@ configuration. The conventional name for the configuration file is
|
|||
`install.conf.yaml`.
|
||||
|
||||
```yaml
|
||||
- clean: ['~']
|
||||
common:
|
||||
- clean: ['~']
|
||||
|
||||
- link:
|
||||
- link:
|
||||
~/.dotfiles: ''
|
||||
~/.tmux.conf: tmux.conf
|
||||
~/.vim: vim/
|
||||
~/.vimrc: vimrc
|
||||
|
||||
- shell:
|
||||
- shell:
|
||||
- [git update-submodules, Installing/updating submodules]
|
||||
|
||||
laptop:
|
||||
- shell:
|
||||
- [sudo apt-get install vim, Installing vim]
|
||||
|
||||
server:
|
||||
- shell:
|
||||
- [sudo apt-get install tmux, Installing tmux]
|
||||
- [echo 'Europe/Paris' | sudo tee /etc/timezone > /dev/null && sudo dpkg-reconfigure -f noninteractive tzdata, Configuring timezone]
|
||||
```
|
||||
|
||||
The configuration file can also be written in JSON. Here is the JSON equivalent
|
||||
|
@ -251,7 +270,8 @@ of the YAML configuration given above. The conventional name for this file is
|
|||
`install.conf.json`.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"common": [
|
||||
{
|
||||
"clean": ["~"]
|
||||
},
|
||||
|
@ -268,7 +288,35 @@ of the YAML configuration given above. The conventional name for this file is
|
|||
["git submodule update --init --recursive", "Installing submodules"]
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"laptop": [
|
||||
{
|
||||
"clean": []
|
||||
},
|
||||
{
|
||||
"link": {}
|
||||
},
|
||||
{
|
||||
"shell": [
|
||||
["sudo apt-get install vim", "Installing vim"]
|
||||
]
|
||||
}
|
||||
],
|
||||
"server": [
|
||||
{
|
||||
"clean": []
|
||||
},
|
||||
{
|
||||
"link": {}
|
||||
},
|
||||
{
|
||||
"shell": [
|
||||
["sudo apt-get install tmux", "Installing tmux"],
|
||||
["echo 'Europe/Paris' | sudo tee /etc/timezone > /dev/null && sudo dpkg-reconfigure -f noninteractive tzdata", "Configuring timezone"]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Contributing
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from argparse import ArgumentParser
|
||||
from .config import ConfigReader, ReadingError
|
||||
from .config import ConfigReader, ReadingError, ConfigurationError
|
||||
from .dispatcher import Dispatcher, DispatchError
|
||||
from .messenger import Messenger
|
||||
from .messenger import Level
|
||||
|
@ -17,9 +17,12 @@ def add_options(parser):
|
|||
parser.add_argument('-c', '--config-file', nargs = 1, dest = 'config_file',
|
||||
help = 'run commands given in CONFIGFILE', metavar = 'CONFIGFILE',
|
||||
required = True)
|
||||
parser.add_argument('-t', '--targets', nargs = '*', dest = 'targets',
|
||||
help = 'set the target environments defined in the configuration file', metavar = 'TARGET',
|
||||
required = True)
|
||||
|
||||
def read_config(config_file):
|
||||
reader = ConfigReader(config_file)
|
||||
def read_config(config_file, target):
|
||||
reader = ConfigReader(config_file, target)
|
||||
return reader.get_config()
|
||||
|
||||
def main():
|
||||
|
@ -34,14 +37,20 @@ def main():
|
|||
log.set_level(Level.INFO)
|
||||
if (options.verbose):
|
||||
log.set_level(Level.DEBUG)
|
||||
tasks = read_config(options.config_file[0])
|
||||
targets = options.targets
|
||||
target_tasks = read_config(options.config_file[0], targets)
|
||||
|
||||
success = True
|
||||
for target, tasks in target_tasks.iteritems():
|
||||
log.info('\nExecuting tasks for target %s' % target)
|
||||
dispatcher = Dispatcher(options.base_directory[0])
|
||||
success = dispatcher.dispatch(tasks)
|
||||
success &= dispatcher.dispatch(tasks)
|
||||
|
||||
if success:
|
||||
log.info('\n==> All tasks executed successfully')
|
||||
else:
|
||||
raise DispatchError('\n==> Some tasks were not executed successfully')
|
||||
except (ReadingError, DispatchError) as e:
|
||||
except (ReadingError, DispatchError, ConfigurationError) as e:
|
||||
log.error('%s' % e)
|
||||
exit(1)
|
||||
except KeyboardInterrupt:
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
import yaml
|
||||
from .messenger import Messenger
|
||||
|
||||
class ConfigReader(object):
|
||||
def __init__(self, config_file_path):
|
||||
self._config = self._read(config_file_path)
|
||||
def __init__(self, config_file_path, targets):
|
||||
complete_config = self._read(config_file_path)
|
||||
|
||||
target_configs = {}
|
||||
for target in targets:
|
||||
if not complete_config.has_key(target):
|
||||
raise ConfigurationError('The target %s is not defined in the configuration file' % target)
|
||||
target_configs[target] = complete_config.get(target)
|
||||
|
||||
self._config = target_configs
|
||||
|
||||
def _read(self, config_file_path):
|
||||
try:
|
||||
|
@ -17,3 +26,6 @@ class ConfigReader(object):
|
|||
|
||||
class ReadingError(Exception):
|
||||
pass
|
||||
|
||||
class ConfigurationError(Exception):
|
||||
pass
|
||||
|
|
Loading…
Reference in a new issue