Kaydet (Commit) c9c37b1c authored tarafından Greg Ward's avatar Greg Ward

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.
üst d6bc4e7f
...@@ -13,19 +13,25 @@ __rcsid__ = "$Id$" ...@@ -13,19 +13,25 @@ __rcsid__ = "$Id$"
import sys, os import sys, os
import string, re import string, re
from types import * from types import *
from copy import copy
from distutils.errors import * from distutils.errors import *
from distutils.fancy_getopt import fancy_getopt from distutils.fancy_getopt import fancy_getopt, print_help
from distutils import util from distutils import util
# This is not *quite* the same as a Python NAME; I don't allow leading # Regex to define acceptable Distutils command names. This is not *quite*
# underscores. The fact that they're very similar is no coincidence... # 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_]*)$') command_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$')
# Defining this as a global is probably inadequate -- what about # Defining this as a global is probably inadequate -- what about
# listing the available options (or even commands, which can vary # listing the available options (or even commands, which can vary
# quite late as well) # 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): def setup (**attrs):
...@@ -79,12 +85,20 @@ def setup (**attrs): ...@@ -79,12 +85,20 @@ def setup (**attrs):
# Parse the command line; any command-line errors are the end-users # Parse the command line; any command-line errors are the end-users
# fault, so turn them into SystemExit to suppress tracebacks. # fault, so turn them into SystemExit to suppress tracebacks.
try: try:
dist.parse_command_line (sys.argv[1:]) ok = dist.parse_command_line (sys.argv[1:])
except DistutilsArgError, msg: except DistutilsArgError, msg:
sys.stderr.write (usage + "\n")
raise SystemExit, msg raise SystemExit, msg
# And finally, run all the commands found on the command line. # 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 () # setup ()
...@@ -114,14 +128,17 @@ class Distribution: ...@@ -114,14 +128,17 @@ class Distribution:
# don't want to pollute the commands with too many options that they # don't want to pollute the commands with too many options that they
# have minimal control over. # have minimal control over.
global_options = [('verbose', 'v', global_options = [('verbose', 'v',
"run verbosely"), "run verbosely (default)"),
('quiet=!verbose', 'q', ('quiet', 'q',
"run quietly (turns verbosity off)"), "run quietly (turns verbosity off)"),
('dry-run', 'n', ('dry-run', 'n',
"don't actually do anything"), "don't actually do anything"),
('force', 'f', ('force', 'f',
"skip dependency checking between files"), "skip dependency checking between files"),
('help', 'h',
"show this help message"),
] ]
negative_opt = {'quiet': 'verbose'}
# -- Creation/initialization methods ------------------------------- # -- Creation/initialization methods -------------------------------
...@@ -138,17 +155,20 @@ class Distribution: ...@@ -138,17 +155,20 @@ class Distribution:
command objects by 'parse_command_line()'.""" command objects by 'parse_command_line()'."""
# Default values for our command-line options # Default values for our command-line options
self.verbose = 0 self.verbose = 1
self.dry_run = 0 self.dry_run = 0
self.force = 0 self.force = 0
self.help = 0
# And the "distribution meta-data" options -- these can only # And the "distribution meta-data" options -- these can only
# come from setup.py (the caller), not the command line # come from setup.py (the caller), not the command line
# (or a hypothetical config file).. # (or a hypothetical config file).
self.name = None self.name = None
self.version = None self.version = None
self.author = None self.author = None
self.author_email = None self.author_email = None
self.maintainer = None
self.maintainer_email = None
self.url = None self.url = None
self.licence = None self.licence = None
self.description = None self.description = None
...@@ -236,7 +256,11 @@ class Distribution: ...@@ -236,7 +256,11 @@ class Distribution:
'options' attribute. Any error in that 'options' attribute 'options' attribute. Any error in that 'options' attribute
raises DistutilsGetoptError; any error on the command-line raises DistutilsGetoptError; any error on the command-line
raises DistutilsArgError. If no Distutils commands were found 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 # We have to parse the command line a bit at a time -- global
# options, then the first command, then its options, and so on -- # options, then the first command, then its options, and so on --
...@@ -246,7 +270,14 @@ class Distribution: ...@@ -246,7 +270,14 @@ class Distribution:
# happen until we know what the command is. # happen until we know what the command is.
self.commands = [] 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: while args:
# Pull the current command from the head of the command line # Pull the current command from the head of the command line
...@@ -258,7 +289,10 @@ class Distribution: ...@@ -258,7 +289,10 @@ class Distribution:
# Make sure we have a command object to put the options into # Make sure we have a command object to put the options into
# (this either pulls it out of a cache of command objects, # (this either pulls it out of a cache of command objects,
# or finds and instantiates the command class). # 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 -- # Require that the command class be derived from Command --
# that way, we can be sure that we at least have the 'run' # that way, we can be sure that we at least have the 'run'
...@@ -279,8 +313,24 @@ class Distribution: ...@@ -279,8 +313,24 @@ class Distribution:
# Poof! like magic, all commands support the global # Poof! like magic, all commands support the global
# options too, just by adding in 'global_options'. # 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:]) 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.command_obj[command] = cmd_obj
self.have_run[command] = 0 self.have_run[command] = 0
...@@ -288,9 +338,11 @@ class Distribution: ...@@ -288,9 +338,11 @@ class Distribution:
# Oops, no commands found -- an end-user error # Oops, no commands found -- an end-user error
if not self.commands: if not self.commands:
sys.stderr.write (usage + "\n")
raise DistutilsArgError, "no commands supplied" raise DistutilsArgError, "no commands supplied"
# All is well: return true
return 1
# parse_command_line() # parse_command_line()
...@@ -318,7 +370,7 @@ class Distribution: ...@@ -318,7 +370,7 @@ class Distribution:
module = sys.modules[module_name] module = sys.modules[module_name]
except ImportError: except ImportError:
raise DistutilsModuleError, \ raise DistutilsModuleError, \
"invalid command '%s' (no module named %s)" % \ "invalid command '%s' (no module named '%s')" % \
(command, module_name) (command, module_name)
try: try:
...@@ -359,7 +411,8 @@ class Distribution: ...@@ -359,7 +411,8 @@ class Distribution:
'create_command_obj()'. If none found, the action taken 'create_command_obj()'. If none found, the action taken
depends on 'create': if true (the default), create a new depends on 'create': if true (the default), create a new
command object by calling 'create_command_obj()' and return 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) cmd_obj = self.command_obj.get (command)
if not cmd_obj and create: if not cmd_obj and create:
...@@ -520,6 +573,10 @@ class Command: ...@@ -520,6 +573,10 @@ class Command:
self._dry_run = None self._dry_run = None
self._force = 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 # 'ready' records whether or not 'set_final_options()' has been
# called. 'set_final_options()' itself should not pay attention to # called. 'set_final_options()' itself should not pay attention to
# this flag: it is the business of 'ensure_ready()', which always # this flag: it is the business of 'ensure_ready()', which always
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment