1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright (c) 2012 Red Hat, Inc.
5
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6
# not use this file except in compliance with the License. You may obtain
7
# a copy of the License at
9
# http://www.apache.org/licenses/LICENSE-2.0
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
# License for the specific language governing permissions and limitations
23
Compatibility code for handling the deprecated --flagfile option.
25
gflags style configuration files are deprecated and will be removed in future.
27
The code in this module transles --flagfile options into --config-file and can
28
be removed when support for --flagfile is removed.
32
def _get_flagfile(argp):
33
'''Parse the filename from a --flagfile argument.
35
The current and next arguments are passed as a 2 item list. If the
36
flagfile filename is in the next argument, the two arguments are
37
joined into the first item while the second item is set to None.
39
i = argp[0].find('-flagfile')
43
# Accept -flagfile or -flagfile
44
if i != 0 and (i != 1 or argp[0][i] != '-'):
48
if i == len(argp[0]): # Accept [-]-flagfile foo
49
argp[0] += '=' + argp[1]
52
if argp[0][i] != '=': # Accept [-]-flagfile=foo
55
return argp[0][i + 1:]
58
def _open_file_for_reading(path):
59
'''Helper method which test code may stub out.'''
60
return open(path, 'r')
63
def _open_fd_for_writing(fd, _path):
64
'''Helper method which test code may stub out.'''
65
return os.fdopen(fd, 'w')
68
def _read_lines(flagfile):
69
'''Read a flag file, returning all lines with comments stripped.'''
70
with _open_file_for_reading(flagfile) as f:
74
if l.isspace() or l.startswith('#') or l.startswith('//'):
80
def _read_flagfile(arg, next_arg, tempdir=None):
81
'''Convert a --flagfile argument to --config-file.
83
If the supplied argument is a --flagfile argument, read the contents
84
of the file and convert it to a .ini format config file. Return a
85
--config-file argument with the converted file.
87
If the flag file contains more --flagfile arguments, multiple
88
--config-file arguments will be returned.
90
The returned argument list may also contain None values which should
91
be filtered out later.
93
argp = [arg, next_arg]
94
flagfile = _get_flagfile(argp)
98
args = _read_lines(flagfile)
100
if args and not args[0].startswith('--'):
101
# This is a config file, not a flagfile, so return it.
102
return ['--config-file=' + flagfile] + argp[1:]
105
# We're recursing here to convert any --flagfile arguments
106
# read from this flagfile into --config-file arguments
108
# We don't actually include those --config-file arguments
109
# in the generated config file; instead we include all those
110
# --config-file args in the final command line
112
args = _iterate_args(args, _read_flagfile, tempdir=tempdir)
114
config_file_args = []
116
(fd, tmpconf) = tempfile.mkstemp(suffix='.conf', dir=tempdir)
118
with _open_fd_for_writing(fd, tmpconf) as f:
119
f.write('[DEFAULT]\n')
121
if arg.startswith('--config-file='):
122
config_file_args.append(arg)
125
f.write(arg[2:] + '\n')
126
elif arg[2:].startswith('no'):
127
f.write(arg[4:] + '=false\n')
129
f.write(arg[2:] + '=true\n')
131
return ['--config-file=' + tmpconf] + argp[1:] + config_file_args
134
def _iterate_args(args, iterator, **kwargs):
135
'''Run an iterator function on the supplied args list.
137
The iterator is passed the current arg and next arg and returns a
138
list of args. The returned args replace the suppied args in the
141
The iterator will be passed None for the next arg when processing
147
for i in range(len(args)):
148
if args[i] is None: # last item, or consumed file name
151
modified = iterator(args[i], args[i + 1], **kwargs)
152
args[i], args[i + 1] = modified[:2]
154
ret.extend(modified[:1] + modified[2:]) # don't append next arg
156
return filter(None, ret)
159
def handle_flagfiles(args, tempdir=None):
160
'''Replace --flagfile arguments with --config-file arguments.
162
Replace any --flagfile argument in the supplied list with a --config-file
163
argument containing a temporary config file with the contents of the flag
164
file translated to .ini format.
166
The tempdir argument is a directory which will be used to create temporary
169
return _iterate_args(args[:], _read_flagfile, tempdir=tempdir)
172
@contextlib.contextmanager
173
def handle_flagfiles_managed(args):
174
'''A context manager for handle_flagfiles() which removes temp files.
176
For use with the 'with' statement, i.e.::
178
with handle_flagfiles_managed(args) as args:
180
# Any temporary fils have been removed
182
# NOTE(johannes): Would be nice to use utils.tempdir(), but it
183
# causes an import loop
184
tempdir = tempfile.mkdtemp(prefix='nova-conf-')
186
yield handle_flagfiles(args, tempdir=tempdir)
188
shutil.rmtree(tempdir)