diff options
author | Greg Ward <gward@python.net> | 1999-12-12 16:51:44 (GMT) |
---|---|---|
committer | Greg Ward <gward@python.net> | 1999-12-12 16:51:44 (GMT) |
commit | c9c37b1c6e6105fe00e4aa958b62f946a75800ac (patch) | |
tree | ccba4a1c3d726e4c939647aca0bc4069e0a20923 /Lib | |
parent | d6bc4e7fc001d7b64713c90bf5909d60c2adabe5 (diff) | |
download | cpython-c9c37b1c6e6105fe00e4aa958b62f946a75800ac.zip cpython-c9c37b1c6e6105fe00e4aa958b62f946a75800ac.tar.gz cpython-c9c37b1c6e6105fe00e4aa958b62f946a75800ac.tar.bz2 |
Made "verbose" mode the default; now you have to supply --quiet if you
want no output. Still no option for a happy medium though.
Added "--help" global option.
Changed 'parse_command_line()' to recognize help options (both for the
whole distribution and per-command), and to distinguish "regular run"
and "user asked for help" by returning false in the latter case.
Also in 'parse_command_line()', detect invalid command name on command
line by catching DistutilsModuleError.
a 'negative_opt' class attribute right after 'global_options'; changed
how we call 'fancy_getopt()' accordingly.
Initialize 'maintainer' and 'maintainer_email' attributes to Distribution
to avoid AttributeError when 'author' and 'author_email' not defined.
Initialize 'help' attribute in Command constructor (to avoid
AttributeError when user *doesn't* ask for help).
In 'setup()':
* show usage message before dying when we catch DistutilsArgError
* only run commands if 'parse_command_line()' returned true (that
way, we exit immediately when a help option is found)
* catch KeyboardInterrupt and IOError from running commands
Bulked up usage message to show --help options.
Comment, docstring, and error message tweaks.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/distutils/core.py | 93 |
1 files changed, 75 insertions, 18 deletions
diff --git a/Lib/distutils/core.py b/Lib/distutils/core.py index 23fc3cc..13bf9c7 100644 --- a/Lib/distutils/core.py +++ b/Lib/distutils/core.py @@ -13,19 +13,25 @@ __rcsid__ = "$Id$" import sys, os import string, re from types import * +from copy import copy from distutils.errors import * -from distutils.fancy_getopt import fancy_getopt +from distutils.fancy_getopt import fancy_getopt, print_help from distutils import util -# This is not *quite* the same as a Python NAME; I don't allow leading -# underscores. The fact that they're very similar is no coincidence... +# Regex to define acceptable Distutils command names. This is not *quite* +# the same as a Python NAME -- I don't allow leading underscores. The fact +# that they're very similar is no coincidence; the default naming scheme is +# to look for a Python module named after the command. command_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$') # Defining this as a global is probably inadequate -- what about # listing the available options (or even commands, which can vary # quite late as well) -usage = '%s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]' % sys.argv[0] - +usage = """\ +usage: %s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] + or: %s --help + or: %s cmd --help +""" % (sys.argv[0], sys.argv[0], sys.argv[0]) def setup (**attrs): @@ -79,12 +85,20 @@ def setup (**attrs): # Parse the command line; any command-line errors are the end-users # fault, so turn them into SystemExit to suppress tracebacks. try: - dist.parse_command_line (sys.argv[1:]) + ok = dist.parse_command_line (sys.argv[1:]) except DistutilsArgError, msg: + sys.stderr.write (usage + "\n") raise SystemExit, msg # And finally, run all the commands found on the command line. - dist.run_commands () + if ok: + try: + dist.run_commands () + except KeyboardInterrupt: + raise SystemExit, "interrupted" + except IOError, exc: + # is this 1.5.2-specific? 1.5-specific? + raise SystemExit, "error: %s: %s" % (exc.filename, exc.strerror) # setup () @@ -114,14 +128,17 @@ class Distribution: # don't want to pollute the commands with too many options that they # have minimal control over. global_options = [('verbose', 'v', - "run verbosely"), - ('quiet=!verbose', 'q', + "run verbosely (default)"), + ('quiet', 'q', "run quietly (turns verbosity off)"), ('dry-run', 'n', "don't actually do anything"), ('force', 'f', "skip dependency checking between files"), + ('help', 'h', + "show this help message"), ] + negative_opt = {'quiet': 'verbose'} # -- Creation/initialization methods ------------------------------- @@ -138,17 +155,20 @@ class Distribution: command objects by 'parse_command_line()'.""" # Default values for our command-line options - self.verbose = 0 + self.verbose = 1 self.dry_run = 0 self.force = 0 + self.help = 0 # And the "distribution meta-data" options -- these can only # come from setup.py (the caller), not the command line - # (or a hypothetical config file).. + # (or a hypothetical config file). self.name = None self.version = None self.author = None self.author_email = None + self.maintainer = None + self.maintainer_email = None self.url = None self.licence = None self.description = None @@ -236,7 +256,11 @@ class Distribution: 'options' attribute. Any error in that 'options' attribute raises DistutilsGetoptError; any error on the command-line raises DistutilsArgError. If no Distutils commands were found - on the command line, raises DistutilsArgError.""" + on the command line, raises DistutilsArgError. Return true if + command-line successfully parsed and we should carry on with + executing commands; false if no errors but we shouldn't execute + commands (currently, this only happens if user asks for + help).""" # We have to parse the command line a bit at a time -- global # options, then the first command, then its options, and so on -- @@ -246,7 +270,14 @@ class Distribution: # happen until we know what the command is. self.commands = [] - args = fancy_getopt (self.global_options, self, sys.argv[1:]) + args = fancy_getopt (self.global_options, self.negative_opt, + self, sys.argv[1:]) + + if self.help: + print_help (self.global_options, header="Global options:") + print + print usage + return while args: # Pull the current command from the head of the command line @@ -258,7 +289,10 @@ class Distribution: # Make sure we have a command object to put the options into # (this either pulls it out of a cache of command objects, # or finds and instantiates the command class). - cmd_obj = self.find_command_obj (command) + try: + cmd_obj = self.find_command_obj (command) + except DistutilsModuleError, msg: + raise DistutilsArgError, msg # Require that the command class be derived from Command -- # that way, we can be sure that we at least have the 'run' @@ -279,8 +313,24 @@ class Distribution: # Poof! like magic, all commands support the global # options too, just by adding in 'global_options'. - args = fancy_getopt (self.global_options + cmd_obj.options, + negative_opt = self.negative_opt + if hasattr (cmd_obj, 'negative_opt'): + negative_opt = copy (negative_opt) + negative_opt.update (cmd_obj.negative_opt) + + options = self.global_options + cmd_obj.options + args = fancy_getopt (options, negative_opt, cmd_obj, args[1:]) + if cmd_obj.help: + print_help (self.global_options, + header="Global options:") + print + print_help (cmd_obj.options, + header="Options for '%s' command:" % command) + print + print usage + return + self.command_obj[command] = cmd_obj self.have_run[command] = 0 @@ -288,9 +338,11 @@ class Distribution: # Oops, no commands found -- an end-user error if not self.commands: - sys.stderr.write (usage + "\n") raise DistutilsArgError, "no commands supplied" + # All is well: return true + return 1 + # parse_command_line() @@ -318,7 +370,7 @@ class Distribution: module = sys.modules[module_name] except ImportError: raise DistutilsModuleError, \ - "invalid command '%s' (no module named %s)" % \ + "invalid command '%s' (no module named '%s')" % \ (command, module_name) try: @@ -359,7 +411,8 @@ class Distribution: 'create_command_obj()'. If none found, the action taken depends on 'create': if true (the default), create a new command object by calling 'create_command_obj()' and return - it; otherwise, return None.""" + it; otherwise, return None. If 'command' is an invalid + command name, then DistutilsModuleError will be raised.""" cmd_obj = self.command_obj.get (command) if not cmd_obj and create: @@ -520,6 +573,10 @@ class Command: self._dry_run = None self._force = None + # The 'help' flag is just used for command-line parsing, so + # none of that complicated bureaucracy is needed. + self.help = 0 + # 'ready' records whether or not 'set_final_options()' has been # called. 'set_final_options()' itself should not pay attention to # this flag: it is the business of 'ensure_ready()', which always |