dist.py revision f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605
1fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward"""distutils.dist
2fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
3fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg WardProvides the Distribution class, which represents the module distribution
48ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Wardbeing built/installed/distributed.
58ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward"""
6fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
7fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward# created 2000/04/03, Greg Ward
8fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward# (extricated from core.py; actually dates back to the beginning)
9fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
10fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward__revision__ = "$Id$"
11fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
121426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smithimport sys, os, string, re
13fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Wardfrom types import *
14fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Wardfrom copy import copy
15fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Wardfrom distutils.errors import *
1636c36fec7cd7f056832c2043ec385f6e921c8c83Greg Wardfrom distutils import sysconfig
1782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Wardfrom distutils.fancy_getopt import FancyGetopt, longopt_xlate
181426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smithfrom distutils.util import check_environ
19fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
20fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
21fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward# Regex to define acceptable Distutils command names.  This is not *quite*
22fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward# the same as a Python NAME -- I don't allow leading underscores.  The fact
23fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward# that they're very similar is no coincidence; the default naming scheme is
24fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward# to look for a Python module named after the command.
25fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Wardcommand_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$')
26fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
27fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
28fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Wardclass Distribution:
298ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    """The core of the Distutils.  Most of the work hiding behind 'setup'
308ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    is really done within a Distribution instance, which farms the work out
318ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    to the Distutils commands specified on the command line.
328ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward
338ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    Setup scripts will almost never instantiate Distribution directly,
348ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    unless the 'setup()' function is totally inadequate to their needs.
358ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    However, it is conceivable that a setup script might wish to subclass
368ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    Distribution for some specialized purpose, and then pass the subclass
378ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    to 'setup()' as the 'distclass' keyword argument.  If so, it is
388ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    necessary to respect the expectations that 'setup' has of Distribution.
398ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    See the code for 'setup()', in core.py, for details.
408ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    """
41fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
42fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
43fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # 'global_options' describes the command-line options that may be
4482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # supplied to the setup script prior to any actual commands.
4582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of
46fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # these global options.  This list should be kept to a bare minimum,
47fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # since every global option is also valid as a command option -- and we
48fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # don't want to pollute the commands with too many options that they
49fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # have minimal control over.
50d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    global_options = [('verbose', 'v', "run verbosely (default)"),
51d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                      ('quiet', 'q', "run quietly (turns verbosity off)"),
52d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                      ('dry-run', 'n', "don't actually do anything"),
53d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                      ('help', 'h', "show detailed help message"),
54fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                     ]
5582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
5682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # options that are not propagated to the commands
5782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    display_options = [
5882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('help-commands', None,
5982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "list all available commands"),
6082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('name', None,
6182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print package name"),
6282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('version', 'V',
6382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print package version"),
6482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('fullname', None,
6582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print <package name>-<version>"),
6682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('author', None,
6782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the author's name"),
6882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('author-email', None,
6982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the author's email address"),
7082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('maintainer', None,
7182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the maintainer's name"),
7282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('maintainer-email', None,
7382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the maintainer's email address"),
7482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('contact', None,
75d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward         "print the maintainer's name if known, else the author's"),
7682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('contact-email', None,
77d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward         "print the maintainer's email address if known, else the author's"),
7882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('url', None,
7982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the URL for this package"),
8082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('licence', None,
8182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the licence of the package"),
8282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('license', None,
8382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "alias for --licence"),
8482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('description', None,
8582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the package description"),
86e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward        ('long-description', None,
87e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward         "print the long package description"),
8882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ]
8982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    display_option_names = map(lambda x: string.translate(x[0], longopt_xlate),
9082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                           display_options)
9182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
9282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # negative options are options that exclude other options
93fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    negative_opt = {'quiet': 'verbose'}
94fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
95fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
96fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # -- Creation/initialization methods -------------------------------
97fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
98fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def __init__ (self, attrs=None):
99fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        """Construct a new Distribution instance: initialize all the
1008ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        attributes of a Distribution, and then use 'attrs' (a dictionary
1018ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        mapping attribute names to values) to assign some of those
1028ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        attributes their "real" values.  (Any attributes not mentioned in
1038ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        'attrs' will be assigned to some null value: 0, None, an empty list
1048ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        or dictionary, etc.)  Most importantly, initialize the
1058ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        'command_obj' attribute to the empty dictionary; this will be
1068ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        filled in with real command objects by 'parse_command_line()'.
1078ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        """
108fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
109fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Default values for our command-line options
110fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.verbose = 1
111fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.dry_run = 0
112fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.help = 0
11382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        for attr in self.display_option_names:
11482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward            setattr(self, attr, 0)
11582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
11682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # Store the distribution meta-data (name, version, author, and so
11782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # forth) in a separate object -- we're getting to have enough
11882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # information here (and enough command-line options) that it's
11982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # worth it.  Also delegate 'get_XXX()' methods to the 'metadata'
12082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # object in a sneaky and underhanded (but efficient!) way.
12182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.metadata = DistributionMetadata ()
1224982f98bc919d2a6377e3e0e82c186bc5b1d70ffGreg Ward        method_basenames = dir(self.metadata) + \
1234982f98bc919d2a6377e3e0e82c186bc5b1d70ffGreg Ward                           ['fullname', 'contact', 'contact_email']
1244982f98bc919d2a6377e3e0e82c186bc5b1d70ffGreg Ward        for basename in method_basenames:
1254982f98bc919d2a6377e3e0e82c186bc5b1d70ffGreg Ward            method_name = "get_" + basename
1264982f98bc919d2a6377e3e0e82c186bc5b1d70ffGreg Ward            setattr(self, method_name, getattr(self.metadata, method_name))
127fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
128fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # 'cmdclass' maps command names to class objects, so we
129fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # can 1) quickly figure out which class to instantiate when
130fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # we need to create a new command object, and 2) have a way
13182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # for the setup script to override command classes
132fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.cmdclass = {}
133fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
1349821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        # 'script_name' and 'script_args' are usually set to sys.argv[0]
1359821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        # and sys.argv[1:], but they can be overridden when the caller is
1369821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        # not necessarily a setup script run from the command-line.
1379821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        self.script_name = None
1389821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        self.script_args = None
1399821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward
140d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # 'command_options' is where we store command options between
141d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # parsing them (from config files, the command-line, etc.) and when
142d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # they are actually needed -- ie. when the command in question is
143d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # instantiated.  It is a dictionary of dictionaries of 2-tuples:
144d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        #   command_options = { command_name : { option : (source, value) } }
1451426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        self.command_options = {}
1461426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
147fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # These options are really the business of various commands, rather
148fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # than of the Distribution itself.  We provide aliases for them in
149fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Distribution as a convenience to the developer.
150fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.packages = None
151fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.package_dir = None
152fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.py_modules = None
153fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.libraries = None
15451def7d667a42eac177690e1fe00eab7f2102319Greg Ward        self.headers = None
155fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.ext_modules = None
156fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.ext_package = None
157fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.include_dirs = None
158fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.extra_path = None
159b2e3bb3d6aaf4ef04211b932c64ef9cd5adc56bbGregory P. Smith        self.scripts = None
1606a901dd1bd1d2cfdd744bf7524ccb9b890b28d06Gregory P. Smith        self.data_files = None
161fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
162fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # And now initialize bookkeeping stuff that can't be supplied by
163fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # the caller at all.  'command_obj' maps command names to
164fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Command instances -- that's how we enforce that every command
165fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # class is a singleton.
166fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.command_obj = {}
167fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
168fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # 'have_run' maps command names to boolean values; it keeps track
169fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # of whether we have actually run a particular command, to make it
170fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # cheap to "run" a command whenever we think we might need to -- if
171fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # it's already been done, no need for expensive filesystem
172fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # operations, we just check the 'have_run' dictionary and carry on.
173fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # It's only safe to query 'have_run' for a command class that has
174fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # been instantiated -- a false value will be inserted when the
175fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # command object is created, and replaced with a true value when
176612eb9f58fe38f33484f36bcba97a4b3d8e090a9Greg Ward        # the command is successfully run.  Thus it's probably best to use
177fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # '.get()' rather than a straight lookup.
178fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.have_run = {}
179fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
180fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Now we'll use the attrs dictionary (ultimately, keyword args from
18182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # the setup script) to possibly override any or all of these
18282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # distribution options.
18382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
184fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        if attrs:
185fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
186fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # Pull out the set of command options and work on them
187fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # specifically.  Note that this order guarantees that aliased
188fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # command options will override any supplied redundantly
189fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # through the general options dictionary.
190fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            options = attrs.get ('options')
191fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            if options:
192fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                del attrs['options']
193fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                for (command, cmd_options) in options.items():
1940e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward                    opt_dict = self.get_option_dict(command)
1950e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward                    for (opt, val) in cmd_options.items():
1960e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward                        opt_dict[opt] = ("setup script", val)
197fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
198fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # Now work on the rest of the attributes.  Any attribute that's
199fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # not already defined is invalid!
200fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            for (key,val) in attrs.items():
20182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                if hasattr (self.metadata, key):
20282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                    setattr (self.metadata, key, val)
20382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                elif hasattr (self, key):
204fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                    setattr (self, key, val)
205fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                else:
20602a1a2b077e969e5fef8504cece5852bf641552dGreg Ward                    raise DistutilsSetupError, \
207fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                          "invalid distribution option '%s'" % key
208fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
209fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # __init__ ()
210fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
211fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
2120e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward    def get_option_dict (self, command):
2130e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        """Get the option dictionary for a given command.  If that
2140e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        command's option dictionary hasn't been created yet, then create it
2150e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        and return the new dictionary; otherwise, return the existing
2160e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        option dictionary.
2170e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        """
2180e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward
2190e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        dict = self.command_options.get(command)
2200e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        if dict is None:
2210e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward            dict = self.command_options[command] = {}
2220e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        return dict
2230e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward
2240e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward
225c32d9a69527af6d2823650ea7674e207c975f090Greg Ward    def dump_option_dicts (self, header=None, commands=None, indent=""):
226c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        from pprint import pformat
227c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
228c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if commands is None:             # dump all command option dicts
229c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            commands = self.command_options.keys()
230c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            commands.sort()
231c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
232c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if header is not None:
233c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            print indent + header
234c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            indent = indent + "  "
235c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
236c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if not commands:
237c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            print indent + "no commands known yet"
238c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            return
239c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
240c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        for cmd_name in commands:
241c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            opt_dict = self.command_options.get(cmd_name)
242c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            if opt_dict is None:
243c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                print indent + "no option dict for '%s' command" % cmd_name
244c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            else:
245c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                print indent + "option dict for '%s' command:" % cmd_name
246c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                out = pformat(opt_dict)
247c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                for line in string.split(out, "\n"):
248c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                    print indent + "  " + line
249c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
250c32d9a69527af6d2823650ea7674e207c975f090Greg Ward    # dump_option_dicts ()
251c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
252c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
253c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
254d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    # -- Config file finding/parsing methods ---------------------------
255d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
2561426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith    def find_config_files (self):
2571426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        """Find as many configuration files as should be processed for this
2581426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        platform, and return a list of filenames in the order in which they
2591426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        should be parsed.  The filenames returned are guaranteed to exist
2601426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        (modulo nasty race conditions).
2611426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
2621426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        On Unix, there are three possible config files: pydistutils.cfg in
2631426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        the Distutils installation directory (ie. where the top-level
2641426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        Distutils __inst__.py file lives), .pydistutils.cfg in the user's
2651426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        home directory, and setup.cfg in the current directory.
2661426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
2671426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        On Windows and Mac OS, there are two possible config files:
2681426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        pydistutils.cfg in the Python installation directory (sys.prefix)
269d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        and setup.cfg in the current directory.
270d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
2711426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        files = []
272acf3f6a7000eaed43f8c4e5df249967b06dfc474Greg Ward        check_environ()
273acf3f6a7000eaed43f8c4e5df249967b06dfc474Greg Ward
2741169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        # Where to look for the system-wide Distutils config file
2751169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        sys_dir = os.path.dirname(sys.modules['distutils'].__file__)
2761169687692e5e897033421fe6a73a3c32675a7d7Greg Ward
2771169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        # Look for the system config file
2781169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        sys_file = os.path.join(sys_dir, "distutils.cfg")
2791169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        if os.path.isfile(sys_file):
2801169687692e5e897033421fe6a73a3c32675a7d7Greg Ward            files.append(sys_file)
2811169687692e5e897033421fe6a73a3c32675a7d7Greg Ward
2821169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        # What to call the per-user config file
2831169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        if os.name == 'posix':
28465d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            user_filename = ".pydistutils.cfg"
28565d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton        else:
28665d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            user_filename = "pydistutils.cfg"
287acf3f6a7000eaed43f8c4e5df249967b06dfc474Greg Ward
2881169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        # And look for the user config file
28965d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton        if os.environ.has_key('HOME'):
29065d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            user_file = os.path.join(os.environ.get('HOME'), user_filename)
2911426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith            if os.path.isfile(user_file):
2921426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith                files.append(user_file)
2931426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
2941426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        # All platforms support local setup.cfg
2951426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        local_file = "setup.cfg"
2961426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        if os.path.isfile(local_file):
2971426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith            files.append(local_file)
2981426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
2991426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        return files
3001426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3011426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith    # find_config_files ()
3021426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3031426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3041426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith    def parse_config_files (self, filenames=None):
3051426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3061426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        from ConfigParser import ConfigParser
3072bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward        from distutils.core import DEBUG
3081426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3091426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        if filenames is None:
3101426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith            filenames = self.find_config_files()
3111426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3122bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward        if DEBUG: print "Distribution.parse_config_files():"
313474607777d10562679b1640d3831290b0c4284f7Greg Ward
3141426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        parser = ConfigParser()
315d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        for filename in filenames:
3162bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward            if DEBUG: print "  reading", filename
317d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            parser.read(filename)
318d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            for section in parser.sections():
319d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                options = parser.options(section)
3200e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward                opt_dict = self.get_option_dict(section)
321d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
322d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                for opt in options:
323d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                    if opt != '__name__':
3240e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward                        opt_dict[opt] = (filename, parser.get(section,opt))
3251426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
326474607777d10562679b1640d3831290b0c4284f7Greg Ward            # Make the ConfigParser forget everything (so we retain
327474607777d10562679b1640d3831290b0c4284f7Greg Ward            # the original filenames that options come from) -- gag,
328474607777d10562679b1640d3831290b0c4284f7Greg Ward            # retch, puke -- another good reason for a distutils-
329474607777d10562679b1640d3831290b0c4284f7Greg Ward            # specific config parser (sigh...)
330474607777d10562679b1640d3831290b0c4284f7Greg Ward            parser.__init__()
3311426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3321426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
333d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    # -- Command-line parsing methods ----------------------------------
334fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
3359821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward    def parse_command_line (self):
3369821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        """Parse the setup script's command line, taken from the
3379821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        'script_args' instance attribute (which defaults to 'sys.argv[1:]'
3389821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        -- see 'setup()' in core.py).  This list is first processed for
3399821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        "global options" -- options that set attributes of the Distribution
3409821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        instance.  Then, it is alternately scanned for Distutils commands
3419821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        and options for that command.  Each new command terminates the
3429821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        options for the previous command.  The allowed options for a
3439821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        command are determined by the 'user_options' attribute of the
3449821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        command class -- thus, we have to be able to load command classes
3459821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        in order to parse the command line.  Any error in that 'options'
3469821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        attribute raises DistutilsGetoptError; any error on the
3479821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        command-line raises DistutilsArgError.  If no Distutils commands
3489821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        were found on the command line, raises DistutilsArgError.  Return
3499821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        true if command-line were successfully parsed and we should carry
3509821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        on with executing commands; false if no errors but we shouldn't
3519821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        execute commands (currently, this only happens if user asks for
3529821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        help).
353d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
354fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # We have to parse the command line a bit at a time -- global
355fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # options, then the first command, then its options, and so on --
356fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # because each command will be handled by a different class, and
357d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # the options that are valid for a particular class aren't known
358d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # until we have loaded the command class, which doesn't happen
359d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # until we know what the command is.
360fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
361fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.commands = []
36282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        parser = FancyGetopt (self.global_options + self.display_options)
36382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        parser.set_negative_aliases (self.negative_opt)
36458ec6ede20d0b632f8325e1363aaa6e445ad61efGreg Ward        parser.set_aliases ({'license': 'licence'})
3659821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        args = parser.getopt (args=self.script_args, object=self)
36682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        option_order = parser.get_option_order()
367fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
36882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # for display options we return immediately
36982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        if self.handle_display_options(option_order):
370fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            return
371fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
372fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        while args:
373d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            args = self._parse_command_opts(parser, args)
374d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            if args is None:            # user asked for help (and got it)
375fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                return
376fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
377d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Handle the cases of --help as a "global" option, ie.
378d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # "setup.py --help" and "setup.py --help command ...".  For the
379d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # former, we show global options (--verbose, --dry-run, etc.)
380d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # and display-only options (--name, --version, etc.); for the
381d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # latter, we omit the display-only options and show help for
382d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # each command listed on the command line.
383d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if self.help:
384d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            self._show_help(parser,
385d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                            display_options=len(self.commands) == 0,
386d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                            commands=self.commands)
387fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            return
388fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
389fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Oops, no commands found -- an end-user error
390fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        if not self.commands:
391fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            raise DistutilsArgError, "no commands supplied"
392fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
393fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # All is well: return true
394fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return 1
395fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
396fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # parse_command_line()
397fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
398d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    def _parse_command_opts (self, parser, args):
399d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """Parse the command-line options for a single command.
400d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        'parser' must be a FancyGetopt instance; 'args' must be the list
401d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        of arguments, starting with the current command (whose options
402d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        we are about to parse).  Returns a new version of 'args' with
403d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        the next command at the front of the list; will be the empty
404d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        list if there are no more commands on the command line.  Returns
405d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        None if the user asked for help on this command.
406d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
407d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # late import because of mutual dependence between these modules
408d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        from distutils.cmd import Command
409d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
410d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Pull the current command from the head of the command line
411d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        command = args[0]
412d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if not command_re.match (command):
413d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            raise SystemExit, "invalid command name '%s'" % command
414d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        self.commands.append (command)
415d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
416d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Dig up the command class that implements this command, so we
417d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # 1) know that it's a valid command, and 2) know which options
418d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # it takes.
419d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        try:
420d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            cmd_class = self.get_command_class (command)
421d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        except DistutilsModuleError, msg:
422d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            raise DistutilsArgError, msg
423d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
424d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Require that the command class be derived from Command -- want
425d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # to be sure that the basic "command" interface is implemented.
426d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if not issubclass (cmd_class, Command):
427d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            raise DistutilsClassError, \
428d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                  "command class %s must subclass Command" % cmd_class
429d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
430d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Also make sure that the command object provides a list of its
431d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # known options.
432d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if not (hasattr (cmd_class, 'user_options') and
433d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                type (cmd_class.user_options) is ListType):
434d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            raise DistutilsClassError, \
435d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                  ("command class %s must provide " +
436d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                   "'user_options' attribute (a list of tuples)") % \
437d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                  cmd_class
438d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
439d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # If the command class has a list of negative alias options,
440d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # merge it in with the global negative aliases.
441d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        negative_opt = self.negative_opt
442d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if hasattr (cmd_class, 'negative_opt'):
443d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            negative_opt = copy (negative_opt)
444d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            negative_opt.update (cmd_class.negative_opt)
445d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
4462ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward	# Check for help_options in command class.  They have a different
4472ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward	# format (tuple of four) so we need to preprocess them here.
44865d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton        if (hasattr(cmd_class, 'help_options') and
4492ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward            type (cmd_class.help_options) is ListType):
4502ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward            help_options = fix_help_options(cmd_class.help_options)
4512ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward        else:
45255fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward            help_options = []
4532ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward
4549d17a7ad6df0a940f8f10cf7a113aaffc4222309Greg Ward
455d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # All commands support the global options too, just by adding
456d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # in 'global_options'.
457d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        parser.set_option_table (self.global_options +
45855fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward                                 cmd_class.user_options +
45955fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward                                 help_options)
460d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        parser.set_negative_aliases (negative_opt)
461d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        (args, opts) = parser.getopt (args[1:])
462474607777d10562679b1640d3831290b0c4284f7Greg Ward        if hasattr(opts, 'help') and opts.help:
463d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            self._show_help(parser, display_options=0, commands=[cmd_class])
464d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            return
465d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
46665d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton        if (hasattr(cmd_class, 'help_options') and
4672ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward            type (cmd_class.help_options) is ListType):
46865d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            help_option_found=0
46965d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            for (help_option, short, desc, func) in cmd_class.help_options:
47065d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton                if hasattr(opts, parser.get_attr_name(help_option)):
47165d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton                    help_option_found=1
4722ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward		    #print "showing help for option %s of command %s" % \
4732ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward                    #      (help_option[0],cmd_class)
47455fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward
47555fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward                    if callable(func):
47665d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton                        func()
47755fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward                    else:
47855fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward                        raise DistutilsClassError, \
47955fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward                            ("invalid help function %s for help option '%s': "
48055fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward                             "must be a callable object (function, etc.)") % \
48155fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward                            (`func`, help_option)
48255fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward
48355fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward            if help_option_found:
48465d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton                return
4859d17a7ad6df0a940f8f10cf7a113aaffc4222309Greg Ward
486d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Put the options from the command-line into their official
487d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # holding pen, the 'command_options' dictionary.
4880e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        opt_dict = self.get_option_dict(command)
489d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        for (name, value) in vars(opts).items():
4900e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward            opt_dict[name] = ("command line", value)
491d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
492d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        return args
493d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
494d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    # _parse_command_opts ()
495d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
496d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
497d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    def _show_help (self,
498d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                    parser,
499d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                    global_options=1,
500d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                    display_options=1,
501d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                    commands=[]):
502d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """Show help for the setup script command-line in the form of
503d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        several lists of command-line options.  'parser' should be a
504d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        FancyGetopt instance; do not expect it to be returned in the
505d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        same state, as its option table will be reset to make it
506d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        generate the correct help text.
507d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
508d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        If 'global_options' is true, lists the global options:
509d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        --verbose, --dry-run, etc.  If 'display_options' is true, lists
510d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        the "display-only" options: --name, --version, etc.  Finally,
511d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        lists per-command help for every command name or command class
512d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        in 'commands'.
513d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
514d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # late import because of mutual dependence between these modules
5159821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        from distutils.core import gen_usage
516d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        from distutils.cmd import Command
517d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
518d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if global_options:
519d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            parser.set_option_table (self.global_options)
520d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            parser.print_help ("Global options:")
521d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            print
522d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
523d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if display_options:
524d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            parser.set_option_table (self.display_options)
525d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            parser.print_help (
526d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                "Information display options (just display " +
527d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                "information, ignore any commands)")
528d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            print
529d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
530d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        for command in self.commands:
531d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            if type(command) is ClassType and issubclass(klass, Command):
532d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                klass = command
533d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            else:
534d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                klass = self.get_command_class (command)
53565d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            if (hasattr(klass, 'help_options') and
5362ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward                type (klass.help_options) is ListType):
53765d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton                parser.set_option_table (klass.user_options +
5382ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward                                         fix_help_options(klass.help_options))
53965d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            else:
54065d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton                parser.set_option_table (klass.user_options)
541d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            parser.print_help ("Options for '%s' command:" % klass.__name__)
542d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            print
543d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
5449821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        print gen_usage(self.script_name)
545d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        return
546d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
547d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    # _show_help ()
5489d17a7ad6df0a940f8f10cf7a113aaffc4222309Greg Ward
549d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
55082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def handle_display_options (self, option_order):
55182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        """If there were any non-global "display-only" options
552d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        (--help-commands or the metadata display options) on the command
553d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        line, display the requested info and return true; else return
554d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        false.
555d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
5569821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        from distutils.core import gen_usage
55782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
55882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # User just wants a list of commands -- we'll print it out and stop
55982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # processing now (ie. if they ran "setup --help-commands foo bar",
56082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # we ignore "foo bar").
56182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        if self.help_commands:
56282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward            self.print_commands ()
56382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward            print
5649821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward            print gen_usage(self.script_name)
56582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward            return 1
56682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
56782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # If user supplied any of the "display metadata" options, then
56882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # display that metadata in the order in which the user supplied the
56982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # metadata options.
57082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        any_display_options = 0
57182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        is_display_option = {}
57282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        for option in self.display_options:
57382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward            is_display_option[option[0]] = 1
57482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
57582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        for (opt, val) in option_order:
57682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward            if val and is_display_option.get(opt):
57782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                opt = string.translate (opt, longopt_xlate)
57882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                print getattr(self.metadata, "get_"+opt)()
57982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                any_display_options = 1
58082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
58182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return any_display_options
58282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
58382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # handle_display_options()
584fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
585fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def print_command_list (self, commands, header, max_length):
586fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        """Print a subset of the list of all commands -- used by
587d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        'print_commands()'.
588d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
589fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
590fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        print header + ":"
591fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
592fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        for cmd in commands:
593fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            klass = self.cmdclass.get (cmd)
594fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            if not klass:
595d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                klass = self.get_command_class (cmd)
596fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            try:
597fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                description = klass.description
598fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            except AttributeError:
599fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                description = "(no description available)"
600fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
601fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            print "  %-*s  %s" % (max_length, cmd, description)
602fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
603fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # print_command_list ()
604fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
605fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
606fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def print_commands (self):
607d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """Print out a help message listing all available commands with a
608d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        description of each.  The list is divided into "standard commands"
609d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        (listed in distutils.command.__all__) and "extra commands"
610d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        (mentioned in self.cmdclass, but not a standard command).  The
611d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        descriptions come from the command class attribute
612d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        'description'.
613d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
614fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
615fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        import distutils.command
616fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        std_commands = distutils.command.__all__
617fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        is_std = {}
618fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        for cmd in std_commands:
619fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            is_std[cmd] = 1
620fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
621fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        extra_commands = []
622fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        for cmd in self.cmdclass.keys():
623fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            if not is_std.get(cmd):
624fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                extra_commands.append (cmd)
625fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
626fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        max_length = 0
627fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        for cmd in (std_commands + extra_commands):
628fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            if len (cmd) > max_length:
629fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                max_length = len (cmd)
630fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
631fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.print_command_list (std_commands,
632fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                                 "Standard commands",
633fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                                 max_length)
634fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        if extra_commands:
635fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            print
636fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            self.print_command_list (extra_commands,
637fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                                     "Extra commands",
638fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                                     max_length)
639fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
640fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # print_commands ()
641fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
642fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
643fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # -- Command class/object methods ----------------------------------
644fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
645d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    def get_command_class (self, command):
646d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """Return the class that implements the Distutils command named by
647d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        'command'.  First we check the 'cmdclass' dictionary; if the
648d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        command is mentioned there, we fetch the class object from the
649d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        dictionary and return it.  Otherwise we load the command module
650d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        ("distutils.command." + command) and fetch the command class from
651d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        the module.  The loaded class is also stored in 'cmdclass'
652d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        to speed future calls to 'get_command_class()'.
6531426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
6541426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        Raises DistutilsModuleError if the expected module could not be
655d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        found, or if that module does not define the expected class.
656d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
657d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        klass = self.cmdclass.get(command)
658d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if klass:
659d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            return klass
660fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
661fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        module_name = 'distutils.command.' + command
662fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        klass_name = command
663fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
664fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        try:
665fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            __import__ (module_name)
666fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            module = sys.modules[module_name]
667fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        except ImportError:
668fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            raise DistutilsModuleError, \
669fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                  "invalid command '%s' (no module named '%s')" % \
670fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                  (command, module_name)
671fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
672fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        try:
673d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            klass = getattr(module, klass_name)
674d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        except AttributeError:
675fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            raise DistutilsModuleError, \
676fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                  "invalid command '%s' (no class '%s' in module '%s')" \
677fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                  % (command, klass_name, module_name)
678fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
679d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        self.cmdclass[command] = klass
680fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return klass
681fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
682d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    # get_command_class ()
683fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
684d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    def get_command_obj (self, command, create=1):
685d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """Return the command object for 'command'.  Normally this object
686612eb9f58fe38f33484f36bcba97a4b3d8e090a9Greg Ward        is cached on a previous call to 'get_command_obj()'; if no command
687d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        object for 'command' is in the cache, then we either create and
688d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        return it (if 'create' is true) or return None.
689d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
6902bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward        from distutils.core import DEBUG
691d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        cmd_obj = self.command_obj.get(command)
692fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        if not cmd_obj and create:
6932bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward            if DEBUG:
6942bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward                print "Distribution.get_command_obj(): " \
6952bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward                      "creating '%s' command object" % command
696474607777d10562679b1640d3831290b0c4284f7Greg Ward
697d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            klass = self.get_command_class(command)
698474607777d10562679b1640d3831290b0c4284f7Greg Ward            cmd_obj = self.command_obj[command] = klass(self)
699474607777d10562679b1640d3831290b0c4284f7Greg Ward            self.have_run[command] = 0
700474607777d10562679b1640d3831290b0c4284f7Greg Ward
701474607777d10562679b1640d3831290b0c4284f7Greg Ward            # Set any options that were supplied in config files
702474607777d10562679b1640d3831290b0c4284f7Greg Ward            # or on the command line.  (NB. support for error
703474607777d10562679b1640d3831290b0c4284f7Greg Ward            # reporting is lame here: any errors aren't reported
704474607777d10562679b1640d3831290b0c4284f7Greg Ward            # until 'finalize_options()' is called, which means
705474607777d10562679b1640d3831290b0c4284f7Greg Ward            # we won't report the source of the error.)
706474607777d10562679b1640d3831290b0c4284f7Greg Ward            options = self.command_options.get(command)
707474607777d10562679b1640d3831290b0c4284f7Greg Ward            if options:
708c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                self._set_command_options(cmd_obj, options)
709fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
710fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return cmd_obj
711fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
712c32d9a69527af6d2823650ea7674e207c975f090Greg Ward    def _set_command_options (self, command_obj, option_dict=None):
713c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        """Set the options for 'command_obj' from 'option_dict'.  Basically
714c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        this means copying elements of a dictionary ('option_dict') to
715c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        attributes of an instance ('command').
716c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
717c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        'command_obj' must be a Commnd instance.  If 'option_dict' is not
718c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        supplied, uses the standard option dictionary for this command
719c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        (from 'self.command_options').
720c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        """
721c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        from distutils.core import DEBUG
722c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
723c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        command_name = command_obj.get_command_name()
724c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if option_dict is None:
725c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            option_dict = self.get_option_dict(command_name)
726c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
727c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if DEBUG: print "  setting options for '%s' command:" % command_name
728c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        for (option, (source, value)) in option_dict.items():
729c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            if DEBUG: print "    %s = %s (from %s)" % (option, value, source)
730c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            if not hasattr(command_obj, option):
731c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                raise DistutilsOptionError, \
732c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                      ("error in %s: command '%s' has no such option '%s'") % \
733c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                      (source, command_name, option)
734c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            setattr(command_obj, option, value)
735c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
736f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward    def reinitialize_command (self, command, reinit_subcommands=0):
737c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        """Reinitializes a command to the state it was in when first
738c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        returned by 'get_command_obj()': ie., initialized but not yet
7397d9c705b234ad2ad013db1649e5fd2ffc2a59a75Greg Ward        finalized.  This provides the opportunity to sneak option
740c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        values in programmatically, overriding or supplementing
741c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        user-supplied values from the config files and command line.
742c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        You'll have to re-finalize the command object (by calling
743c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        'finalize_options()' or 'ensure_finalized()') before using it for
744c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        real.
745c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
746f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        'command' should be a command name (string) or command object.  If
747f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        'reinit_subcommands' is true, also reinitializes the command's
748f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        sub-commands, as declared by the 'sub_commands' class attribute (if
749f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        it has one).  See the "install" command for an example.  Only
750f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        reinitializes the sub-commands that actually matter, ie. those
751f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        whose test predicates return true.
752f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward
753c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        Returns the reinitialized command object.
754c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        """
755f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        print "reinitialize_command: command=%s" % command
756f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        print "  before: have_run =", self.have_run
757f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward
758c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        from distutils.cmd import Command
759c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if not isinstance(command, Command):
760c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            command_name = command
761c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            command = self.get_command_obj(command_name)
762c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        else:
763c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            command_name = command.get_command_name()
764c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
765c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if not command.finalized:
766282c7a0230b578147a89a18ec22410b830edddfeGreg Ward            return command
767c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        command.initialize_options()
768c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        command.finalized = 0
76943955c9a023ea7b50b28052112dbdc914c090a27Greg Ward        self.have_run[command_name] = 0
770c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        self._set_command_options(command)
771f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward
772f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        print "  after:  have_run =", self.have_run
773f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward
774f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        if reinit_subcommands:
775f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward            print ("  reinitializing sub-commands: %s" %
776f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward                   command.get_sub_commands())
777f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward            for sub in command.get_sub_commands():
778f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward                self.reinitialize_command(sub, reinit_subcommands)
779f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward
780c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        return command
781c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
782fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
783fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # -- Methods that operate on the Distribution ----------------------
784fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
785fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def announce (self, msg, level=1):
786fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        """Print 'msg' if 'level' is greater than or equal to the verbosity
787d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        level recorded in the 'verbose' attribute (which, currently, can be
788d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        only 0 or 1).
789d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
790fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        if self.verbose >= level:
791fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            print msg
792fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
793fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
794fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def run_commands (self):
79582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        """Run each command that was seen on the setup script command line.
796d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        Uses the list of commands found and cache of command objects
797d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        created by 'get_command_obj()'."""
798fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
799fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        for cmd in self.commands:
800fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            self.run_command (cmd)
801fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
802fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
803fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # -- Methods that operate on its Commands --------------------------
804fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
805fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def run_command (self, command):
806fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        """Do whatever it takes to run a command (including nothing at all,
807d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if the command has already been run).  Specifically: if we have
808d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        already created and run the command named by 'command', return
809d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        silently without doing anything.  If the command named by 'command'
810d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        doesn't even have a command object yet, create one.  Then invoke
811d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        'run()' on that command object (or an existing one).
812d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
813fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
814fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Already been here, done that? then return silently.
815fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        if self.have_run.get (command):
816fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            return
817fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
818fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.announce ("running " + command)
819d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        cmd_obj = self.get_command_obj (command)
8204fb29e55f8f53e60b36eae3fbe56e9666aacc9c5Greg Ward        cmd_obj.ensure_finalized ()
821fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        cmd_obj.run ()
822fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.have_run[command] = 1
823fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
824fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
825fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # -- Distribution query methods ------------------------------------
826fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
827fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def has_pure_modules (self):
828fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return len (self.packages or self.py_modules or []) > 0
829fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
830fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def has_ext_modules (self):
831fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return self.ext_modules and len (self.ext_modules) > 0
832fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
833fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def has_c_libraries (self):
834fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return self.libraries and len (self.libraries) > 0
835fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
836fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def has_modules (self):
837fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return self.has_pure_modules() or self.has_ext_modules()
838fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
83951def7d667a42eac177690e1fe00eab7f2102319Greg Ward    def has_headers (self):
84051def7d667a42eac177690e1fe00eab7f2102319Greg Ward        return self.headers and len(self.headers) > 0
84151def7d667a42eac177690e1fe00eab7f2102319Greg Ward
84244a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward    def has_scripts (self):
84344a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward        return self.scripts and len(self.scripts) > 0
84444a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward
84544a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward    def has_data_files (self):
84644a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward        return self.data_files and len(self.data_files) > 0
84744a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward
848fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def is_pure (self):
849fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return (self.has_pure_modules() and
850fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                not self.has_ext_modules() and
851fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                not self.has_c_libraries())
852fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
85382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # -- Metadata query methods ----------------------------------------
85482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
85582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # If you're looking for 'get_name()', 'get_version()', and so forth,
85682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # they are defined in a sneaky way: the constructor binds self.get_XXX
85782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # to self.metadata.get_XXX.  The actual code is in the
85882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # DistributionMetadata class, below.
85982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
86082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward# class Distribution
86182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
86282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
86382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Wardclass DistributionMetadata:
86482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    """Dummy class to hold the distribution meta-data: name, version,
86582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    author, and so forth."""
86682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
86782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def __init__ (self):
86882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.name = None
86982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.version = None
87082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.author = None
87182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.author_email = None
87282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.maintainer = None
87382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.maintainer_email = None
87482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.url = None
87582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.licence = None
87682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.description = None
877e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward        self.long_description = None
87882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
87982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # -- Metadata query methods ----------------------------------------
88082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
881fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def get_name (self):
882fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return self.name or "UNKNOWN"
883fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
88482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_version(self):
88582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.version or "???"
88682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
88782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_fullname (self):
88882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return "%s-%s" % (self.get_name(), self.get_version())
88982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
89082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_author(self):
89182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.author or "UNKNOWN"
892fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
89382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_author_email(self):
89482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.author_email or "UNKNOWN"
89582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
89682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_maintainer(self):
89782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.maintainer or "UNKNOWN"
89882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
89982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_maintainer_email(self):
90082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.maintainer_email or "UNKNOWN"
90182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
90282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_contact(self):
90382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return (self.maintainer or
90482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                self.author or
90582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                "UNKNOWN")
90682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
90782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_contact_email(self):
90882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return (self.maintainer_email or
90982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                self.author_email or
91082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                "UNKNOWN")
91182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
91282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_url(self):
91382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.url or "UNKNOWN"
91482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
91582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_licence(self):
91682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.licence or "UNKNOWN"
91782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
91882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_description(self):
91982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.description or "UNKNOWN"
920e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward
921e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward    def get_long_description(self):
922e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward        return self.long_description or "UNKNOWN"
923e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward
92482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward# class DistributionMetadata
925fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
9262ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward
9272ff7887270385bd6dddc2d5461486334b4fec8bcGreg Warddef fix_help_options (options):
9282ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    """Convert a 4-tuple 'help_options' list as found in various command
9292ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    classes to the 3-tuple form required by FancyGetopt.
9302ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    """
9312ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    new_options = []
9322ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    for help_tuple in options:
9332ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward        new_options.append(help_tuple[0:3])
9342ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    return new_options
9352ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward
9362ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward
937fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Wardif __name__ == "__main__":
938fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    dist = Distribution ()
939fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    print "ok"
940