Revision d971402f lib/cli.py

b/lib/cli.py
1480 1480
  ]
1481 1481

  
1482 1482

  
1483
def _ParseArgs(argv, commands, aliases, env_override):
1483
class _ShowUsage(Exception):
1484
  """Exception class for L{_ParseArgs}.
1485

  
1486
  """
1487
  def __init__(self, exit_error):
1488
    """Initializes instances of this class.
1489

  
1490
    @type exit_error: bool
1491
    @param exit_error: Whether to report failure on exit
1492

  
1493
    """
1494
    Exception.__init__(self)
1495
    self.exit_error = exit_error
1496

  
1497

  
1498
class _ShowVersion(Exception):
1499
  """Exception class for L{_ParseArgs}.
1500

  
1501
  """
1502

  
1503

  
1504
def _ParseArgs(binary, argv, commands, aliases, env_override):
1484 1505
  """Parser for the command line arguments.
1485 1506

  
1486 1507
  This function parses the arguments and returns the function which
1487 1508
  must be executed together with its (modified) arguments.
1488 1509

  
1489
  @param argv: the command line
1490
  @param commands: dictionary with special contents, see the design
1491
      doc for cmdline handling
1492
  @param aliases: dictionary with command aliases {'alias': 'target, ...}
1510
  @param binary: Script name
1511
  @param argv: Command line arguments
1512
  @param commands: Dictionary containing command definitions
1513
  @param aliases: dictionary with command aliases {"alias": "target", ...}
1493 1514
  @param env_override: list of env variables allowed for default args
1515
  @raise _ShowUsage: If usage description should be shown
1516
  @raise _ShowVersion: If version should be shown
1494 1517

  
1495 1518
  """
1496 1519
  assert not (env_override - set(commands))
1520
  assert not (set(aliases.keys()) & set(commands.keys()))
1497 1521

  
1498
  if len(argv) == 0:
1499
    binary = "<command>"
1522
  if len(argv) > 1:
1523
    cmd = argv[1]
1500 1524
  else:
1501
    binary = argv[0].split("/")[-1]
1525
    # No option or command given
1526
    raise _ShowUsage(exit_error=True)
1502 1527

  
1503
  if len(argv) > 1 and argv[1] == "--version":
1504
    ToStdout("%s (ganeti %s) %s", binary, constants.VCS_VERSION,
1505
             constants.RELEASE_VERSION)
1506
    # Quit right away. That way we don't have to care about this special
1507
    # argument. optparse.py does it the same.
1508
    sys.exit(0)
1509

  
1510
  if len(argv) < 2 or not (argv[1] in commands or
1511
                           argv[1] in aliases):
1512
    # let's do a nice thing
1513
    sortedcmds = commands.keys()
1514
    sortedcmds.sort()
1515

  
1516
    ToStdout("Usage: %s {command} [options...] [argument...]", binary)
1517
    ToStdout("%s <command> --help to see details, or man %s", binary, binary)
1518
    ToStdout("")
1519

  
1520
    # compute the max line length for cmd + usage
1521
    mlen = max([len(" %s" % cmd) for cmd in commands])
1522
    mlen = min(60, mlen) # should not get here...
1523

  
1524
    # and format a nice command list
1525
    ToStdout("Commands:")
1526
    for cmd in sortedcmds:
1527
      cmdstr = " %s" % (cmd,)
1528
      help_text = commands[cmd][4]
1529
      help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
1530
      ToStdout("%-*s - %s", mlen, cmdstr, help_lines.pop(0))
1531
      for line in help_lines:
1532
        ToStdout("%-*s   %s", mlen, "", line)
1533

  
1534
    ToStdout("")
1535

  
1536
    return None, None, None
1528
  if cmd == "--version":
1529
    raise _ShowVersion()
1530
  elif cmd == "--help":
1531
    raise _ShowUsage(exit_error=False)
1532
  elif not (cmd in commands or cmd in aliases):
