summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Ward <gward@python.net>2000-04-21 02:28:14 (GMT)
committerGreg Ward <gward@python.net>2000-04-21 02:28:14 (GMT)
commit82715e1f11ec1f4c7b13b07ca55f56850c4c3dab (patch)
tree1dd7b084123f9f870dbc7b00c9281cf84a7793d7
parent283c745c572ea251f6f63e4c16905157ada66233 (diff)
downloadcpython-82715e1f11ec1f4c7b13b07ca55f56850c4c3dab.zip
cpython-82715e1f11ec1f4c7b13b07ca55f56850c4c3dab.tar.gz
cpython-82715e1f11ec1f4c7b13b07ca55f56850c4c3dab.tar.bz2
Patch, originally from Bastian Kleineidam and savagely mutilated by me,
to add the "display metadata" options: --name, --version, --author, and so forth. Main changes: * added 'display_options' class attribute to list all the "display only" options (--help-commands plus the metadata options) * added DistributionMetadata class as a place to put the actual metadata information from the setup script (not to be confused with the metadata display options); the logic dealing with metadata (eg. return self.name or "UNKNOWN") is now in this class * changed 'parse_command_line()' to use the new OO interface provided by fancy_getopt, mainly so we can get at the original order of options on the command line, so we can print multiple lines of distribution meta-data in the order specified by the user * added 'handle_display_options()' to handle display-only options Also fixed some crufty old comments/docstrings.
-rw-r--r--Lib/distutils/dist.py243
1 files changed, 193 insertions, 50 deletions
diff --git a/Lib/distutils/dist.py b/Lib/distutils/dist.py
index 408b9f5..bedd9d2 100644
--- a/Lib/distutils/dist.py
+++ b/Lib/distutils/dist.py
@@ -12,7 +12,7 @@ import sys, string, re
from types import *
from copy import copy
from distutils.errors import *
-from distutils.fancy_getopt import fancy_getopt, print_help
+from distutils.fancy_getopt import FancyGetopt, longopt_xlate
# Regex to define acceptable Distutils command names. This is not *quite*
@@ -40,8 +40,8 @@ class Distribution:
# 'global_options' describes the command-line options that may be
- # supplied to the client (setup.py) prior to any actual commands.
- # Eg. "./setup.py -nv" or "./setup.py --verbose" both take advantage of
+ # supplied to the setup script prior to any actual commands.
+ # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of
# these global options. This list should be kept to a bare minimum,
# since every global option is also valid as a command option -- and we
# don't want to pollute the commands with too many options that they
@@ -53,8 +53,47 @@ class Distribution:
('dry-run', 'n',
"don't actually do anything"),
('help', 'h',
- "show this help message"),
+ "show this help message, plus help for any commands " +
+ "given on the command-line"),
]
+
+ # options that are not propagated to the commands
+ display_options = [
+ ('help-commands', None,
+ "list all available commands"),
+ ('name', None,
+ "print package name"),
+ ('version', 'V',
+ "print package version"),
+ ('fullname', None,
+ "print <package name>-<version>"),
+ ('author', None,
+ "print the author's name"),
+ ('author-email', None,
+ "print the author's email address"),
+ ('maintainer', None,
+ "print the maintainer's name"),
+ ('maintainer-email', None,
+ "print the maintainer's email address"),
+ ('contact', None,
+ "print the name of the maintainer if present, "
+ "else author"),
+ ('contact-email', None,
+ "print the email of the maintainer if present, "
+ "else author"),
+ ('url', None,
+ "print the URL for this package"),
+ ('licence', None,
+ "print the licence of the package"),
+ ('license', None,
+ "alias for --licence"),
+ ('description', None,
+ "print the package description"),
+ ]
+ display_option_names = map(lambda x: string.translate(x[0], longopt_xlate),
+ display_options)
+
+ # negative options are options that exclude other options
negative_opt = {'quiet': 'verbose'}
@@ -75,31 +114,28 @@ class Distribution:
self.verbose = 1
self.dry_run = 0
self.help = 0
- self.help_commands = 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).
- 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
+ for attr in self.display_option_names:
+ setattr(self, attr, 0)
+
+ # Store the distribution meta-data (name, version, author, and so
+ # forth) in a separate object -- we're getting to have enough
+ # information here (and enough command-line options) that it's
+ # worth it. Also delegate 'get_XXX()' methods to the 'metadata'
+ # object in a sneaky and underhanded (but efficient!) way.
+ self.metadata = DistributionMetadata ()
+ for attr in dir(self.metadata):
+ meth_name = "get_" + attr
+ setattr(self, meth_name, getattr(self.metadata, meth_name))
# 'cmdclass' maps command names to class objects, so we
# can 1) quickly figure out which class to instantiate when
# we need to create a new command object, and 2) have a way
- # for the client to override command classes
+ # for the setup script to override command classes
self.cmdclass = {}
# These options are really the business of various commands, rather
# than of the Distribution itself. We provide aliases for them in
# Distribution as a convenience to the developer.
- # dictionary.
self.packages = None
self.package_dir = None
self.py_modules = None
@@ -128,8 +164,9 @@ class Distribution:
self.have_run = {}
# Now we'll use the attrs dictionary (ultimately, keyword args from
- # the client) to possibly override any or all of these distribution
- # options.
+ # the setup script) to possibly override any or all of these
+ # distribution options.
+
if attrs:
# Pull out the set of command options and work on them
@@ -149,7 +186,9 @@ class Distribution:
# Now work on the rest of the attributes. Any attribute that's
# not already defined is invalid!
for (key,val) in attrs.items():
- if hasattr (self, key):
+ if hasattr (self.metadata, key):
+ setattr (self.metadata, key, val)
+ elif hasattr (self, key):
setattr (self, key, val)
else:
raise DistutilsSetupError, \
@@ -192,19 +231,17 @@ class Distribution:
# happen until we know what the command is.
self.commands = []
- options = self.global_options + \
- [('help-commands', None,
- "list all available commands")]
- args = fancy_getopt (options, self.negative_opt,
- self, sys.argv[1:])
+ parser = FancyGetopt (self.global_options + self.display_options)
+ parser.set_negative_aliases (self.negative_opt)
+ args = parser.getopt (object=self)
+ option_order = parser.get_option_order()
- # User just wants a list of commands -- we'll print it out and stop
- # processing now (ie. if they ran "setup --help-commands foo bar",
- # we ignore "foo bar").
- if self.help_commands:
- self.print_commands ()
- print
- print usage
+ # Handle aliases (license == licence)
+ if self.license:
+ self.licence = 1
+
+ # for display options we return immediately
+ if self.handle_display_options(option_order):
return
while args:
@@ -246,15 +283,17 @@ class Distribution:
negative_opt = copy (negative_opt)
negative_opt.update (cmd_obj.negative_opt)
- options = self.global_options + cmd_obj.user_options
- args = fancy_getopt (options, negative_opt,
- cmd_obj, args[1:])
+ parser.set_option_table (self.global_options +
+ cmd_obj.user_options)
+ parser.set_negative_aliases (negative_opt)
+ args = parser.getopt (args[1:], cmd_obj)
if cmd_obj.help:
- print_help (self.global_options,
- header="Global options:")
+ parser.set_option_table (self.global_options)
+ parser.print_help ("Global options:")
print
- print_help (cmd_obj.user_options,
- header="Options for '%s' command:" % command)
+
+ parser.set_option_table (cmd_obj.user_options)
+ parser.print_help ("Options for '%s' command:" % command)
print
print usage
return
@@ -271,13 +310,23 @@ class Distribution:
# get help on a command, but I support it because that's how
# CVS does it -- might as well be consistent.)
if self.help:
- print_help (self.global_options, header="Global options:")
+ parser.set_option_table (self.global_options)
+ parser.print_help (
+ "Global options (apply to all commands, " +
+ "or can be used per command):")
print
+ if not self.commands:
+ parser.set_option_table (self.display_options)
+ parser.print_help (
+ "Information display options (just display " +
+ "information, ignore any commands)")
+ print
+
for command in self.commands:
klass = self.find_command_class (command)
- print_help (klass.user_options,
- header="Options for '%s' command:" % command)
+ parser.set_option_table (klass.user_options)
+ parser.print_help ("Options for '%s' command:" % command)
print
print usage
@@ -292,6 +341,40 @@ class Distribution:
# parse_command_line()
+ def handle_display_options (self, option_order):
+ """If there were any non-global "display-only" options
+ (--help-commands or the metadata display options) on the command
+ line, display the requested info and return true; else return
+ false."""
+
+ from distutils.core import usage
+
+ # User just wants a list of commands -- we'll print it out and stop
+ # processing now (ie. if they ran "setup --help-commands foo bar",
+ # we ignore "foo bar").
+ if self.help_commands:
+ self.print_commands ()
+ print
+ print usage
+ return 1
+
+ # If user supplied any of the "display metadata" options, then
+ # display that metadata in the order in which the user supplied the
+ # metadata options.
+ any_display_options = 0
+ is_display_option = {}
+ for option in self.display_options:
+ is_display_option[option[0]] = 1
+
+ for (opt, val) in option_order:
+ if val and is_display_option.get(opt):
+ opt = string.translate (opt, longopt_xlate)
+ print getattr(self.metadata, "get_"+opt)()
+ any_display_options = 1
+
+ return any_display_options
+
+ # handle_display_options()
def print_command_list (self, commands, header, max_length):
"""Print a subset of the list of all commands -- used by
@@ -437,7 +520,7 @@ class Distribution:
def run_commands (self):
- """Run each command that was seen on the client command line.
+ """Run each command that was seen on the setup script command line.
Uses the list of commands found and cache of command objects
created by 'create_command_obj()'."""
@@ -532,14 +615,74 @@ class Distribution:
not self.has_ext_modules() and
not self.has_c_libraries())
+ # -- Metadata query methods ----------------------------------------
+
+ # If you're looking for 'get_name()', 'get_version()', and so forth,
+ # they are defined in a sneaky way: the constructor binds self.get_XXX
+ # to self.metadata.get_XXX. The actual code is in the
+ # DistributionMetadata class, below.
+
+# class Distribution
+
+
+class DistributionMetadata:
+ """Dummy class to hold the distribution meta-data: name, version,
+ author, and so forth."""
+
+ def __init__ (self):
+ 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
+
+ # -- Metadata query methods ----------------------------------------
+
def get_name (self):
return self.name or "UNKNOWN"
- def get_full_name (self):
- return "%s-%s" % ((self.name or "UNKNOWN"), (self.version or "???"))
-
-# class Distribution
+ def get_version(self):
+ return self.version or "???"
+
+ def get_fullname (self):
+ return "%s-%s" % (self.get_name(), self.get_version())
+
+ def get_author(self):
+ return self.author or "UNKNOWN"
+ def get_author_email(self):
+ return self.author_email or "UNKNOWN"
+
+ def get_maintainer(self):
+ return self.maintainer or "UNKNOWN"
+
+ def get_maintainer_email(self):
+ return self.maintainer_email or "UNKNOWN"
+
+ def get_contact(self):
+ return (self.maintainer or
+ self.author or
+ "UNKNOWN")
+
+ def get_contact_email(self):
+ return (self.maintainer_email or
+ self.author_email or
+ "UNKNOWN")
+
+ def get_url(self):
+ return self.url or "UNKNOWN"
+
+ def get_licence(self):
+ return self.licence or "UNKNOWN"
+
+ def get_description(self):
+ return self.description or "UNKNOWN"
+
+# class DistributionMetadata
if __name__ == "__main__":
dist = Distribution ()