~ubuntu-branches/ubuntu/intrepid/xen-3.3/intrepid-updates

« back to all changes in this revision

Viewing changes to tools/python/xen/xm/opts.py

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2008-08-14 10:28:57 UTC
  • Revision ID: james.westby@ubuntu.com-20080814102857-a832fn5gowurz5do
Tags: upstream-3.3.0
ImportĀ upstreamĀ versionĀ 3.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#============================================================================
 
2
# This library is free software; you can redistribute it and/or
 
3
# modify it under the terms of version 2.1 of the GNU Lesser General Public
 
4
# License as published by the Free Software Foundation.
 
5
#
 
6
# This library is distributed in the hope that it will be useful,
 
7
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
8
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
9
# Lesser General Public License for more details.
 
10
#
 
11
# You should have received a copy of the GNU Lesser General Public
 
12
# License along with this library; if not, write to the Free Software
 
13
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
14
#============================================================================
 
15
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
 
16
# Copyright (C) 2005 XenSource Ltd.
 
17
#============================================================================
 
18
 
 
19
"""Object-oriented command-line option support.
 
20
"""
 
21
import getopt
 
22
import os
 
23
import os.path
 
24
import sys
 
25
import types
 
26
 
 
27
 
 
28
 
 
29
def _line_wrap(text, width = 70):
 
30
    lines = []
 
31
    current_line = ''
 
32
    words = text.strip().split()
 
33
    while words:
 
34
        word = words.pop(0)
 
35
        if len(current_line) + len(word) + 1 < width:
 
36
            current_line += word + ' '
 
37
        else:
 
38
            lines.append(current_line.strip())
 
39
            current_line = word + ' '
 
40
            
 
41
    if current_line:
 
42
        lines.append(current_line.strip())
 
43
    return lines
 
44
 
 
45
def wrap(text, width = 70):
 
46
    """ Really basic textwrap. Useful because textwrap is not available
 
47
    for Python 2.2, and textwrap.wrap ignores newlines in Python 2.3+.
 
48
    """
 
49
    if len(text) < width:
 
50
        return [text]
 
51
    
 
52
    lines = []
 
53
    for line in text.split('\n'):
 
54
        lines += _line_wrap(line, width)
 
55
    return lines
 
56
 
 
57
class OptionError(Exception):
 
58
    """Denotes an error in option parsing."""
 
59
    def __init__(self, message, usage = ''):
 
60
        self.message = message
 
61
        self.usage = usage
 
62
    def __str__(self):
 
63
        return self.message
 
64
 
 
65
class XMLFileError(Exception):
 
66
    """Thrown is input is an XML File"""
 
67
    def __init__(self, XMLFile):
 
68
        self.XMLFile = XMLFile
 
69
    def __str__(self):
 
70
        return "XMLFileError: %s" % self.XMLFile
 
71
    def getFile(self):
 
72
        return self.XMLFile
 
73
 
 
74
class Opt:
 
75
    """An individual option.
 
76
    """
 
77
    def __init__(self, opts, name, short=None, long=None,
 
78
                 val=None, fn=None, use=None, default=None):
 
79
        """Create an option.
 
80
 
 
81
        opts    parent options object
 
82
        name    name of the field it controls
 
83
        short   short (1-char) command line switch (optional)
 
84
        long    long command-line switch. Defaults to option name.
 
85
        val     string used to print option args in help.
 
86
                If val is not specified the option has no arg.
 
87
        fn      function to call when the option is specified.
 
88
        use     usage (help) string
 
89
        default default value if not specified on command-line
 
90
        """
 
91
        self.opts = opts
 
92
        self.name = name
 
93
        self.short = short
 
94
        if long is None:
 
95
            long = name
 
96
        self.long = long
 
97
        self.val = val
 
98
        self.use = use
 
99
        self.default = default
 
100
        self.optkeys = []
 
101
        if self.short:
 
102
            self.optkeys.append('-' + self.short)
 
103
        if self.long:
 
104
            self.optkeys.append('--' + self.long)
 
105
        self.fn = fn
 
106
        self.specified_opt = None
 
107
        self.specified_val = None
 
108
        self.value = None
 
109
        self.set(default)
 
110
 
 
111
 
 
112
    def reset(self):
 
113
        self.specified_opt = None
 
