dist.py revision ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1
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
15ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1Andrew M. Kuchling
16ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1Andrew M. Kuchlingtry:
17ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1Andrew M. Kuchling    import warnings
18ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1Andrew M. Kuchlingexcept:
19ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1Andrew M. Kuchling    warnings = None
20ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1Andrew M. Kuchling
21fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Wardfrom distutils.errors import *
222f2b6c62baf42e06c06f0dcae4879cf88dd6a916Greg Wardfrom distutils.fancy_getopt import FancyGetopt, translate_longopt
23a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchlingfrom distutils.util import check_environ, strtobool, rfc822_escape
24cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hyltonfrom distutils import log
25fcd7353863c024bb87aabe7c4639ca8df692ac85Jeremy Hyltonfrom distutils.debug import DEBUG
26fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
27fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward# Regex to define acceptable Distutils command names.  This is not *quite*
28fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward# the same as a Python NAME -- I don't allow leading underscores.  The fact
29fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward# that they're very similar is no coincidence; the default naming scheme is
30fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward# to look for a Python module named after the command.
31fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Wardcommand_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$')
32fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
33fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
34fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Wardclass Distribution:
358ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    """The core of the Distutils.  Most of the work hiding behind 'setup'
368ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    is really done within a Distribution instance, which farms the work out
378ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    to the Distutils commands specified on the command line.
388ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward
398ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    Setup scripts will almost never instantiate Distribution directly,
408ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    unless the 'setup()' function is totally inadequate to their needs.
418ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    However, it is conceivable that a setup script might wish to subclass
428ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    Distribution for some specialized purpose, and then pass the subclass
438ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    to 'setup()' as the 'distclass' keyword argument.  If so, it is
448ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    necessary to respect the expectations that 'setup' has of Distribution.
458ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    See the code for 'setup()', in core.py, for details.
468ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward    """
47fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
48fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
49fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # 'global_options' describes the command-line options that may be
5082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # supplied to the setup script prior to any actual commands.
5182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of
52fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # these global options.  This list should be kept to a bare minimum,
53fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # since every global option is also valid as a command option -- and we
54fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # don't want to pollute the commands with too many options that they
55fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # have minimal control over.
56cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hylton    # The fourth entry for verbose means that it can be repeated.
57cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hylton    global_options = [('verbose', 'v', "run verbosely (default)", 1),
58d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                      ('quiet', 'q', "run quietly (turns verbosity off)"),
59d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                      ('dry-run', 'n', "don't actually do anything"),
60d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                      ('help', 'h', "show detailed help message"),
61fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                     ]
6282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
6382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # options that are not propagated to the commands
6482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    display_options = [
6582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('help-commands', None,
6682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "list all available commands"),
6782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('name', None,
6882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print package name"),
6982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('version', 'V',
7082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print package version"),
7182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('fullname', None,
7282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print <package name>-<version>"),
7382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('author', None,
7482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the author's name"),
7582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('author-email', None,
7682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the author's email address"),
7782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('maintainer', None,
7882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the maintainer's name"),
7982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('maintainer-email', None,
8082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the maintainer's email address"),
8182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('contact', None,
82d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward         "print the maintainer's name if known, else the author's"),
8382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('contact-email', None,
84d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward         "print the maintainer's email address if known, else the author's"),
8582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('url', None,
8682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the URL for this package"),
8782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('license', None,
88fa7dc57d6c9023a5028aacb802438527ab2cfaceAndrew M. Kuchling         "print the license of the package"),
89fa7dc57d6c9023a5028aacb802438527ab2cfaceAndrew M. Kuchling        ('licence', None,
90fa7dc57d6c9023a5028aacb802438527ab2cfaceAndrew M. Kuchling         "alias for --license"),
9182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ('description', None,
9282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward         "print the package description"),
93e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward        ('long-description', None,
94e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward         "print the long package description"),
95a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        ('platforms', None,
96a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling         "print the list of platforms"),
97a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        ('keywords', None,
98a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling         "print the list of keywords"),
9982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        ]
1002f2b6c62baf42e06c06f0dcae4879cf88dd6a916Greg Ward    display_option_names = map(lambda x: translate_longopt(x[0]),
1012f2b6c62baf42e06c06f0dcae4879cf88dd6a916Greg Ward                               display_options)
10282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
10382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # negative options are options that exclude other options
104fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    negative_opt = {'quiet': 'verbose'}
105fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
106fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
107fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # -- Creation/initialization methods -------------------------------
108b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake
109fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def __init__ (self, attrs=None):
110fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        """Construct a new Distribution instance: initialize all the
1118ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        attributes of a Distribution, and then use 'attrs' (a dictionary
1128ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        mapping attribute names to values) to assign some of those
1138ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        attributes their "real" values.  (Any attributes not mentioned in
1148ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        'attrs' will be assigned to some null value: 0, None, an empty list
1158ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        or dictionary, etc.)  Most importantly, initialize the
1168ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        'command_obj' attribute to the empty dictionary; this will be
1178ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        filled in with real command objects by 'parse_command_line()'.
1188ff5a3fd926cd42ed8f4ceaf5300d64bbe43d152Greg Ward        """
119fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
120fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Default values for our command-line options
121fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.verbose = 1
122fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.dry_run = 0
123fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.help = 0
12482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        for attr in self.display_option_names:
12582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward            setattr(self, attr, 0)
12682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
12782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # Store the distribution meta-data (name, version, author, and so
12882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # forth) in a separate object -- we're getting to have enough
12982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # information here (and enough command-line options) that it's
13082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # worth it.  Also delegate 'get_XXX()' methods to the 'metadata'
13182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # object in a sneaky and underhanded (but efficient!) way.
132fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        self.metadata = DistributionMetadata()
133a8aefe535c879c8b0f5201961648a89c8e3d7887Neil Schemenauer        for basename in self.metadata._METHOD_BASENAMES:
1344982f98bc919d2a6377e3e0e82c186bc5b1d70ffGreg Ward            method_name = "get_" + basename
1354982f98bc919d2a6377e3e0e82c186bc5b1d70ffGreg Ward            setattr(self, method_name, getattr(self.metadata, method_name))
136fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
137fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # 'cmdclass' maps command names to class objects, so we
138fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # can 1) quickly figure out which class to instantiate when
139fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # we need to create a new command object, and 2) have a way
14082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # for the setup script to override command classes
141fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.cmdclass = {}
142fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
1439821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        # 'script_name' and 'script_args' are usually set to sys.argv[0]
1449821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        # and sys.argv[1:], but they can be overridden when the caller is
1459821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        # not necessarily a setup script run from the command-line.
1469821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        self.script_name = None
1479821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        self.script_args = None
1489821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward
149d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # 'command_options' is where we store command options between
150d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # parsing them (from config files, the command-line, etc.) and when
151d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # they are actually needed -- ie. when the command in question is
152d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # instantiated.  It is a dictionary of dictionaries of 2-tuples:
153d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        #   command_options = { command_name : { option : (source, value) } }
1541426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        self.command_options = {}
1551426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
156fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # These options are really the business of various commands, rather
157fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # than of the Distribution itself.  We provide aliases for them in
158fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Distribution as a convenience to the developer.
159fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.packages = None
160fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.package_dir = None
161fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.py_modules = None
162fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.libraries = None
16351def7d667a42eac177690e1fe00eab7f2102319Greg Ward        self.headers = None
164fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.ext_modules = None
165fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.ext_package = None
166fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.include_dirs = None
167fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.extra_path = None
168b2e3bb3d6aaf4ef04211b932c64ef9cd5adc56bbGregory P. Smith        self.scripts = None
1696a901dd1bd1d2cfdd744bf7524ccb9b890b28d06Gregory P. Smith        self.data_files = None
170fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
171fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # And now initialize bookkeeping stuff that can't be supplied by
172fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # the caller at all.  'command_obj' maps command names to
173fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Command instances -- that's how we enforce that every command
174fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # class is a singleton.
175fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.command_obj = {}
176fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
177fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # 'have_run' maps command names to boolean values; it keeps track
178fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # of whether we have actually run a particular command, to make it
179fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # cheap to "run" a command whenever we think we might need to -- if
180fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # it's already been done, no need for expensive filesystem
181fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # operations, we just check the 'have_run' dictionary and carry on.
182fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # It's only safe to query 'have_run' for a command class that has
183fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # been instantiated -- a false value will be inserted when the
184fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # command object is created, and replaced with a true value when
185612eb9f58fe38f33484f36bcba97a4b3d8e090a9Greg Ward        # the command is successfully run.  Thus it's probably best to use
186fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # '.get()' rather than a straight lookup.
187fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.have_run = {}
188fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
189fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Now we'll use the attrs dictionary (ultimately, keyword args from
19082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # the setup script) to possibly override any or all of these
19182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # distribution options.
19282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
193fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        if attrs:
194fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
195fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # Pull out the set of command options and work on them
196fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # specifically.  Note that this order guarantees that aliased
197fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # command options will override any supplied redundantly
198fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # through the general options dictionary.
199fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            options = attrs.get('options')
200fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            if options:
201fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                del attrs['options']
202fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                for (command, cmd_options) in options.items():
2030e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward                    opt_dict = self.get_option_dict(command)
2040e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward                    for (opt, val) in cmd_options.items():
2050e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward                        opt_dict[opt] = ("setup script", val)
206fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
207fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # Now work on the rest of the attributes.  Any attribute that's
208fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            # not already defined is invalid!
209fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            for (key,val) in attrs.items():
210fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                if hasattr(self.metadata, key):
211fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                    setattr(self.metadata, key, val)
212fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                elif hasattr(self, key):
213fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                    setattr(self, key, val)
214fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                else:
215ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1Andrew M. Kuchling                    msg = "Unknown distribution option: %s" % repr(key)
216ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1Andrew M. Kuchling                    if warnings is not None:
217ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1Andrew M. Kuchling                        warnings.warn(msg)
218ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1Andrew M. Kuchling                    else:
219ff4ad9a1cec90b66b65cb5f1b647e41742d7aab1Andrew M. Kuchling                        sys.stderr.write(msg + "\n")
220fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
221a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        self.finalize_options()
222b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake
223fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # __init__ ()
224fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
225fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
2260e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward    def get_option_dict (self, command):
2270e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        """Get the option dictionary for a given command.  If that
2280e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        command's option dictionary hasn't been created yet, then create it
2290e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        and return the new dictionary; otherwise, return the existing
2300e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        option dictionary.
2310e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        """
2320e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward
2330e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        dict = self.command_options.get(command)
2340e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        if dict is None:
2350e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward            dict = self.command_options[command] = {}
2360e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        return dict
2370e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward
2380e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward
239c32d9a69527af6d2823650ea7674e207c975f090Greg Ward    def dump_option_dicts (self, header=None, commands=None, indent=""):
240c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        from pprint import pformat
241c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
242c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if commands is None:             # dump all command option dicts
243c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            commands = self.command_options.keys()
244c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            commands.sort()
245c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
246c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if header is not None:
247c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            print indent + header
248c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            indent = indent + "  "
249c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
250c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if not commands:
251c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            print indent + "no commands known yet"
252c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            return
253c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
254c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        for cmd_name in commands:
255c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            opt_dict = self.command_options.get(cmd_name)
256c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            if opt_dict is None:
257c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                print indent + "no option dict for '%s' command" % cmd_name
258c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            else:
259c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                print indent + "option dict for '%s' command:" % cmd_name
260c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                out = pformat(opt_dict)
261c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                for line in string.split(out, "\n"):
262c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                    print indent + "  " + line
263c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
264c32d9a69527af6d2823650ea7674e207c975f090Greg Ward    # dump_option_dicts ()
265b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake
266c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
267c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
268d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    # -- Config file finding/parsing methods ---------------------------
269d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
2701426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith    def find_config_files (self):
2711426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        """Find as many configuration files as should be processed for this
2721426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        platform, and return a list of filenames in the order in which they
2731426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        should be parsed.  The filenames returned are guaranteed to exist
2741426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        (modulo nasty race conditions).
2751426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
276d303b61eb4f8e893ea558bd3b829561ffc28514eAndrew M. Kuchling        There are three possible config files: distutils.cfg in the
277d303b61eb4f8e893ea558bd3b829561ffc28514eAndrew M. Kuchling        Distutils installation directory (ie. where the top-level
278d303b61eb4f8e893ea558bd3b829561ffc28514eAndrew M. Kuchling        Distutils __inst__.py file lives), a file in the user's home
279d303b61eb4f8e893ea558bd3b829561ffc28514eAndrew M. Kuchling        directory named .pydistutils.cfg on Unix and pydistutils.cfg
280d303b61eb4f8e893ea558bd3b829561ffc28514eAndrew M. Kuchling        on Windows/Mac, and setup.cfg in the current directory.
281d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
2821426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        files = []
283acf3f6a7000eaed43f8c4e5df249967b06dfc474Greg Ward        check_environ()
284acf3f6a7000eaed43f8c4e5df249967b06dfc474Greg Ward
2851169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        # Where to look for the system-wide Distutils config file
2861169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        sys_dir = os.path.dirname(sys.modules['distutils'].__file__)
2871169687692e5e897033421fe6a73a3c32675a7d7Greg Ward
2881169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        # Look for the system config file
2891169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        sys_file = os.path.join(sys_dir, "distutils.cfg")
2901169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        if os.path.isfile(sys_file):
2911169687692e5e897033421fe6a73a3c32675a7d7Greg Ward            files.append(sys_file)
2921169687692e5e897033421fe6a73a3c32675a7d7Greg Ward
2931169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        # What to call the per-user config file
2941169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        if os.name == 'posix':
29565d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            user_filename = ".pydistutils.cfg"
29665d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton        else:
29765d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            user_filename = "pydistutils.cfg"
298fa9ff76aae32ecaae6b5409a410c10ff12116732Greg Ward
2991169687692e5e897033421fe6a73a3c32675a7d7Greg Ward        # And look for the user config file
30065d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton        if os.environ.has_key('HOME'):
30165d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            user_file = os.path.join(os.environ.get('HOME'), user_filename)
3021426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith            if os.path.isfile(user_file):
3031426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith                files.append(user_file)
3041426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3051426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        # All platforms support local setup.cfg
3061426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        local_file = "setup.cfg"
3071426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        if os.path.isfile(local_file):
3081426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith            files.append(local_file)
3091426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3101426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        return files
3111426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3121426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith    # find_config_files ()
3131426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3141426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3151426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith    def parse_config_files (self, filenames=None):
3161426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3171426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        from ConfigParser import ConfigParser
3181426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3191426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        if filenames is None:
3201426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith            filenames = self.find_config_files()
3211426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
3222bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward        if DEBUG: print "Distribution.parse_config_files():"
323474607777d10562679b1640d3831290b0c4284f7Greg Ward
3241426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        parser = ConfigParser()
325d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        for filename in filenames:
3262bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward            if DEBUG: print "  reading", filename
327d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            parser.read(filename)
328d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            for section in parser.sections():
329d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                options = parser.options(section)
3300e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward                opt_dict = self.get_option_dict(section)
331d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
332d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                for opt in options:
333d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                    if opt != '__name__':
334ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                        val = parser.get(section,opt)
335ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                        opt = string.replace(opt, '-', '_')
336ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                        opt_dict[opt] = (filename, val)
3371426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
338474607777d10562679b1640d3831290b0c4284f7Greg Ward            # Make the ConfigParser forget everything (so we retain
339474607777d10562679b1640d3831290b0c4284f7Greg Ward            # the original filenames that options come from) -- gag,
340474607777d10562679b1640d3831290b0c4284f7Greg Ward            # retch, puke -- another good reason for a distutils-
341474607777d10562679b1640d3831290b0c4284f7Greg Ward            # specific config parser (sigh...)
342474607777d10562679b1640d3831290b0c4284f7Greg Ward            parser.__init__()
3431426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
344ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward        # If there was a "global" section in the config file, use it
345ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward        # to set Distribution options.
346ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward
347ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward        if self.command_options.has_key('global'):
348ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward            for (opt, (src, val)) in self.command_options['global'].items():
349ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                alias = self.negative_opt.get(opt)
350ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                try:
351ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                    if alias:
352ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                        setattr(self, alias, not strtobool(val))
353ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                    elif opt in ('verbose', 'dry_run'): # ugh!
354ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                        setattr(self, opt, strtobool(val))
355ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                except ValueError, msg:
356ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                    raise DistutilsOptionError, msg
357ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward
358ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward    # parse_config_files ()
359ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward
3601426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
361d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    # -- Command-line parsing methods ----------------------------------
362fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
3639821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward    def parse_command_line (self):
3649821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        """Parse the setup script's command line, taken from the
3659821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        'script_args' instance attribute (which defaults to 'sys.argv[1:]'
3669821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        -- see 'setup()' in core.py).  This list is first processed for
3679821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        "global options" -- options that set attributes of the Distribution
3689821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        instance.  Then, it is alternately scanned for Distutils commands
3699821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        and options for that command.  Each new command terminates the
3709821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        options for the previous command.  The allowed options for a
3719821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        command are determined by the 'user_options' attribute of the
3729821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        command class -- thus, we have to be able to load command classes
3739821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        in order to parse the command line.  Any error in that 'options'
3749821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        attribute raises DistutilsGetoptError; any error on the
3759821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        command-line raises DistutilsArgError.  If no Distutils commands
3769821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        were found on the command line, raises DistutilsArgError.  Return
377ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward        true if command-line was successfully parsed and we should carry
3789821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        on with executing commands; false if no errors but we shouldn't
3799821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        execute commands (currently, this only happens if user asks for
3809821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        help).
381d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
3823f819ec2edc54c8ccf0e6edb836a908ff6e31904Andrew M. Kuchling        #
383981a1787b7de07033dff56bc8bf8af631a3b181dFred Drake        # We now have enough information to show the Macintosh dialog
384981a1787b7de07033dff56bc8bf8af631a3b181dFred Drake        # that allows the user to interactively specify the "command line".
3853f819ec2edc54c8ccf0e6edb836a908ff6e31904Andrew M. Kuchling        #
3863f819ec2edc54c8ccf0e6edb836a908ff6e31904Andrew M. Kuchling        if sys.platform == 'mac':
3873f819ec2edc54c8ccf0e6edb836a908ff6e31904Andrew M. Kuchling            import EasyDialogs
3883f819ec2edc54c8ccf0e6edb836a908ff6e31904Andrew M. Kuchling            cmdlist = self.get_command_list()
3893f819ec2edc54c8ccf0e6edb836a908ff6e31904Andrew M. Kuchling            self.script_args = EasyDialogs.GetArgv(
3903f819ec2edc54c8ccf0e6edb836a908ff6e31904Andrew M. Kuchling                self.global_options + self.display_options, cmdlist)
391b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake
392fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # We have to parse the command line a bit at a time -- global
393fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # options, then the first command, then its options, and so on --
394fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # because each command will be handled by a different class, and
395d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # the options that are valid for a particular class aren't known
396d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # until we have loaded the command class, which doesn't happen
397d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # until we know what the command is.
398fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
399fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.commands = []
400fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        parser = FancyGetopt(self.global_options + self.display_options)
401fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        parser.set_negative_aliases(self.negative_opt)
402fa7dc57d6c9023a5028aacb802438527ab2cfaceAndrew M. Kuchling        parser.set_aliases({'licence': 'license'})
403fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        args = parser.getopt(args=self.script_args, object=self)
40482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        option_order = parser.get_option_order()
405cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hylton        log.set_verbosity(self.verbose)
406fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
40782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # for display options we return immediately
40882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        if self.handle_display_options(option_order):
409fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            return
410b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake
411fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        while args:
412d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            args = self._parse_command_opts(parser, args)
413d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            if args is None:            # user asked for help (and got it)
414fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                return
415fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
416d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Handle the cases of --help as a "global" option, ie.
417d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # "setup.py --help" and "setup.py --help command ...".  For the
418d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # former, we show global options (--verbose, --dry-run, etc.)
419d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # and display-only options (--name, --version, etc.); for the
420d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # latter, we omit the display-only options and show help for
421d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # each command listed on the command line.
422d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if self.help:
423d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            self._show_help(parser,
424d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                            display_options=len(self.commands) == 0,
425d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                            commands=self.commands)
426fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            return
427fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
428fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Oops, no commands found -- an end-user error
429fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        if not self.commands:
430fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            raise DistutilsArgError, "no commands supplied"
431fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
432fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # All is well: return true
433fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return 1
434fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
435fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # parse_command_line()
436fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
437d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    def _parse_command_opts (self, parser, args):
438d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """Parse the command-line options for a single command.
439d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        'parser' must be a FancyGetopt instance; 'args' must be the list
440d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        of arguments, starting with the current command (whose options
441d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        we are about to parse).  Returns a new version of 'args' with
442d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        the next command at the front of the list; will be the empty
443d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        list if there are no more commands on the command line.  Returns
444d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        None if the user asked for help on this command.
445d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
446d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # late import because of mutual dependence between these modules
447d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        from distutils.cmd import Command
448d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
449d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Pull the current command from the head of the command line
450d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        command = args[0]
451fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        if not command_re.match(command):
452d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            raise SystemExit, "invalid command name '%s'" % command
453fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        self.commands.append(command)
454d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
455d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Dig up the command class that implements this command, so we
456d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # 1) know that it's a valid command, and 2) know which options
457d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # it takes.
458d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        try:
459fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            cmd_class = self.get_command_class(command)
460d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        except DistutilsModuleError, msg:
461d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            raise DistutilsArgError, msg
462d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
463d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Require that the command class be derived from Command -- want
464d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # to be sure that the basic "command" interface is implemented.
465fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        if not issubclass(cmd_class, Command):
466d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            raise DistutilsClassError, \
467d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                  "command class %s must subclass Command" % cmd_class
468d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
469d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Also make sure that the command object provides a list of its
470d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # known options.
471fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        if not (hasattr(cmd_class, 'user_options') and
472fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                type(cmd_class.user_options) is ListType):
473d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            raise DistutilsClassError, \
474d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                  ("command class %s must provide " +
475d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                   "'user_options' attribute (a list of tuples)") % \
476d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                  cmd_class
477d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
478d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # If the command class has a list of negative alias options,
479d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # merge it in with the global negative aliases.
480d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        negative_opt = self.negative_opt
481fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        if hasattr(cmd_class, 'negative_opt'):
482fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            negative_opt = copy(negative_opt)
483fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            negative_opt.update(cmd_class.negative_opt)
484d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
485fa9ff76aae32ecaae6b5409a410c10ff12116732Greg Ward        # Check for help_options in command class.  They have a different
486fa9ff76aae32ecaae6b5409a410c10ff12116732Greg Ward        # format (tuple of four) so we need to preprocess them here.
48765d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton        if (hasattr(cmd_class, 'help_options') and
488fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            type(cmd_class.help_options) is ListType):
4892ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward            help_options = fix_help_options(cmd_class.help_options)
4902ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward        else:
49155fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward            help_options = []
4922ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward
4939d17a7ad6df0a940f8f10cf7a113aaffc4222309Greg Ward
494d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # All commands support the global options too, just by adding
495d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # in 'global_options'.
496fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        parser.set_option_table(self.global_options +
497fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                                cmd_class.user_options +
498fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                                help_options)
499fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        parser.set_negative_aliases(negative_opt)
500fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        (args, opts) = parser.getopt(args[1:])
501474607777d10562679b1640d3831290b0c4284f7Greg Ward        if hasattr(opts, 'help') and opts.help:
502d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            self._show_help(parser, display_options=0, commands=[cmd_class])
503d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            return
504d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
50565d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton        if (hasattr(cmd_class, 'help_options') and
506fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            type(cmd_class.help_options) is ListType):
50765d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            help_option_found=0
50865d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            for (help_option, short, desc, func) in cmd_class.help_options:
50965d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton                if hasattr(opts, parser.get_attr_name(help_option)):
51065d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton                    help_option_found=1
511fa9ff76aae32ecaae6b5409a410c10ff12116732Greg Ward                    #print "showing help for option %s of command %s" % \
5122ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward                    #      (help_option[0],cmd_class)
51355fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward
51455fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward                    if callable(func):
51565d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton                        func()
51655fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward                    else:
517981a1787b7de07033dff56bc8bf8af631a3b181dFred Drake                        raise DistutilsClassError(
518981a1787b7de07033dff56bc8bf8af631a3b181dFred Drake                            "invalid help function %s for help option '%s': "
519981a1787b7de07033dff56bc8bf8af631a3b181dFred Drake                            "must be a callable object (function, etc.)"
520981a1787b7de07033dff56bc8bf8af631a3b181dFred Drake                            % (`func`, help_option))
52155fced3df9efac28e4ead6e3115a4e8658e28bf5Greg Ward
522b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake            if help_option_found:
52365d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton                return
5249d17a7ad6df0a940f8f10cf7a113aaffc4222309Greg Ward
525d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # Put the options from the command-line into their official
526d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # holding pen, the 'command_options' dictionary.
5270e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward        opt_dict = self.get_option_dict(command)
528d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        for (name, value) in vars(opts).items():
5290e48cfd2c5735a500d638aed929c3207173a4f9eGreg Ward            opt_dict[name] = ("command line", value)
530d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
531d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        return args
532d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
533d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    # _parse_command_opts ()
534d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
535d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
536a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling    def finalize_options (self):
537a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        """Set final values for all the options on the Distribution
538a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        instance, analogous to the .finalize_options() method of Command
539a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        objects.
540a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        """
541a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling
542a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        keywords = self.metadata.keywords
543a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        if keywords is not None:
544a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling            if type(keywords) is StringType:
545a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling                keywordlist = string.split(keywords, ',')
546a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling                self.metadata.keywords = map(string.strip, keywordlist)
547a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling
548a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        platforms = self.metadata.platforms
549a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        if platforms is not None:
550a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling            if type(platforms) is StringType:
551a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling                platformlist = string.split(platforms, ',')
552a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling                self.metadata.platforms = map(string.strip, platformlist)
553a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling
554d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    def _show_help (self,
555d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                    parser,
556d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                    global_options=1,
557d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                    display_options=1,
558d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                    commands=[]):
559d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """Show help for the setup script command-line in the form of
560d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        several lists of command-line options.  'parser' should be a
561d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        FancyGetopt instance; do not expect it to be returned in the
562d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        same state, as its option table will be reset to make it
563d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        generate the correct help text.
564d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
565d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        If 'global_options' is true, lists the global options:
566d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        --verbose, --dry-run, etc.  If 'display_options' is true, lists
567d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        the "display-only" options: --name, --version, etc.  Finally,
568d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        lists per-command help for every command name or command class
569d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        in 'commands'.
570d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
571d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        # late import because of mutual dependence between these modules
5729821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        from distutils.core import gen_usage
573d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        from distutils.cmd import Command
574d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
575d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if global_options:
576fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            parser.set_option_table(self.global_options)
577fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            parser.print_help("Global options:")
578d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            print
579d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
580d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if display_options:
581fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            parser.set_option_table(self.display_options)
582fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            parser.print_help(
583d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                "Information display options (just display " +
584d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                "information, ignore any commands)")
585d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            print
586d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
587d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        for command in self.commands:
588fa7dc57d6c9023a5028aacb802438527ab2cfaceAndrew M. Kuchling            if type(command) is ClassType and issubclass(command, Command):
589d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward                klass = command
590d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            else:
591fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                klass = self.get_command_class(command)
59265d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            if (hasattr(klass, 'help_options') and
593fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                type(klass.help_options) is ListType):
594fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                parser.set_option_table(klass.user_options +
595fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                                        fix_help_options(klass.help_options))
59665d6edb478d8c649766c59c5ae186bf0d1e812e6Jeremy Hylton            else:
597fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                parser.set_option_table(klass.user_options)
598fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            parser.print_help("Options for '%s' command:" % klass.__name__)
599d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            print
600d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
6019821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        print gen_usage(self.script_name)
602d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        return
603d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
604d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    # _show_help ()
605fa9ff76aae32ecaae6b5409a410c10ff12116732Greg Ward
606d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward
60782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def handle_display_options (self, option_order):
60882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        """If there were any non-global "display-only" options
609d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        (--help-commands or the metadata display options) on the command
610d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        line, display the requested info and return true; else return
611d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        false.
612d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
6139821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward        from distutils.core import gen_usage
61482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
61582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # User just wants a list of commands -- we'll print it out and stop
61682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # processing now (ie. if they ran "setup --help-commands foo bar",
61782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # we ignore "foo bar").
61882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        if self.help_commands:
619fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            self.print_commands()
62082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward            print
6219821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward            print gen_usage(self.script_name)
62282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward            return 1
62382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
62482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # If user supplied any of the "display metadata" options, then
62582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # display that metadata in the order in which the user supplied the
62682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        # metadata options.
62782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        any_display_options = 0
62882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        is_display_option = {}
62982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        for option in self.display_options:
63082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward            is_display_option[option[0]] = 1
63182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
63282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        for (opt, val) in option_order:
63382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward            if val and is_display_option.get(opt):
6342f2b6c62baf42e06c06f0dcae4879cf88dd6a916Greg Ward                opt = translate_longopt(opt)
635a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling                value = getattr(self.metadata, "get_"+opt)()
636a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling                if opt in ['keywords', 'platforms']:
637a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling                    print string.join(value, ',')
638a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling                else:
639a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling                    print value
64082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                any_display_options = 1
64182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
64282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return any_display_options
64382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
64482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # handle_display_options()
645fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
646fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def print_command_list (self, commands, header, max_length):
647fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        """Print a subset of the list of all commands -- used by
648d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        'print_commands()'.
649d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
650fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
651fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        print header + ":"
652fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
653fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        for cmd in commands:
654fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            klass = self.cmdclass.get(cmd)
655fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            if not klass:
656fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                klass = self.get_command_class(cmd)
657fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            try:
658fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                description = klass.description
659fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            except AttributeError:
660fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                description = "(no description available)"
661fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
662fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            print "  %-*s  %s" % (max_length, cmd, description)
663fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
664fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # print_command_list ()
665fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
666fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
667fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def print_commands (self):
668d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """Print out a help message listing all available commands with a
669d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        description of each.  The list is divided into "standard commands"
670d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        (listed in distutils.command.__all__) and "extra commands"
671d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        (mentioned in self.cmdclass, but not a standard command).  The
672d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        descriptions come from the command class attribute
673d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        'description'.
674d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
675fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
676fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        import distutils.command
677fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        std_commands = distutils.command.__all__
678fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        is_std = {}
679fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        for cmd in std_commands:
680fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            is_std[cmd] = 1
681fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
682fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        extra_commands = []
683fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        for cmd in self.cmdclass.keys():
684fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            if not is_std.get(cmd):
685fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                extra_commands.append(cmd)
686fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
687fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        max_length = 0
688fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        for cmd in (std_commands + extra_commands):
689fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            if len(cmd) > max_length:
690fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                max_length = len(cmd)
691fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
692fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        self.print_command_list(std_commands,
693fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                                "Standard commands",
694fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                                max_length)
695fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        if extra_commands:
696fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            print
697fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            self.print_command_list(extra_commands,
698fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                                    "Extra commands",
699fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward                                    max_length)
700fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
701fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # print_commands ()
702fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
703f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward    def get_command_list (self):
704f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        """Get a list of (command, description) tuples.
705f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        The list is divided into "standard commands" (listed in
706f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        distutils.command.__all__) and "extra commands" (mentioned in
707f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        self.cmdclass, but not a standard command).  The descriptions come
708f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        from the command class attribute 'description'.
709f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        """
710f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        # Currently this is only used on Mac OS, for the Mac-only GUI
711f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        # Distutils interface (by Jack Jansen)
712f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward
713f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        import distutils.command
714f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        std_commands = distutils.command.__all__
715f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        is_std = {}
716f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        for cmd in std_commands:
717f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward            is_std[cmd] = 1
718f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward
719f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        extra_commands = []
720f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        for cmd in self.cmdclass.keys():
721f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward            if not is_std.get(cmd):
722f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward                extra_commands.append(cmd)
723f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward
724f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        rv = []
725f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        for cmd in (std_commands + extra_commands):
726f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward            klass = self.cmdclass.get(cmd)
727f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward            if not klass:
728f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward                klass = self.get_command_class(cmd)
729f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward            try:
730f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward                description = klass.description
731f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward            except AttributeError:
732f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward                description = "(no description available)"
733f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward            rv.append((cmd, description))
734f6fc875831d0cfbf4077b4d2e1800365a78f7c2eGreg Ward        return rv
735fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
736fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # -- Command class/object methods ----------------------------------
737fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
738d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    def get_command_class (self, command):
739d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """Return the class that implements the Distutils command named by
740d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        'command'.  First we check the 'cmdclass' dictionary; if the
741d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        command is mentioned there, we fetch the class object from the
742d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        dictionary and return it.  Otherwise we load the command module
743d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        ("distutils.command." + command) and fetch the command class from
744d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        the module.  The loaded class is also stored in 'cmdclass'
745d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        to speed future calls to 'get_command_class()'.
7461426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith
7471426354cf649546a2437df75f2c319ff0b456c53Gregory P. Smith        Raises DistutilsModuleError if the expected module could not be
748d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        found, or if that module does not define the expected class.
749d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
750d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        klass = self.cmdclass.get(command)
751d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if klass:
752d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            return klass
753fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
754fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        module_name = 'distutils.command.' + command
755fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        klass_name = command
756fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
757fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        try:
758fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            __import__ (module_name)
759fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            module = sys.modules[module_name]
760fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        except ImportError:
761fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            raise DistutilsModuleError, \
762fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                  "invalid command '%s' (no module named '%s')" % \
763fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                  (command, module_name)
764fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
765fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        try:
766d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            klass = getattr(module, klass_name)
767d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        except AttributeError:
768fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            raise DistutilsModuleError, \
769fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                  "invalid command '%s' (no class '%s' in module '%s')" \
770fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                  % (command, klass_name, module_name)
771fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
772d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        self.cmdclass[command] = klass
773fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return klass
774fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
775d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    # get_command_class ()
776fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
777d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward    def get_command_obj (self, command, create=1):
778d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """Return the command object for 'command'.  Normally this object
779612eb9f58fe38f33484f36bcba97a4b3d8e090a9Greg Ward        is cached on a previous call to 'get_command_obj()'; if no command
780d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        object for 'command' is in the cache, then we either create and
781d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        return it (if 'create' is true) or return None.
782d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
783d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        cmd_obj = self.command_obj.get(command)
784fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        if not cmd_obj and create:
7852bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward            if DEBUG:
7862bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward                print "Distribution.get_command_obj(): " \
7872bd3f4250d59cabc0dda29fc3289beda315ce06aGreg Ward                      "creating '%s' command object" % command
788474607777d10562679b1640d3831290b0c4284f7Greg Ward
789d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward            klass = self.get_command_class(command)
790474607777d10562679b1640d3831290b0c4284f7Greg Ward            cmd_obj = self.command_obj[command] = klass(self)
791474607777d10562679b1640d3831290b0c4284f7Greg Ward            self.have_run[command] = 0
792474607777d10562679b1640d3831290b0c4284f7Greg Ward
793474607777d10562679b1640d3831290b0c4284f7Greg Ward            # Set any options that were supplied in config files
794474607777d10562679b1640d3831290b0c4284f7Greg Ward            # or on the command line.  (NB. support for error
795474607777d10562679b1640d3831290b0c4284f7Greg Ward            # reporting is lame here: any errors aren't reported
796474607777d10562679b1640d3831290b0c4284f7Greg Ward            # until 'finalize_options()' is called, which means
797474607777d10562679b1640d3831290b0c4284f7Greg Ward            # we won't report the source of the error.)
798474607777d10562679b1640d3831290b0c4284f7Greg Ward            options = self.command_options.get(command)
799474607777d10562679b1640d3831290b0c4284f7Greg Ward            if options:
800c32d9a69527af6d2823650ea7674e207c975f090Greg Ward                self._set_command_options(cmd_obj, options)
801fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
802fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return cmd_obj
803fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
804c32d9a69527af6d2823650ea7674e207c975f090Greg Ward    def _set_command_options (self, command_obj, option_dict=None):
805c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        """Set the options for 'command_obj' from 'option_dict'.  Basically
806c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        this means copying elements of a dictionary ('option_dict') to
807c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        attributes of an instance ('command').
808c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
809ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward        'command_obj' must be a Command instance.  If 'option_dict' is not
810c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        supplied, uses the standard option dictionary for this command
811c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        (from 'self.command_options').
812c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        """
813c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        command_name = command_obj.get_command_name()
814c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if option_dict is None:
815c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            option_dict = self.get_option_dict(command_name)
816c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
817c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if DEBUG: print "  setting options for '%s' command:" % command_name
818c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        for (option, (source, value)) in option_dict.items():
819c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            if DEBUG: print "    %s = %s (from %s)" % (option, value, source)
820ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward            try:
8212f2b6c62baf42e06c06f0dcae4879cf88dd6a916Greg Ward                bool_opts = map(translate_longopt, command_obj.boolean_options)
822ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward            except AttributeError:
823ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                bool_opts = []
824ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward            try:
825ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                neg_opt = command_obj.negative_opt
826ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward            except AttributeError:
827ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                neg_opt = {}
828ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward
829ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward            try:
8302c08cf0ffacdd450e24eeca1f58dfca571538449Greg Ward                is_string = type(value) is StringType
8312c08cf0ffacdd450e24eeca1f58dfca571538449Greg Ward                if neg_opt.has_key(option) and is_string:
832ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                    setattr(command_obj, neg_opt[option], not strtobool(value))
8332c08cf0ffacdd450e24eeca1f58dfca571538449Greg Ward                elif option in bool_opts and is_string:
834ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                    setattr(command_obj, option, strtobool(value))
835ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                elif hasattr(command_obj, option):
836ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                    setattr(command_obj, option, value)
837ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                else:
838ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                    raise DistutilsOptionError, \
839ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                          ("error in %s: command '%s' has no such option '%s'"
840ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                           % (source, command_name, option))
841ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward            except ValueError, msg:
842ceb9e226a638301e68420d7b6728bdc86fd30f0cGreg Ward                raise DistutilsOptionError, msg
843c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
844f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward    def reinitialize_command (self, command, reinit_subcommands=0):
845c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        """Reinitializes a command to the state it was in when first
846c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        returned by 'get_command_obj()': ie., initialized but not yet
8477d9c705b234ad2ad013db1649e5fd2ffc2a59a75Greg Ward        finalized.  This provides the opportunity to sneak option
848c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        values in programmatically, overriding or supplementing
849c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        user-supplied values from the config files and command line.
850c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        You'll have to re-finalize the command object (by calling
851c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        'finalize_options()' or 'ensure_finalized()') before using it for
852b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake        real.
853c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
854f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        'command' should be a command name (string) or command object.  If
855f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        'reinit_subcommands' is true, also reinitializes the command's
856f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        sub-commands, as declared by the 'sub_commands' class attribute (if
857f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        it has one).  See the "install" command for an example.  Only
858f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        reinitializes the sub-commands that actually matter, ie. those
859f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        whose test predicates return true.
860f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward
861c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        Returns the reinitialized command object.
862c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        """
863c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        from distutils.cmd import Command
864c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if not isinstance(command, Command):
865c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            command_name = command
866c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            command = self.get_command_obj(command_name)
867c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        else:
868c32d9a69527af6d2823650ea7674e207c975f090Greg Ward            command_name = command.get_command_name()
869c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
870c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        if not command.finalized:
871282c7a0230b578147a89a18ec22410b830edddfeGreg Ward            return command
872c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        command.initialize_options()
873c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        command.finalized = 0
87443955c9a023ea7b50b28052112dbdc914c090a27Greg Ward        self.have_run[command_name] = 0
875c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        self._set_command_options(command)
876f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward
877f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward        if reinit_subcommands:
878f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward            for sub in command.get_sub_commands():
879b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake                self.reinitialize_command(sub, reinit_subcommands)
880f449ea51aa9b72bf8d8ea7a19e87c5a169fc9605Greg Ward
881c32d9a69527af6d2823650ea7674e207c975f090Greg Ward        return command
882c32d9a69527af6d2823650ea7674e207c975f090Greg Ward
883b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake
884fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # -- Methods that operate on the Distribution ----------------------
885fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
886fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def announce (self, msg, level=1):
887cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hylton        log.debug(msg)
888fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
889fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def run_commands (self):
89082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        """Run each command that was seen on the setup script command line.
891d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        Uses the list of commands found and cache of command objects
892fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        created by 'get_command_obj()'.
893fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        """
894fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        for cmd in self.commands:
895fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward            self.run_command(cmd)
896fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
897fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
898fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # -- Methods that operate on its Commands --------------------------
899fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
900fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def run_command (self, command):
901fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        """Do whatever it takes to run a command (including nothing at all,
902d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        if the command has already been run).  Specifically: if we have
903d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        already created and run the command named by 'command', return
904d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        silently without doing anything.  If the command named by 'command'
905d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        doesn't even have a command object yet, create one.  Then invoke
906d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        'run()' on that command object (or an existing one).
907d5d8a9982b77ef54fcacf8ff7bfa449a2eab35dbGreg Ward        """
908fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        # Already been here, done that? then return silently.
909fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        if self.have_run.get(command):
910fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward            return
911fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
912cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hylton        log.info("running %s", command)
913fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        cmd_obj = self.get_command_obj(command)
914fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        cmd_obj.ensure_finalized()
915fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        cmd_obj.run()
916fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        self.have_run[command] = 1
917fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
918fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
919fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    # -- Distribution query methods ------------------------------------
920fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
921fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def has_pure_modules (self):
922fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        return len(self.packages or self.py_modules or []) > 0
923fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
924fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def has_ext_modules (self):
925fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        return self.ext_modules and len(self.ext_modules) > 0
926fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
927fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def has_c_libraries (self):
928fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward        return self.libraries and len(self.libraries) > 0
929fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
930fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def has_modules (self):
931fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return self.has_pure_modules() or self.has_ext_modules()
932fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
93351def7d667a42eac177690e1fe00eab7f2102319Greg Ward    def has_headers (self):
93451def7d667a42eac177690e1fe00eab7f2102319Greg Ward        return self.headers and len(self.headers) > 0
93551def7d667a42eac177690e1fe00eab7f2102319Greg Ward
93644a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward    def has_scripts (self):
93744a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward        return self.scripts and len(self.scripts) > 0
93844a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward
93944a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward    def has_data_files (self):
94044a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward        return self.data_files and len(self.data_files) > 0
94144a61bbb66cfc6a0821d591ccf33fbc209aab112Greg Ward
942fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def is_pure (self):
943fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return (self.has_pure_modules() and
944fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                not self.has_ext_modules() and
945fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward                not self.has_c_libraries())
946fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
94782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # -- Metadata query methods ----------------------------------------
94882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
94982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # If you're looking for 'get_name()', 'get_version()', and so forth,
95082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # they are defined in a sneaky way: the constructor binds self.get_XXX
95182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # to self.metadata.get_XXX.  The actual code is in the
95282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # DistributionMetadata class, below.
95382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
95482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward# class Distribution
95582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
95682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
95782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Wardclass DistributionMetadata:
95882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    """Dummy class to hold the distribution meta-data: name, version,
959fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward    author, and so forth.
960fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward    """
96182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
962a8aefe535c879c8b0f5201961648a89c8e3d7887Neil Schemenauer    _METHOD_BASENAMES = ("name", "version", "author", "author_email",
963a8aefe535c879c8b0f5201961648a89c8e3d7887Neil Schemenauer                         "maintainer", "maintainer_email", "url",
964a8aefe535c879c8b0f5201961648a89c8e3d7887Neil Schemenauer                         "license", "description", "long_description",
965a8aefe535c879c8b0f5201961648a89c8e3d7887Neil Schemenauer                         "keywords", "platforms", "fullname", "contact",
966a8aefe535c879c8b0f5201961648a89c8e3d7887Neil Schemenauer                         "contact_email", "licence")
967a8aefe535c879c8b0f5201961648a89c8e3d7887Neil Schemenauer
96882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def __init__ (self):
96982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.name = None
97082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.version = None
97182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.author = None
97282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.author_email = None
97382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.maintainer = None
97482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.maintainer_email = None
97582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.url = None
976fa7dc57d6c9023a5028aacb802438527ab2cfaceAndrew M. Kuchling        self.license = None
97782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        self.description = None
978e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward        self.long_description = None
979a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        self.keywords = None
980a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        self.platforms = None
981b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake
982a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling    def write_pkg_info (self, base_dir):
983a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        """Write the PKG-INFO file into the release tree.
984a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        """
985a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling
986a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        pkg_info = open( os.path.join(base_dir, 'PKG-INFO'), 'w')
987a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling
988a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        pkg_info.write('Metadata-Version: 1.0\n')
989a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        pkg_info.write('Name: %s\n' % self.get_name() )
990a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        pkg_info.write('Version: %s\n' % self.get_version() )
991a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        pkg_info.write('Summary: %s\n' % self.get_description() )
992a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        pkg_info.write('Home-page: %s\n' % self.get_url() )
993ffb963c7f699c9b6ab0debc1825a55ec8f98556fAndrew M. Kuchling        pkg_info.write('Author: %s\n' % self.get_contact() )
994ffb963c7f699c9b6ab0debc1825a55ec8f98556fAndrew M. Kuchling        pkg_info.write('Author-email: %s\n' % self.get_contact_email() )
995fa7dc57d6c9023a5028aacb802438527ab2cfaceAndrew M. Kuchling        pkg_info.write('License: %s\n' % self.get_license() )
996a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling
997a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        long_desc = rfc822_escape( self.get_long_description() )
998a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        pkg_info.write('Description: %s\n' % long_desc)
999a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling
1000a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        keywords = string.join( self.get_keywords(), ',')
1001a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        if keywords:
1002a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling            pkg_info.write('Keywords: %s\n' % keywords )
1003a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling
1004a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        for platform in self.get_platforms():
1005a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling            pkg_info.write('Platform: %s\n' % platform )
1006a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling
1007a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        pkg_info.close()
1008b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake
1009a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling    # write_pkg_info ()
1010b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake
101182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    # -- Metadata query methods ----------------------------------------
101282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
1013fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    def get_name (self):
1014fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward        return self.name or "UNKNOWN"
1015fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
101682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_version(self):
1017bcd8975740da47e7d1c8a5d2839ad4bf214fe34bThomas Heller        return self.version or "0.0.0"
101882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
101982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_fullname (self):
102082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return "%s-%s" % (self.get_name(), self.get_version())
102182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
102282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_author(self):
102382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.author or "UNKNOWN"
1024fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
102582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_author_email(self):
102682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.author_email or "UNKNOWN"
102782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
102882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_maintainer(self):
102982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.maintainer or "UNKNOWN"
103082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
103182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_maintainer_email(self):
103282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.maintainer_email or "UNKNOWN"
103382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
103482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_contact(self):
103582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return (self.maintainer or
103682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                self.author or
103782715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                "UNKNOWN")
103882715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
103982715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_contact_email(self):
104082715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return (self.maintainer_email or
104182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                self.author_email or
104282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward                "UNKNOWN")
104382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
104482715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_url(self):
104582715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.url or "UNKNOWN"
104682715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward
1047fa7dc57d6c9023a5028aacb802438527ab2cfaceAndrew M. Kuchling    def get_license(self):
1048fa7dc57d6c9023a5028aacb802438527ab2cfaceAndrew M. Kuchling        return self.license or "UNKNOWN"
1049fa7dc57d6c9023a5028aacb802438527ab2cfaceAndrew M. Kuchling    get_licence = get_license
1050b94b849d65af71b4b432a74fdaef8ccd88209cc0Fred Drake
105182715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward    def get_description(self):
105282715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward        return self.description or "UNKNOWN"
1053e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward
1054e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward    def get_long_description(self):
1055e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward        return self.long_description or "UNKNOWN"
1056e5a584e86572a1ae85d99bc2a77b439d7024934fGreg Ward
1057a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling    def get_keywords(self):
1058a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        return self.keywords or []
1059a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling
1060a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling    def get_platforms(self):
1061a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling        return self.platforms or ["UNKNOWN"]
1062a7210ed2728faefdcc440fb359ff1a1abdca998eAndrew M. Kuchling
106382715e1f11ec1f4c7b13b07ca55f56850c4c3dabGreg Ward# class DistributionMetadata
1064fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward
10652ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward
10662ff7887270385bd6dddc2d5461486334b4fec8bcGreg Warddef fix_help_options (options):
10672ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    """Convert a 4-tuple 'help_options' list as found in various command
10682ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    classes to the 3-tuple form required by FancyGetopt.
10692ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    """
10702ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    new_options = []
10712ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    for help_tuple in options:
10722ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward        new_options.append(help_tuple[0:3])
10732ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward    return new_options
10742ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward
10752ff7887270385bd6dddc2d5461486334b4fec8bcGreg Ward
1076fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Wardif __name__ == "__main__":
1077fd7b91eff98d4e5fafbe50be0c875d1644bcfa6fGreg Ward    dist = Distribution()
1078fe6462c1f3206dd69659d20b5babab515fc6d4c3Greg Ward    print "ok"
1079