-
Notifications
You must be signed in to change notification settings - Fork 4
/
deploy
executable file
·220 lines (190 loc) · 7.39 KB
/
deploy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#!/usr/bin/env python
import sys
import getopt
import os.path
import shutil
import subprocess
def get_files(dire):
"""list files from directory, skipping backup files
Arguments:
- `dire`:
"""
import re
return [x for x in os.listdir(dire) if not re.match(r'[#]?.*[#~]', x)]
#####################
# files configuration
#####################
# list of files for each group
apps_list = get_files('apps')
configs_list = get_files('config')
# each group descriptor
# list of files, prefix, function to rename
apps_tuple = (apps_list, '~/bin', None)
configs_tuple = (configs_list, '~', lambda x: '.' + x) # config files usually have . prefix
# list of groups
deployable_objects = { 'apps' : apps_tuple,
'config' : configs_tuple }
########################
# files configuratio end
########################
class DeployError(Exception):
def __init__(self, what, was_error = True, show_usage = False):
self.__what = what
self.was_error = was_error
self.show_usage = show_usage
def __str__(self):
return str(self.__what)
def show_usage():
print '''deploy - config install tool
Usage: deploy [-l] [-d] [-h] [-p path] group [entry]
-l list entries
-p custom perfix, if other than $HOME
-f force overwrite
-d check if source files and already present files in their
destination locations are different (only files)
-h show help
'''
def list_all_entries():
''' will list all entries in tree-like form'''
for group, entries_tuple in deployable_objects.items():
print '+- %s (default install prefix: %s)' % (group, entries_tuple[1])
for en in entries_tuple[0][:-1]:
print ' +- %s' % (en)
print ' \- %s' % (entries_tuple[0][-1])
def compare_single_entry(src_path, dst_path):
'''compare given paths and return True if files are the same
or False otherwise'''
cmd = ['cmp', '-s', src_path, dst_path]
returncode = subprocess.call(cmd)
if returncode != 0:
return False
return True
def compare_all_entries(prefix = None):
'''check if files (only files) differ by calling cmp -s
optional prefix should already be expanded'''
for group, entries_tuple in deployable_objects.items():
# get default prefix
p = os.path.expanduser(entries_tuple[1])
if prefix:
p = prefix
for en in entries_tuple[0]:
src_file = group + os.sep + en
dst_file = p + os.sep
if entries_tuple[2]: # use the file rename function that was provided
dst_file += entries_tuple[2](en)
else:
dst_file += en
if os.path.exists(dst_file) and not os.path.isdir(dst_file):
if not compare_single_entry(src_file, dst_file):
print '%s and %s differ' % (src_file, dst_file)
def deploy_single_object(from_path, to_path, force = False):
'''deploy single file/directory, if destination path already
exists, depending on force flag it will or will not be overwritten'''
path_exists = os.path.exists(to_path) # check if we do not overwrite by chance
sys.stdout.write('deploy %s as %s: ' % (from_path, to_path))
try:
if not path_exists or (path_exists and force):
info_msg = ''
if os.path.isdir(from_path):
if path_exists: # force condition was checked before
shutil.rmtree(to_path)
info_msg = 'original target removed - '
shutil.copytree(from_path, to_path)
else:
shutil.copy2(from_path, to_path)
sys.stdout.write('OK')
if path_exists and force:
info_msg += 'overwrite'
sys.stdout.write(' (%s)\n' % (info_msg))
else:
sys.stdout.write('\n')
else:
sys.stdout.write('path exists - skip (use -f)\n')
except OSError, e:
sys.stdout.write('ERROR (%d - %s)\n' % (e.errno, e.strerror))
def deploy_objects(group_name, objects_list, prefix = None, force = False):
'''will deploy the requested objects
the first element of list is the name of the group
the subsequent elements are the objects in the group
force flag controls whether the target will be overwritten
optional prefix should already be expanded'''
# first entry in args list is group
if not deployable_objects.has_key(group_name):
raise DeployError('group %s not found' % (group_name))
to_deploy_list = [] # elements that will be deployed
objects_group_tuple = deployable_objects[group_name]
from_dir = group_name
if len(objects_list) < 1:
# user passed only a group name
# deploy all objects in group
to_deploy_list = objects_group_tuple[0]
else: # len >= 1
# user passed names of specific objects to deploy
# check if these exist
to_deploy_list = []
for ob in objects_list:
if ob in objects_group_tuple[0]:
to_deploy_list.append(ob)
else:
raise DeployError('entry %s not found in group %s' % (ob, group_name))
# handle prefix
if prefix == None:
prefix = os.path.expanduser(objects_group_tuple[1])
# dump path separator if present
if prefix[-1] == os.sep:
prefix = prefix[:-1]
# deploy all targets, one by one
for depobj in to_deploy_list:
from_path = from_dir + os.sep + depobj
# target path can be overriden by additional function
if objects_group_tuple[2]:
depobj = objects_group_tuple[2](depobj)
to_path = prefix + os.sep + depobj
try:
# make sure that prefix exists
if not os.path.exists(prefix):
os.makedirs(prefix)
deploy_single_object(from_path, to_path, force)
except OSError, e:
print '%s: ERROR (%d - %s)' % (to_path, e.errno, e.strerror)
print 'all done'
if __name__ == '__main__':
try:
optlist = []
args = []
custom_prefix = None
force = False
run_cmp = False
try:
optlist, args = getopt.getopt(sys.argv[1:], 'lhp:fd')
except getopt.GetoptError, e:
raise DeployError(str(e), show_usage = True)
list_entries = False
for opt, optarg in optlist:
if opt == '-l':
list_entries = True
elif opt == '-h':
raise DeployError('', was_error = False, show_usage = True)
elif opt == '-p':
custom_prefix = os.path.expanduser(optarg)
elif opt == '-f':
force = True
elif opt == '-d':
run_cmp = True
if list_entries:
# just list all entries in tree form
list_all_entries()
elif run_cmp:
# compare of source objects and destination differ
compare_all_entries(custom_prefix)
else:
# user wants to deploy files
if len(args) == 0:
raise DeployError('no objects to deploy specified', show_usage = True)
deploy_objects(args[0], args[1:], custom_prefix, force)
except DeployError, de:
if de.was_error:
print 'error: %s' % (str(de))
if de.show_usage:
show_usage()
sys.exit(1)