root / snf-webproject / synnefo / webproject / management / commands / settings.py @ e2c178f2
History | View | Annotate | Download (14.5 kB)
1 |
# Copyright 2013 GRNET S.A. All rights reserved.
|
---|---|
2 |
#
|
3 |
# Redistribution and use in source and binary forms, with or without
|
4 |
# modification, are permitted provided that the following conditions
|
5 |
# are met:
|
6 |
#
|
7 |
# 1. Redistributions of source code must retain the above copyright
|
8 |
# notice, this list of conditions and the following disclaimer.
|
9 |
#
|
10 |
# 2. Redistributions in binary form must reproduce the above copyright
|
11 |
# notice, this list of conditions and the following disclaimer in the
|
12 |
# documentation and/or other materials provided with the distribution.
|
13 |
#
|
14 |
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
15 |
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
16 |
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
17 |
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
18 |
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
19 |
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
20 |
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
21 |
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
22 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
23 |
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
24 |
# SUCH DAMAGE.
|
25 |
#
|
26 |
# The views and conclusions contained in the software and documentation are
|
27 |
# those of the authors and should not be interpreted as representing official
|
28 |
# policies, either expressed or implied, of GRNET S.A.
|
29 |
|
30 |
from synnefo.settings.setup import Setting |
31 |
from django.core.management.base import BaseCommand, CommandError |
32 |
from optparse import make_option |
33 |
from os.path import isdir |
34 |
from pprint import pformat |
35 |
from textwrap import wrap |
36 |
|
37 |
NoValue = Setting.NoValue |
38 |
available_categories = sorted(Setting.Catalogs['categories'].keys()) |
39 |
available_types = sorted(Setting.Catalogs['types'].keys()) |
40 |
|
41 |
|
42 |
class Command(BaseCommand): |
43 |
help = """Display synnefo settings
|
44 |
|
45 |
Example:
|
46 |
settings --select type=mandatory,configured
|
47 |
settings --select hidden --select type=default,
|
48 |
"""
|
49 |
|
50 |
option_list = BaseCommand.option_list + ( |
51 |
make_option( |
52 |
"-s", "--select", |
53 |
type='string',
|
54 |
dest="selection_strings",
|
55 |
action="append",
|
56 |
metavar='[!]selection,...',
|
57 |
help=("List settings that match any comma-separated criteria:"
|
58 |
" all\n"
|
59 |
" type=<setting type>\n"
|
60 |
" category=<setting category>\n"
|
61 |
" hidden\n"
|
62 |
" configured\n"
|
63 |
" <SETTING_NAME>\n"
|
64 |
"\n"
|
65 |
"Available types: {types}\n"
|
66 |
"Available categories: {categories}\n"
|
67 |
"\n"
|
68 |
"Multiple --select options yield the intersection "
|
69 |
"of their results\n"
|
70 |
"Prepending '!' negates the selection criterion\n"
|
71 |
).format(types=available_types, |
72 |
categories=available_categories)), |
73 |
make_option( |
74 |
"-o", "--sort-order", |
75 |
type='string',
|
76 |
dest="sort_order",
|
77 |
action="store",
|
78 |
default='lexical',
|
79 |
help=("Order settings. Available orderings: "
|
80 |
"['lexical', 'source', "
|
81 |
"'category-lexical', 'category-source']")),
|
82 |
make_option( |
83 |
"-d", "--defaults", |
84 |
dest="display_defaults",
|
85 |
action="store_true",
|
86 |
default=False,
|
87 |
help=("Include setting default value.")),
|
88 |
|
89 |
make_option( |
90 |
"-t", "--status", |
91 |
dest="display_status",
|
92 |
action="store_true",
|
93 |
default=False,
|
94 |
help=("Display internal setting status.")),
|
95 |
make_option( |
96 |
"-1", "--oneline", |
97 |
dest="display_multiline",
|
98 |
action="store_false",
|
99 |
default=True,
|
100 |
help=("Display setting in multiple lines")),
|
101 |
make_option( |
102 |
"-l", "--details", |
103 |
dest="display_details",
|
104 |
action="store_true",
|
105 |
default=False,
|
106 |
help=("Display full setting details")),
|
107 |
make_option( |
108 |
"-r", "--runtime", |
109 |
dest="printout_runtime",
|
110 |
action="store_true",
|
111 |
default=False,
|
112 |
help=("Append runtime values in printout.")),
|
113 |
make_option( |
114 |
"-p", "--printout", |
115 |
dest="printout",
|
116 |
action="store_true",
|
117 |
default=False,
|
118 |
help=("Create a printout of settings as comment blocks.")),
|
119 |
make_option( |
120 |
"-f", "--printout-files", |
121 |
dest="printout_files",
|
122 |
action="store",
|
123 |
metavar="SETTINGS-DIRECTORY",
|
124 |
help=("Create a printout of settings grouped "
|
125 |
"in files by category.")),
|
126 |
) |
127 |
|
128 |
def mk_filter_all(self, param): |
129 |
if param != '': |
130 |
m = "Invalid filter parameter '{0}'".format(param)
|
131 |
raise AssertionError(m) |
132 |
|
133 |
def filter_all(setting): |
134 |
return True |
135 |
return filter_all
|
136 |
|
137 |
def mk_filter_category(self, category): |
138 |
if category not in Setting.Catalogs['categories']: |
139 |
m = "Unknown category '{0}'".format(category)
|
140 |
raise CommandError(m)
|
141 |
|
142 |
def filter_category(setting): |
143 |
return setting.category == category
|
144 |
return filter_category
|
145 |
|
146 |
def mk_filter_type(self, setting_type): |
147 |
if setting_type not in Setting.Catalogs['types']: |
148 |
m = "Unknown type '{0}'".format(setting_type)
|
149 |
raise CommandError(m)
|
150 |
|
151 |
def filter_type(setting): |
152 |
return setting.setting_type == setting_type
|
153 |
return filter_type
|
154 |
|
155 |
def mk_filter_hidden(self, hidden): |
156 |
if hidden != '': |
157 |
m = "Invalid hidden filter parameter '{0}'".format(hidden)
|
158 |
raise AssertionError(m) |
159 |
|
160 |
def filter_hidden(setting): |
161 |
return not setting.export |
162 |
return filter_hidden
|
163 |
|
164 |
def mk_filter_configured(self, configured): |
165 |
if configured != '': |
166 |
m = "Invalid configured filter parameter '{0}'".format(configured)
|
167 |
raise AssertionError(m) |
168 |
|
169 |
def filter_configured(setting): |
170 |
return setting.configured_value is not NoValue |
171 |
return filter_configured
|
172 |
|
173 |
def mk_filter_setting(self, setting_name): |
174 |
if not Setting.is_valid_setting_name(setting_name): |
175 |
m = "Invalid setting name '{0}'".format(setting_name)
|
176 |
raise AssertionError(m) |
177 |
|
178 |
def filter_setting(setting): |
179 |
return setting.setting_name == setting_name
|
180 |
return filter_setting
|
181 |
|
182 |
def mk_negate(self, filter_method): |
183 |
def negated_filter(*args, **kwargs): |
184 |
return not filter_method(*args, **kwargs) |
185 |
return negated_filter
|
186 |
|
187 |
_mk_filters = { |
188 |
'all': 'mk_filter_all', |
189 |
'category': 'mk_filter_category', |
190 |
'type': 'mk_filter_type', |
191 |
'configured': 'mk_filter_configured', |
192 |
'hidden': 'mk_filter_hidden', |
193 |
'setting': 'mk_filter_setting', |
194 |
} |
195 |
|
196 |
def parse_selection_filters(self, string): |
197 |
filters = [] |
198 |
for term in string.split(','): |
199 |
key, sep, value = term.partition('=')
|
200 |
if key.startswith('!'): |
201 |
negate = True
|
202 |
key = key[1:]
|
203 |
else:
|
204 |
negate = False
|
205 |
|
206 |
if key not in self._mk_filters: |
207 |
if not Setting.is_valid_setting_name(key): |
208 |
return None |
209 |
value = key |
210 |
key = 'setting'
|
211 |
|
212 |
mk_filter_method = getattr(self, self._mk_filters[key]) |
213 |
if not mk_filter_method: |
214 |
m = "Unknown filter '{0}'".format(key)
|
215 |
raise CommandError(m)
|
216 |
|
217 |
filter_method = mk_filter_method(value) |
218 |
if negate:
|
219 |
filter_method = self.mk_negate(filter_method)
|
220 |
filters.append(filter_method) |
221 |
return filters
|
222 |
|
223 |
def sort_lexical(display_settings): |
224 |
return sorted(display_settings.iteritems()) |
225 |
|
226 |
def sort_source(display_settings): |
227 |
registry = Setting.Catalogs['registry']
|
228 |
sortable = [] |
229 |
for name, setting in display_settings.iteritems(): |
230 |
sortable.append((registry[name], name, setting)) |
231 |
sortable.sort() |
232 |
return [(t[1], t[2]) for t in sortable] |
233 |
|
234 |
def sort_category_lexical(display_settings): |
235 |
sortable = [] |
236 |
for name, setting in display_settings.iteritems(): |
237 |
sortable.append((setting.category, name, setting)) |
238 |
sortable.sort() |
239 |
return [(t[1], t[2]) for t in sortable] |
240 |
|
241 |
def sort_category_source(display_settings): |
242 |
registry = Setting.Catalogs['registry']
|
243 |
sortable = [] |
244 |
for name, setting in display_settings.iteritems(): |
245 |
sortable.append((setting.category, registry[name], setting)) |
246 |
sortable.sort() |
247 |
return [(t[1], t[2]) for t in sortable] |
248 |
|
249 |
sort_methods = { |
250 |
'lexical': sort_lexical,
|
251 |
'source': sort_source,
|
252 |
'category-lexical': sort_category_lexical,
|
253 |
'category-source': sort_category_source,
|
254 |
} |
255 |
|
256 |
def display_console(self, display_settings_list, options): |
257 |
for name, setting in display_settings_list: |
258 |
format_str = "{name} = {value}"
|
259 |
flags = [] |
260 |
|
261 |
if setting.runtime_value == setting.default_value:
|
262 |
flags.append('default')
|
263 |
|
264 |
if setting.configured_value is not NoValue: |
265 |
flags.append('configured')
|
266 |
if setting.runtime_value != setting.configured_value:
|
267 |
flags.append('runtime')
|
268 |
|
269 |
value = setting.runtime_value |
270 |
default_value = setting.default_value |
271 |
example_value = setting.example_value |
272 |
dependencies = setting.dependencies |
273 |
description = setting.description |
274 |
sep = " # "
|
275 |
eol = ""
|
276 |
|
277 |
if options['display_multiline']: |
278 |
value = pformat(value) |
279 |
default_value = pformat(default_value) |
280 |
example_value = pformat(example_value) |
281 |
dependencies = pformat(dependencies) |
282 |
sep = "\n # "
|
283 |
description = (sep + ' ').join(wrap(description, 70)) |
284 |
eol = "\n"
|
285 |
|
286 |
format_args = {'name': name,
|
287 |
'value': value,
|
288 |
'example': example_value,
|
289 |
'default': default_value,
|
290 |
'description': description,
|
291 |
'dependencies': dependencies,
|
292 |
'serial': setting.serial,
|
293 |
'configured_depth': setting.configured_depth,
|
294 |
'configured_source': setting.configured_source,
|
295 |
'configure_callback': setting.configure_callback,
|
296 |
'flags': ','.join(flags)} |
297 |
|
298 |
sep = "\n # " if options['display_multiline'] else " # " |
299 |
eol = "\n" if options['display_multiline'] else "" |
300 |
|
301 |
if options['display_details'] or options['display_defaults']: |
302 |
format_str += sep + "Default: {default}"
|
303 |
|
304 |
if options['display_details'] or options['display_status']: |
305 |
format_str += sep + "Flags: {flags}"
|
306 |
|
307 |
if options['display_details']: |
308 |
format_str += sep + "Description: {description}"
|
309 |
format_str += sep + "Dependencies: {dependencies}"
|
310 |
format_str += sep + "Depth: {configured_depth}"
|
311 |
format_str += sep + "Serial: {serial}"
|
312 |
format_str += sep + "Callback: {configure_callback}"
|
313 |
format_str += sep + "Source: {configured_source}"
|
314 |
|
315 |
line = format_str.format(**format_args) + eol |
316 |
print line
|
317 |
|
318 |
def display_printout(self, display_settings_list, runtime=False): |
319 |
for name, setting in display_settings_list: |
320 |
comment = setting.present_as_comment(runtime=runtime) + '\n'
|
321 |
print comment
|
322 |
|
323 |
def printout_files(self, display_settings_list, path, runtime=False): |
324 |
if not isdir(path): |
325 |
m = "Cannot find directory '{path}'".format(path=path)
|
326 |
raise CommandError(m)
|
327 |
|
328 |
category_depths = {} |
329 |
for name, setting in Setting.Catalogs['settings'].iteritems(): |
330 |
category = setting.category |
331 |
if (category not in category_depths or |
332 |
setting.configured_depth > category_depths[category]): |
333 |
category_depths[category] = setting.configured_depth |
334 |
|
335 |
old_filepath = None
|
336 |
conffile = None
|
337 |
filepath = None
|
338 |
for name, setting in display_settings_list: |
339 |
category = setting.category |
340 |
category_depth = 10 * category_depths[category]
|
341 |
filepath = '{path}/{depth}-{category}.conf'
|
342 |
filepath = filepath.format(path=path, |
343 |
depth=category_depth, |
344 |
category=category) |
345 |
if filepath != old_filepath:
|
346 |
if conffile:
|
347 |
conffile.close() |
348 |
conffile = open(filepath, "a") |
349 |
old_filepath = filepath |
350 |
conffile.write(setting.present_as_comment(runtime=runtime)) |
351 |
conffile.write('\n')
|
352 |
|
353 |
def handle(self, *args, **options): |
354 |
if args:
|
355 |
raise CommandError("This command takes no arguments. Only options") |
356 |
|
357 |
selection_strings = options["selection_strings"]
|
358 |
if not selection_strings: |
359 |
selection_strings = ['configured']
|
360 |
|
361 |
and_filters = [self.parse_selection_filters(s)
|
362 |
for s in selection_strings] |
363 |
|
364 |
settings_dict = Setting.Catalogs['settings']
|
365 |
display_settings = {} |
366 |
for name, setting in settings_dict.items(): |
367 |
if all(any(or_filter(setting) for or_filter in and_filter) |
368 |
for and_filter in and_filters): |
369 |
display_settings[name] = setting |
370 |
|
371 |
sort_order = options['sort_order']
|
372 |
if sort_order not in self.sort_methods: |
373 |
m = "Unknown sort method '{0}'".format(sort_order)
|
374 |
raise CommandError(m)
|
375 |
|
376 |
sort_method = self.sort_methods[sort_order]
|
377 |
display_settings_list = sort_method(display_settings) |
378 |
|
379 |
if options['printout']: |
380 |
self.display_printout(display_settings_list,
|
381 |
options['printout_runtime'])
|
382 |
elif options['printout_files']: |
383 |
self.printout_files(display_settings_list,
|
384 |
options['printout_files'],
|
385 |
options['printout_runtime'])
|
386 |
else:
|
387 |
self.display_console(display_settings_list, options)
|