114
        self.specified_val = None
 
115
        self.value = None
 
116
        self.set(self.default)
 
117
 
 
118
 
 
119
    def __repr__(self):
 
120
        return self.name + '=' + str(self.specified_val)
 
121
 
 
122
    def __str__(self):
 
123
        """ Formats the option into:
 
124
        '-k, --key     description'
 
125
        """
 
126
        PARAM_WIDTH = 20
 
127
        if self.val:
 
128
            keys = ', '.join(['%s=%s' % (k, self.val) for k in self.optkeys])
 
129
        else:
 
130
            keys = ', '.join(self.optkeys)
 
131
        desc = wrap(self.use, 55)
 
132
        if len(keys) > PARAM_WIDTH:
 
133
            desc = [''] + desc
 
134
            
 
135
        wrapped = ('\n' + ' ' * (PARAM_WIDTH + 1)).join(desc)
 
136
        return keys.ljust(PARAM_WIDTH + 1) + wrapped
 
137
 
 
138
    def set(self, value):
 
139
        """Set the option value.
 
140
        """
 
141
        self.opts.setopt(self.name, value)
 
142
 
 
143
    def get(self):
 
144
        """Get the option value.
 
145
        """
 
146
        return self.opts.getopt(self.name)
 
147
 
 
148
    def append(self, value):
 
149
        """Append a value to the option value.
 
150
        """
 
151
        v = self.get() or []
 
152
        v.append(value)
 
153
        self.set(v)
 
154
 
 
155
    def short_opt(self):
 
156
        """Short option spec.
 
157
        """
 
158
        if self.short:
 
159
            if self.val:
 
160
                return self.short + ':'
 
161
            else:
 
162
                return self.short
 
163
        else:
 
164
            return None
 
165
 
 
166
    def long_opt(self):
 
167
        """Long option spec.
 
168
        """
 
169
        if self.long:
 
170
            if self.val:
 
171
                return self.long + '='
 
172
            else:
 
173
                return self.long
 
174
        else:
 
175
            return None
 
176
 
 
177
    def format(self, str, start='    ', out=sys.stdout):
 
178
        """Print a string, with consistent indentation at the start of lines.
 
179
        """
 
180
        lines = str.split('\n')
 
181
        for l in lines:
 
182
            l = l.strip()
 
183
            if start:
 
184
                out.write(start)
 
185
            out.write(l)
 
186
            out.write('\n')
 
187
 
 
188
    def show(self, out=sys.stdout):
 
189
        sep = ' '
 
190
        for x in self.optkeys:
 
191
            out.write(sep)
 
192
            out.write(x)
 
193
            sep = ', '
 
194
        if self.val:
 
195
            out.write(' ')
 
196
            out.write(self.val)
 
197
        out.write('\n')
 
198
        if self.use:
 
199
            self.format(self.use, out=out);
 
200
        if self.val:
 
201
            self.format('Default ' + str(self.default or 'None'), out=out)
 
202
 
 
203
    def specify(self, k, v):
 
204
        """Specify the option. Called when the option is set
 
205
        from the command line.
 
206
 
 
207
        k  option switch used
 
208
        v  optional value given (if any)
 
209
        """
 
210
        if k in self.optkeys:
 
211
            if self.val is None and v:
 
212
                self.opts.err("Option '%s' does not take a value" % k)
 
213
            self.specified_opt = k
 
214
            self.specified_val = v
 
215
            if self.fn:
 
216
                self.fn(self, k, v)
 
217
            return 1
 
218
        else:
 
219
            return 0
 
220
 
 
221
    def specified(self):
 
222
        """Test whether the option has been specified: set
 
223
        from the command line.
 
224
        """
 
225
        return self.specified_opt
 
226
 
 
227
class OptVar(Opt):
 
228
    """An individual option variable.
 
229
    """
 
230
    def __init__(self, opts, name,
 
231
                 val=None, fn=None, use=None, default=None):
 
232
        """Create an option.
 
233
 
 
234
        opts    parent options object
 
235
        name    name of the field it controls
 
236
        val     string used to print option args in help.
 
237
                If val is not specified the option has no arg.
 
238
        fn      function to call when the option is specified.
 
239
        use     usage (help) string
 
240
        default default value if not specified on command-line
 
241
        """
 
