1
|
#!/usr/bin/env python
|
2
|
#
|
3
|
# Copyright (c) 2012 Cabo A/S
|
4
|
# All rights reserved.
|
5
|
#
|
6
|
# Written by Dan Villiom Podlaski Christiansen <dan@cabo.dk>
|
7
|
#
|
8
|
|
9
|
'''
|
10
|
Script and module for updating or combining a configuration file with
|
11
|
changes in a template.
|
12
|
'''
|
13
|
|
14
|
import itertools
|
15
|
import os
|
16
|
import sys
|
17
|
|
18
|
import configobj
|
19
|
|
20
|
def _readfile(path):
|
21
|
''' read the entire contents of 'path'. Equivalent to:
|
22
|
|
23
|
>>> open(path).read()
|
24
|
|
25
|
but without relying on reference counting to immediately close the file.
|
26
|
'''
|
27
|
with open(path) as fd:
|
28
|
return fd.read()
|
29
|
|
30
|
def _removedups(lst):
|
31
|
'''
|
32
|
Return a copy of the list with all duplicates removed
|
33
|
|
34
|
http://stackoverflow.com/a/6197827/136864
|
35
|
'''
|
36
|
dset = set()
|
37
|
|
38
|
# relies on the fact that dset.add() always returns None.
|
39
|
return [ l for l in lst if
|
40
|
l not in dset and not dset.add(l) ]
|
41
|
|
42
|
|
43
|
def combineconfig(config, template):
|
44
|
'''
|
45
|
update the given config with new entries (and comments) from the
|
46
|
template
|
47
|
'''
|
48
|
|
49
|
template = configobj.ConfigObj(template.splitlines())
|
50
|
|
51
|
try:
|
52
|
config = configobj.ConfigObj(config.splitlines(), raise_errors=True)
|
53
|
except configobj.DuplicateError:
|
54
|
config = \
|
55
|
configobj.ConfigObj(_removedups(config.splitlines()))
|
56
|
|
57
|
for key, value in config.items():
|
58
|
if key not in template:
|
59
|
template[key] = value
|
60
|
template.comments[key] = config.comments[key] or ['']
|
61
|
template.comments[key].append('# UNUSED!')
|
62
|
else:
|
63
|
template[key] = value
|
64
|
|
65
|
if not template.comments[key] and any(config.comments[key]):
|
66
|
template.comments[key] = config.comments[key]
|
67
|
|
68
|
return template
|
69
|
|
70
|
def main(args):
|
71
|
'''main entry point'''
|
72
|
|
73
|
try:
|
74
|
if len(args) != 3 and len(args) != 4:
|
75
|
sys.stderr.write('usage: %s <config> <template> [dest]\n' %
|
76
|
os.path.basename(args[0]))
|
77
|
return 1
|
78
|
|
79
|
configpath = args[1]
|
80
|
templatepath = args[2]
|
81
|
|
82
|
config = combineconfig(_readfile(configpath), _readfile(templatepath))
|
83
|
|
84
|
if len(args) == 4:
|
85
|
with open(args[3], 'w') as outfd:
|
86
|
config.write(outfd)
|
87
|
else:
|
88
|
config.write(sys.stdout)
|
89
|
|
90
|
return 0
|
91
|
except Exception as e:
|
92
|
import traceback
|
93
|
traceback.print_exc()
|
94
|
return 1
|
95
|
|
96
|
if __name__ == '__main__':
|
97
|
sys.exit(main(sys.argv))
|