1533
    raise _ShowUsage(exit_error=True)
1537 1534

  
1538 1535
  # get command, unalias it, and look it up in commands
1539
  cmd = argv.pop(1)
1540 1536
  if cmd in aliases:
1541
    if cmd in commands:
1542
      raise errors.ProgrammerError("Alias '%s' overrides an existing"
1543
                                   " command" % cmd)
1544

  
1545 1537
    if aliases[cmd] not in commands:
1546 1538
      raise errors.ProgrammerError("Alias '%s' maps to non-existing"
1547 1539
                                   " command '%s'" % (cmd, aliases[cmd]))
......
1552 1544
    args_env_name = ("%s_%s" % (binary.replace("-", "_"), cmd)).upper()
1553 1545
    env_args = os.environ.get(args_env_name)
1554 1546
    if env_args:
1555
      argv = utils.InsertAtPos(argv, 1, shlex.split(env_args))
1547
      argv = utils.InsertAtPos(argv, 2, shlex.split(env_args))
1556 1548

  
1557 1549
  func, args_def, parser_opts, usage, description = commands[cmd]
1558 1550
  parser = OptionParser(option_list=parser_opts + COMMON_OPTS,
......
1560 1552
                        formatter=TitledHelpFormatter(),
1561 1553
                        usage="%%prog %s %s" % (cmd, usage))
1562 1554
  parser.disable_interspersed_args()
1563
  options, args = parser.parse_args(args=argv[1:])
1555
  options, args = parser.parse_args(args=argv[2:])
1564 1556

  
1565 1557
  if not _CheckArguments(cmd, args_def, args):
1566 1558
    return None, None, None
......
1568 1560
  return func, options, args
1569 1561

  
1570 1562

  
1563
def _FormatUsage(binary, commands):
1564
  """Generates a nice description of all commands.
1565

  
1566
  @param binary: Script name
1567
  @param commands: Dictionary containing command definitions
1568

  
1569
  """
1570
  # compute the max line length for cmd + usage
1571
  mlen = min(60, max(map(len, commands)))
1572

  
1573
  yield "Usage: %s {command} [options...] [argument...]" % binary
1574
  yield "%s <command> --help to see details, or man %s" % (binary, binary)
1575
  yield ""
1576
  yield "Commands:"
1577

  
1578
  # and format a nice command list
1579
  for (cmd, (_, _, _, _, help_text)) in sorted(commands.items()):
1580
    help_lines = textwrap.wrap(help_text, 79 - 3 - mlen)
1581
    yield " %-*s - %s" % (mlen, cmd, help_lines.pop(0))
1582
    for line in help_lines:
1583
      yield " %-*s   %s" % (mlen, "", line)
1584

  
1585
  yield ""
1586

  
1587

  
1571 1588
def _CheckArguments(cmd, args_def, args):
1572 1589
  """Verifies the arguments using the argument definition.
1573 1590

  
......
2242 2259
    aliases = {}
2243 2260

  
2244 2261
  try:
2245
    func, options, args = _ParseArgs(sys.argv, commands, aliases, env_override)
2262
    (func, options, args) = _ParseArgs(binary, sys.argv, commands, aliases,
2263
                                       env_override)
2264
  except _ShowVersion:
2265
    ToStdout("%s (ganeti %s) %s", binary, constants.VCS_VERSION,
2266
             constants.RELEASE_VERSION)
2267
    return constants.EXIT_SUCCESS
2268
  except _ShowUsage, err:
2269
    for line in _FormatUsage(binary, commands):
2270
      ToStdout(line)
2271

  
2272
    if err.exit_error:
2273
      return constants.EXIT_FAILURE
2274
    else:
2275
      return constants.EXIT_SUCCESS
2246 2276
  except errors.ParameterError, err:
2247 2277
    result, err_msg = FormatError(err)
2248 2278
    ToStderr(err_msg)

Also available in: Unified diff