242
        if val is None:
 
243
            val = name.upper()
 
244
        Opt.__init__(self, opts, name, val=val, fn=fn, use=use, default=default)
 
245
        self.optkeys = []
 
246
        self.optkeys.append(self.long)
 
247
 
 
248
    def short_opt(self):
 
249
        return None
 
250
 
 
251
    def long_opt(self):
 
252
        return None
 
253
 
 
254
    def show(self, out=sys.stdout):
 
255
        print >>out, ' %s=%s' % (self.optkeys[0], self.val) 
 
256
        if self.use:
 
257
            self.format(self.use, out=out);
 
258
        if self.val:
 
259
            self.format('Default ' + str(self.default or 'None'), out=out)
 
260
 
 
261
class OptVals:
 
262
    """Class to hold option values.
 
263
    """
 
264
    def __init__(self):
 
265
        self.quiet = False
 
266
 
 
267
class Opts:
 
268
    """Container for options.
 
269
    """
 
270
 
 
271
    imports = ["import sys",
 
272
               "import os",
 
273
               "import os.path",
 
274
               "from xen.util.ip import *",
 
275
               ]
 
276
 
 
277
    def __init__(self, use=None):
 
278
        """Options constructor.
 
279
 
 
280
        use  usage string
 
281
        """
 
282
        self.use = use
 
283
        # List of options.
 
284
        self.options = []
 
285
        # Options indexed by name.
 
286
        self.options_map = {}
 
287
        # Command-line arguments.
 
288
        self.argv = []
 
289
        # Option values.
 
290
        self.vals = OptVals()
 
291
        # Variables for default scripts.
 
292
        self.vars = {}
 
293
        # Option to use for bare words.
 
294
        self.default_opt = None
 
295
 
 
296
 
 
297
    def reset(self):
 
298
        self.vals = OptVals()
 
299
        self.vars = {}
 
300
        for opt in self.options:
 
301
            opt.reset()
 
302
 
 
303
 
 
304
    def __repr__(self):
 
305
        return '\n'.join(map(str, self.options))
 
306
 
 
307
    def __str__(self):
 
308
        options = [s for s in self.options if s.optkeys[0][0] == '-']
 
309
        output = ''
 
310
        if options:
 
311
            output += '\nOptions:\n\n'
 
312
            output += '\n'.join([str(o) for o in options])
 
313
            output += '\n'
 
314
        return output
 
315
 
 
316
    def val_usage(self):
 
317
        optvals = [s for s in self.options if s.optkeys[0][0] != '-']
 
318
        output = ''
 
319
        if optvals:
 
320
            output += '\nValues:\n\n'
 
321
            output += '\n'.join([str(o) for o in optvals])
 
322
            output += '\n'
 
323
        return output
 
324
    
 
325
    def opt(self, name, **args):
 
326
        """Add an option.
 
327
 
 
328
        name    option name
 
329
        **args  keyword params for option constructor
 
330
        """
 
331
        x = Opt(self, name, **args)
 
332
        self.options.append(x)
 
333
        self.options_map[name] = x
 
334
        return x
 
335
 
 
336
    def default(self, name):
 
337
        self.default_opt = name
 
338
 
 
339
    def getdefault(self, val):
 
340
        if self.default_opt is None:
 
341
            return 0
 
342
        opt = self.option(self.default_opt)
 
343
        return opt.set(val)
 
344
 
 
345
    def var(self, name, **args):
 
346
        x = OptVar(self, name, **args)
 
347
        self.options.append(x)
 
348
        self.options_map[name] = x
 
349
        return x     
 
350
 
 
351
    def setvar(self, var, val):
 
352
        """Set a default script variable.
 
353
        """
 
354
        self.vars[var] = val
 
355
 
 
356
    def getvar(self, var):
 
357
        """Get a default script variable.
 
358
        """
 
359
        return self.vars.get(var)
 
360
 
 
361
    def option(self, name):
 
362
        """Get an option (object).
 
363
        """
 
364
        return self.options_map.get(name)
 
365
 
 
366
    def setopt(self, name, val):
 
367
        """Set an option value.
 
368
        An option can also be set using 'opts.vals.name = val'.
 
369
        """
 
370
        setattr(self.vals, name, val)
 
371
 
 
372
    def getopt(self, name):
 
