14 # See the License for the specific language governing permissions and |
14 # See the License for the specific language governing permissions and |
15 # limitations under the License. |
15 # limitations under the License. |
16 |
16 |
17 """Custom optparse OptionParser and functions for reading Python settings files. |
17 """Custom optparse OptionParser and functions for reading Python settings files. |
18 |
18 |
|
19 Default values for trunk/scripts flags can be specified in valid Python syntax |
|
20 in the ~/.soc_scripts_settings file. For example, a default value for the |
|
21 --user flag can be specified with a variable assignment in the settings file |
|
22 like: |
|
23 |
|
24 user = 'joeuser' |
|
25 |
|
26 Defaults in the ~/.soc_scripts_settings file can be explicitly overridden by |
|
27 supplied the actual flag. For example, supplying: |
|
28 |
|
29 --user=someotheruser |
|
30 |
|
31 would override the default value present in the settings file. |
|
32 |
19 Option: class derived from optparse.Option that adds a 'required' parameter |
33 Option: class derived from optparse.Option that adds a 'required' parameter |
20 OptionParser: class derived from optparse.OptionParser for use with Option |
34 OptionParser: class derived from optparse.OptionParser for use with Option |
21 |
35 |
22 readPythonSettings(): interprets a valid Python file as a settings file |
36 readPythonSettings(): interprets a valid Python file as a settings file |
23 """ |
37 """ |
100 for option in self.option_list: |
114 for option in self.option_list: |
101 if (isinstance(option, Option) |
115 if (isinstance(option, Option) |
102 and option.required |
116 and option.required |
103 and (not self.option_seen.has_key(option))): |
117 and (not self.option_seen.has_key(option))): |
104 errors.append( |
118 errors.append( |
105 'required %s option not supplied' % option) |
119 'required %s option not supplied' |
|
120 ' (and default settings not allowed)' % option) |
106 |
121 |
107 if errors: |
122 if errors: |
108 self.error(*errors) |
123 self.error(*errors) |
109 |
124 |
110 return values, args |
125 return values, args |
|
126 |
|
127 |
|
128 def printErrors(errors, exit_code=1): |
|
129 """Prints error message strings to sys.stderr and returns an exit code. |
|
130 |
|
131 Args: |
|
132 errors: error message string or list of error message strings to be printed |
|
133 to sys.stderr |
|
134 exit_code: exit code to return (so that this function can be used as an |
|
135 expression in sys.exit() for example); default is 1 |
|
136 |
|
137 Returns: |
|
138 exit_code |
|
139 """ |
|
140 sys.stderr.write('\nERRORS:\n') |
|
141 |
|
142 if (not isinstance(errors, tuple)) and (not isinstance(errors, list)): |
|
143 errors = [errors] |
|
144 |
|
145 for msg in errors: |
|
146 sys.stderr.write(' %s\n' % msg) |
|
147 |
|
148 sys.stderr.write('\n') |
|
149 |
|
150 return exit_code |
|
151 |
|
152 |
|
153 def printErrorsAndUsage(errors, parser, exit_code=1): |
|
154 """Prints error messages and usage text to sys.stderr and returns exit code. |
|
155 |
|
156 Args: |
|
157 errors: error message string or list of error message strings to be printed |
|
158 to sys.stderr |
|
159 parser: OptionParser with a print_help() method |
|
160 exit_code: exit code to return (so that this function can be used as an |
|
161 expression in sys.exit() for example); default is 1 |
|
162 |
|
163 Returns: |
|
164 exit_code |
|
165 """ |
|
166 exit_code = printErrors(errors, exit_code=exit_code) |
|
167 parser.print_help(file=sys.stderr) |
|
168 |
|
169 return exit_code |
|
170 |
|
171 |
|
172 def getExpandedPath(path): |
|
173 """Returns an expanded, normalized, absolute path. |
|
174 |
|
175 Args: |
|
176 path: path (possibly relative, possibly containing environment variables, |
|
177 etc.) to be expanded, normalized and made absolute |
|
178 |
|
179 Returns: |
|
180 absolute path, after expanding any environment variables and "~", then |
|
181 removing excess . and .. path elements |
|
182 """ |
|
183 return os.path.abspath( |
|
184 os.path.normpath( |
|
185 os.path.expanduser( |
|
186 os.path.expandvars(path)))) |
111 |
187 |
112 |
188 |
113 def readPythonSettings(defaults={}, # {} OK since defaults is always copied |
189 def readPythonSettings(defaults={}, # {} OK since defaults is always copied |
114 settings_dir=DEF_SETTINGS_FILE_DIR, |
190 settings_dir=DEF_SETTINGS_FILE_DIR, |
115 settings_file=DEF_SETTINGS_FILE_NAME): |
191 settings_file=DEF_SETTINGS_FILE_NAME): |
134 # do not let the original defaults be altered |
210 # do not let the original defaults be altered |
135 defaults = defaults.copy() |
211 defaults = defaults.copy() |
136 |
212 |
137 # form absolute path to the settings file, expanding any environment |
213 # form absolute path to the settings file, expanding any environment |
138 # variables and "~", then removing excess . and .. path elements |
214 # variables and "~", then removing excess . and .. path elements |
139 path = os.path.abspath( |
215 path = getExpandedPath(os.path.join(settings_dir, settings_file)) |
140 os.path.normpath( |
|
141 os.path.expanduser( |
|
142 os.path.expandvars( |
|
143 os.path.join(settings_dir, settings_file))))) |
|
144 |
216 |
145 # empty dict to capture the local variables in the settings file |
217 # empty dict to capture the local variables in the settings file |
146 settings_locals = {} |
218 settings_locals = {} |
147 |
219 |
148 try: |
220 try: |
160 |
232 |
161 # overwrite defaults copy with values from the (possibly empty) settings file |
233 # overwrite defaults copy with values from the (possibly empty) settings file |
162 defaults.update(settings_locals) |
234 defaults.update(settings_locals) |
163 |
235 |
164 return defaults |
236 return defaults |
|
237 |
|
238 |
|
239 def readPythonSettingsOrDie(parser=None, |
|
240 defaults={}, # {} OK since defaults is always copied |
|
241 settings_dir=DEF_SETTINGS_FILE_DIR, |
|
242 settings_file=DEF_SETTINGS_FILE_NAME): |
|
243 """Calls readPythonSettings(), calling sys.exit() on any errors. |
|
244 |
|
245 Args: |
|
246 parser: if supplied, an OptionParser instance used to call print_help() |
|
247 to print usage information if errors occur |
|
248 defaults, settings_dir, settings_file: see readPythonSettings() |
|
249 |
|
250 Returns: |
|
251 On success, returns results of readPythonSettings(). |
|
252 |
|
253 Exits: |
|
254 On any error from readPythonSettings(), prints error messages to stderr, |
|
255 possibly prints usage information, and calls sys.exit(1). |
|
256 """ |
|
257 try: |
|
258 return readPythonSettings(defaults=defaults, settings_dir=settings_dir, |
|
259 settings_file=settings_file) |
|
260 except Error, error: |
|
261 if parser: |
|
262 sys.exit(printErrorsAndUsage(error.args, parser)) |
|
263 else: |
|
264 sys.exit(printErrors(error.args)) |
|
265 |
|
266 |
|
267 def makeOptionParserOrDie(*args, **kwargs): |
|
268 """Creates and returns an OptionParser, calling sys.exit() on any errors. |
|
269 |
|
270 Args: |
|
271 *args, **kwargs: supplied directly to OptionParser constructor |
|
272 |
|
273 Returns: |
|
274 On success, returns an OptionParser instance. |
|
275 |
|
276 Exits: |
|
277 On any error, prints error messages to stderr and calls sys.exit(1). |
|
278 """ |
|
279 try: |
|
280 return OptionParser(*args, **kwargs) |
|
281 except Error, error: |
|
282 sys.exit(printErrors(error.args)) |
|
283 |
|
284 |
|
285 def parseOptionsOrDie(parser, args): |
|
286 """Parses command-line options, calling sys.exit() on any errors. |
|
287 |
|
288 Args: |
|
289 parser: an OptionParser instance |
|
290 args: list of command-line arguments to supply to parser |
|
291 |
|
292 Returns: |
|
293 On success, returns (options, args) returned by parser.parse_args(args). |
|
294 |
|
295 Exits: |
|
296 On any error, prints error messages and usage information to stderr and |
|
297 calls sys.exit(1). |
|
298 """ |
|
299 try: |
|
300 return parser.parse_args(args) |
|
301 except Error, error: |
|
302 sys.exit(printErrorsAndUsage(error.args, parser)) |
|
303 |
|
304 |
|
305 def checkCommonSvnOptions(options): |
|
306 """Checks a common subset of command-line options. |
|
307 |
|
308 Multiple scripts accept a subset of common command-line options. |
|
309 |
|
310 Args: |
|
311 options: OptionParser.parse_args() options instance to check |
|
312 |
|
313 Returns: |
|
314 list of error message strings, or an empty list if no errors |
|
315 """ |
|
316 errors = [] |
|
317 |
|
318 if not options.repo: |
|
319 errors.extend( |
|
320 ['--repo must be supplied or have a settings file default']) |
|
321 |
|
322 if not options.wc: |
|
323 errors.extend( |
|
324 ['--wc must be supplied or have a settings file default']) |
|
325 |
|
326 if not options.branch: |
|
327 if not options.user: |
|
328 errors.extend( |
|
329 ['at least one of --branch or --user must be supplied']) |
|
330 |
|
331 return errors |
|
332 |
|
333 |
|
334 def checkCommonSvnOptionsOrDie(options, parser): |
|
335 """Checks subset of command-line options, calling sys.exit() on any errors. |
|
336 |
|
337 Args: |
|
338 options: see checkCommonSvnOptions() |
|
339 parser: an OptionParser instance used to call print_help() to print |
|
340 usage information if errors occur |
|
341 |
|
342 Exits: |
|
343 On any error messages returned by checkCommonSvnOptions(), prints error |
|
344 messages and usage information to stderr and calls sys.exit(1). |
|
345 """ |
|
346 errors = checkCommonSvnOptions(options) |
|
347 |
|
348 if errors: |
|
349 sys.exit(printErrorsAndUsage(errors, parser)) |