373
        """Get an option value.
 
374
        An option value can also be got using 'opts.vals.name'.
 
375
        """
 
376
        return getattr(self.vals, name)
 
377
 
 
378
    def specified(self, name):
 
379
        """Test if an option has been specified.
 
380
        """
 
381
        opt = self.option(name)
 
382
        return opt and opt.specified()
 
383
 
 
384
    def err(self, msg):
 
385
        """Print an error to stderr and exit.
 
386
        """
 
387
        print >>sys.stderr, "Error:", msg
 
388
        sys.exit(1)
 
389
 
 
390
    def info(self, msg):
 
391
        """Print a message to stdout (unless quiet is set).
 
392
        """
 
393
        if self.vals.quiet: return
 
394
        print msg
 
395
 
 
396
    def warn(self, msg):
 
397
        """Print a warning to stdout.
 
398
        """
 
399
        print >>sys.stderr, "Warning:", msg
 
400
 
 
401
    def parse(self, argv):
 
402
        """Parse arguments argv using the options.
 
403
 
 
404
        return remaining arguments
 
405
        """
 
406
        self.argv = argv
 
407
 
 
408
        # hack to work around lack of gnu getopts parsing in python 2.2
 
409
        args = argv[1:]
 
410
        xargs = []
 
411
        while args:
 
412
            # let getopt parse whatever it feels like -- if anything
 
413
            try:
 
414
                (xvals, args) = getopt.getopt(args[0:],
 
415
                                              self.short_opts(),
 
416
                                              self.long_opts())
 
417
            except getopt.GetoptError, err:
 
418
                raise OptionError(str(err), self.use)
 
419
            #self.err(str(err))
 
420
                
 
421
            for (k, v) in xvals:
 
422
                for opt in self.options:
 
423
                    if opt.specify(k, v): break
 
424
                else:
 
425
                    raise OptionError('Unknown option: %s' % k, self.use)
 
426
 
 
427
            if not args:
 
428
                break
 
429
            
 
430
            # then process the 1st arg 
 
431
            (arg,args) = (args[0], args[1:])
 
432
 
 
433
            isvar = 0
 
434
            if '=' in arg:
 
435
                (k, v) = arg.split('=', 1)
 
436
                for opt in self.options:
 
437
                    if opt.specify(k, v):
 
438
                        isvar = 1
 
439
                        break
 
440
            elif self.getdefault(arg):
 
441
                isvar = 1
 
442
            if not isvar:
 
443
                xargs.append(arg)
 
444
 
 
445
        return xargs
 
446
 
 
447
    def short_opts(self):
 
448
        """Get short options specifier for getopt.
 
449
        """
 
450
        l = []
 
451
        for x in self.options:
 
452
            y = x.short_opt()
 
453
            if not y: continue
 
454
            l.append(y)
 
455
        return ''.join(l)
 
456
 
 
457
    def long_opts(self):
 
458
        """Get long options specifier for getopt.
 
459
        """
 
460
        l = []
 
461
        for x in self.options:
 
462
            y = x.long_opt()
 
463
            if not y: continue
 
464
            l.append(y)
 
465
        return l
 
466
 
 
467
    def usage(self):
 
468
        print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
 
469
        print
 
470
        if self.options:
 
471
            for opt in self.options:
 
472
                opt.show()
 
473
                print
 
474
            print
 
475
 
 
476
    def var_usage(self):
 
477
        if self.vars:
 
478
            print 'The config file defines the following variables:'
 
479
            for var in self.vars:
 
480
                var.show()
 
481
                print
 
482
            print
 
483
 
 
484
    def config_usage(self):
 
485
        if self.imports:
 
486
            print 'The following are automically imported:'
 
487
            for x in self.imports:
 
488
                print '   ', x
 
489
            print
 
490
        self.var_usage()
 
491
 
 
492
    def load_defconfig(self, help=0):
 
493
        """Load a defconfig script. Assumes these options set:
 
494
        'path'    search path
 
495
        'defconfig' script name
 
496
        """
 
497
        for x in [ '' ] + self.vals.path.split(':'):
 
498
            if x:
 
499
                p = os.path.join(x, self.vals.defconfig)
 
500
            else:
 
501
                p = self.vals.defconfig
 
502
            if not p.startswith('/'):
 
503
                p = os.path.join(os.path.curdir, p)
 
504
            if os.path.exists(p):
 
505
                self.info('Using config file "%s".' % p)
 
506
 
 
507
                f = open(p)
 
508
                is_xml = (f.read(1) == '<')
 
509
                f.close()
 
510
 
 
511
                if is_xml:
 
512
                    raise XMLFileError(p)
 
513
 
 
514
                self.load(p, help)
 
515
                break
 
516
        else:
 
517
            raise OptionError('Unable to open config file: %s' % \
 
518
                              self.vals.defconfig,
 
519
                              self.use)
 
520
 
 
521
    def load(self, defconfig, help):
 
522
        """Load a defconfig file. Local variables in the file
 
523
        are used to set options with the same names.
 
524
        Variables are not used to set options that are already specified.
 
525
        """
 
526
        # Create global and local dicts for the file.
 
527
        # Initialize locals to the vars.
 
528
        # Use exec to do the standard imports and
 
529
        # define variables we are passing to the script.
 
530
        globs = {}
 
531
        locs = {}
 
532
        locs.update(self.vars)
 
533
        cmd = '\n'.join(self.imports + 
 
534
                        [ "from xen.xm.help import Vars",
 
535
                          "xm_file = '%s'" % defconfig,
 
536
                          "xm_help = %d" % help,
 
537
                          "xm_vars = Vars(xm_file, xm_help, locals())"
 
538
                          ])
 
539
        exec cmd in globs, locs
 
540
        try:
 
541
            execfile(defconfig, globs, locs)
 
542
        except SyntaxError,e:
 
543
                raise SyntaxError, \
 
544
                "Errors were found at line %d while processing %s:\n\t%s"\
 
545
                %(e.lineno,defconfig,e.text)
 
546
        except:
 
547
            if not help: raise
 
548
        if help:
 
549
            self.config_usage()
 
550
            return
 
551
        # Extract the values set by the script and set the corresponding
 
552
        # options, if not set on the command line.
 
553
        vtypes = [ types.StringType,
 
554
                   types.ListType,
 
555
                   types.IntType,
 
556
                   types.FloatType
 
557
                   ]
 
558
        for (k, v) in locs.items():
 
559
            if self.specified(k): continue
 
560
            if not(type(v) in vtypes): continue
 
561
            self.setopt(k, v)
 
562
 
 
563
def set_true(opt, k, v):
 
564
    """Set an option true."""
 
565
    opt.set(1)
 
566
 
 
567
def set_false(opt, k, v):
 
568
    """Set an option false."""
 
569
    opt.set(0)
 
570
 
 
571
def set_bool(opt, k, v):
 
572
    """Set a boolean option.
 
573
    """
 
574
    if v in ('yes', 'y'):
 
575
        opt.set(1)
 
576
    elif v in ('no', 'n'):
 
577
        opt.set(0)
 
578
    else:
 
579
        opt.opts.err('Invalid value:' +v)
 
580
        
 
581
def set_value(opt, k, v):
 
582
    """Set an option to a value."""
 
583
    opt.set(v)
 
584
 
 
585
def set_int(opt, k, v):
 
586
    """Set an option to an integer value."""
 
587
    try:
 
588
        v = int(v)
 
589
    except:
 
590
        opt.opts.err('Invalid value: ' + str(v))
 
591
    opt.set(v)
 
592
 
 
593
def set_long(opt, k, v):
 
594
    """Set an option to a long integer value."""
 
595
    try:
 
596
        v = long(v)
 
597
    except:
 
598
        opt.opts.err('Invalid value: ' + str(v))
 
599
    opt.set(v)
 
600
 
 
601
def set_float(opt, k, v):
 
602
    """Set an option to a float value."""
 
603
    try:
 
604
        v = float(v)
 
605
    except:
 
606
        opt.opts.err('Invalid value: ' + str(v))
 
607
    opt.set(v)
 
608
 
 
609
def append_value(opt, k, v):
 
610
    """Append a value to a list option."""
 
611
    opt.append(v)
 
612
 
 
613
def set_var(opt, k, v):
 
614
    """Set a default script variable.
 
615
    """
 
616
    (var, val) = v.strip().split('=', 1)
 
617
    opt.opts.setvar(var.strip(), val.strip())
 
618