1"""distutils.dist
2
3Provides the Distribution class, which represents the module distribution
4being built/installed/distributed.
5"""
6
7__revision__ = "$Id$"
8
9import sys, os, re
10from email import message_from_file
11
12try:
13    import warnings
14except ImportError:
15    warnings = None
16
17from distutils.errors import (DistutilsOptionError, DistutilsArgError,
18                              DistutilsModuleError, DistutilsClassError)
19from distutils.fancy_getopt import FancyGetopt, translate_longopt
20from distutils.util import check_environ, strtobool, rfc822_escape
21from distutils import log
22from distutils.debug import DEBUG
23
24# Encoding used for the PKG-INFO files
25PKG_INFO_ENCODING = 'utf-8'
26
27# Regex to define acceptable Distutils command names.  This is not *quite*
28# the same as a Python NAME -- I don't allow leading underscores.  The fact
29# that they're very similar is no coincidence; the default naming scheme is
30# to look for a Python module named after the command.
31command_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$')
32
33
34class Distribution:
35    """The core of the Distutils.  Most of the work hiding behind 'setup'
36    is really done within a Distribution instance, which farms the work out
37    to the Distutils commands specified on the command line.
38
39    Setup scripts will almost never instantiate Distribution directly,
40    unless the 'setup()' function is totally inadequate to their needs.
41    However, it is conceivable that a setup script might wish to subclass
42    Distribution for some specialized purpose, and then pass the subclass
43    to 'setup()' as the 'distclass' keyword argument.  If so, it is
44    necessary to respect the expectations that 'setup' has of Distribution.
45    See the code for 'setup()', in core.py, for details.
46    """
47
48
49    # 'global_options' describes the command-line options that may be
50    # supplied to the setup script prior to any actual commands.
51    # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of
52    # these global options.  This list should be kept to a bare minimum,
53    # since every global option is also valid as a command option -- and we
54    # don't want to pollute the commands with too many options that they
55    # have minimal control over.
56    # The fourth entry for verbose means that it can be repeated.
57    global_options = [('verbose', 'v', "run verbosely (default)", 1),
58                      ('quiet', 'q', "run quietly (turns verbosity off)"),
59                      ('dry-run', 'n', "don't actually do anything"),
60                      ('help', 'h', "show detailed help message"),
61                      ('no-user-cfg', None,
62                       'ignore pydistutils.cfg in your home directory'),
63    ]
64
65    # 'common_usage' is a short (2-3 line) string describing the common
66    # usage of the setup script.
67    common_usage = """\
68Common commands: (see '--help-commands' for more)
69
70  setup.py build      will build the package underneath 'build/'
71  setup.py install    will install the package
72"""
73
74    # options that are not propagated to the commands
75    display_options = [
76        ('help-commands', None,
77         "list all available commands"),
78        ('name', None,
79         "print package name"),
80        ('version', 'V',
81         "print package version"),
82        ('fullname', None,
83         "print <package name>-<version>"),
84        ('author', None,
85         "print the author's name"),
86        ('author-email', None,
87         "print the author's email address"),
88        ('maintainer', None,
89         "print the maintainer's name"),
90        ('maintainer-email', None,
91         "print the maintainer's email address"),
92        ('contact', None,
93         "print the maintainer's name if known, else the author's"),
94        ('contact-email', None,
95         "print the maintainer's email address if known, else the author's"),
96        ('url', None,
97         "print the URL for this package"),
98        ('license', None,
99         "print the license of the package"),
100        ('licence', None,
101         "alias for --license"),
102        ('description', None,
103         "print the package description"),
104        ('long-description', None,
105         "print the long package description"),
106        ('platforms', None,
107         "print the list of platforms"),
108        ('classifiers', None,
109         "print the list of classifiers"),
110        ('keywords', None,
111         "print the list of keywords"),
112        ('provides', None,
113         "print the list of packages/modules provided"),
114        ('requires', None,
115         "print the list of packages/modules required"),
116        ('obsoletes', None,
117         "print the list of packages/modules made obsolete")
118        ]
119    display_option_names = map(lambda x: translate_longopt(x[0]),
120                               display_options)
121
122    # negative options are options that exclude other options
123    negative_opt = {'quiet': 'verbose'}
124
125
126    # -- Creation/initialization methods -------------------------------
127
128    def __init__ (self, attrs=None):
129        """Construct a new Distribution instance: initialize all the
130        attributes of a Distribution, and then use 'attrs' (a dictionary
131        mapping attribute names to values) to assign some of those
132        attributes their "real" values.  (Any attributes not mentioned in
133        'attrs' will be assigned to some null value: 0, None, an empty list
134        or dictionary, etc.)  Most importantly, initialize the
135        'command_obj' attribute to the empty dictionary; this will be
136        filled in with real command objects by 'parse_command_line()'.
137        """
138
139        # Default values for our command-line options
140        self.verbose = 1
141        self.dry_run = 0
142        self.help = 0
143        for attr in self.display_option_names:
144            setattr(self, attr, 0)
145
146        # Store the distribution meta-data (name, version, author, and so
147        # forth) in a separate object -- we're getting to have enough
148        # information here (and enough command-line options) that it's
149        # worth it.  Also delegate 'get_XXX()' methods to the 'metadata'
150        # object in a sneaky and underhanded (but efficient!) way.
151        self.metadata = DistributionMetadata()
152        for basename in self.metadata._METHOD_BASENAMES:
153            method_name = "get_" + basename
154            setattr(self, method_name, getattr(self.metadata, method_name))
155
156        # 'cmdclass' maps command names to class objects, so we
157        # can 1) quickly figure out which class to instantiate when
158        # we need to create a new command object, and 2) have a way
159        # for the setup script to override command classes
160        self.cmdclass = {}
161
162        # 'command_packages' is a list of packages in which commands
163        # are searched for.  The factory for command 'foo' is expected
164        # to be named 'foo' in the module 'foo' in one of the packages
165        # named here.  This list is searched from the left; an error
166        # is raised if no named package provides the command being
167        # searched for.  (Always access using get_command_packages().)
168        self.command_packages = None
169
170        # 'script_name' and 'script_args' are usually set to sys.argv[0]
171        # and sys.argv[1:], but they can be overridden when the caller is
172        # not necessarily a setup script run from the command-line.
173        self.script_name = None
174        self.script_args = None
175
176        # 'command_options' is where we store command options between
177        # parsing them (from config files, the command-line, etc.) and when
178        # they are actually needed -- ie. when the command in question is
179        # instantiated.  It is a dictionary of dictionaries of 2-tuples:
180        #   command_options = { command_name : { option : (source, value) } }
181        self.command_options = {}
182
183        # 'dist_files' is the list of (command, pyversion, file) that
184        # have been created by any dist commands run so far. This is
185        # filled regardless of whether the run is dry or not. pyversion
186        # gives sysconfig.get_python_version() if the dist file is
187        # specific to a Python version, 'any' if it is good for all
188        # Python versions on the target platform, and '' for a source
189        # file. pyversion should not be used to specify minimum or
190        # maximum required Python versions; use the metainfo for that
191        # instead.
192        self.dist_files = []
193
194        # These options are really the business of various commands, rather
195        # than of the Distribution itself.  We provide aliases for them in
196        # Distribution as a convenience to the developer.
197        self.packages = None
198        self.package_data = {}
199        self.package_dir = None
200        self.py_modules = None
201        self.libraries = None
202        self.headers = None
203        self.ext_modules = None
204        self.ext_package = None
205        self.include_dirs = None
206        self.extra_path = None
207        self.scripts = None
208        self.data_files = None
209        self.password = ''
210
211        # And now initialize bookkeeping stuff that can't be supplied by
212        # the caller at all.  'command_obj' maps command names to
213        # Command instances -- that's how we enforce that every command
214        # class is a singleton.
215        self.command_obj = {}
216
217        # 'have_run' maps command names to boolean values; it keeps track
218        # of whether we have actually run a particular command, to make it
219        # cheap to "run" a command whenever we think we might need to -- if
220        # it's already been done, no need for expensive filesystem
221        # operations, we just check the 'have_run' dictionary and carry on.
222        # It's only safe to query 'have_run' for a command class that has
223        # been instantiated -- a false value will be inserted when the
224        # command object is created, and replaced with a true value when
225        # the command is successfully run.  Thus it's probably best to use
226        # '.get()' rather than a straight lookup.
227        self.have_run = {}
228
229        # Now we'll use the attrs dictionary (ultimately, keyword args from
230        # the setup script) to possibly override any or all of these
231        # distribution options.
232
233        if attrs:
234            # Pull out the set of command options and work on them
235            # specifically.  Note that this order guarantees that aliased
236            # command options will override any supplied redundantly
237            # through the general options dictionary.
238            options = attrs.get('options')
239            if options is not None:
240                del attrs['options']
241                for (command, cmd_options) in options.items():
242                    opt_dict = self.get_option_dict(command)
243                    for (opt, val) in cmd_options.items():
244                        opt_dict[opt] = ("setup script", val)
245
246            if 'licence' in attrs:
247                attrs['license'] = attrs['licence']
248                del attrs['licence']
249                msg = "'licence' distribution option is deprecated; use 'license'"
250                if warnings is not None:
251                    warnings.warn(msg)
252                else:
253                    sys.stderr.write(msg + "\n")
254
255            # Now work on the rest of the attributes.  Any attribute that's
256            # not already defined is invalid!
257            for (key, val) in attrs.items():
258                if hasattr(self.metadata, "set_" + key):
259                    getattr(self.metadata, "set_" + key)(val)
260                elif hasattr(self.metadata, key):
261                    setattr(self.metadata, key, val)
262                elif hasattr(self, key):
263                    setattr(self, key, val)
264                else:
265                    msg = "Unknown distribution option: %s" % repr(key)
266                    if warnings is not None:
267                        warnings.warn(msg)
268                    else:
269                        sys.stderr.write(msg + "\n")
270
271        # no-user-cfg is handled before other command line args
272        # because other args override the config files, and this
273        # one is needed before we can load the config files.
274        # If attrs['script_args'] wasn't passed, assume false.
275        #
276        # This also make sure we just look at the global options
277        self.want_user_cfg = True
278
279        if self.script_args is not None:
280            for arg in self.script_args:
281                if not arg.startswith('-'):
282                    break
283                if arg == '--no-user-cfg':
284                    self.want_user_cfg = False
285                    break
286
287        self.finalize_options()
288
289    def get_option_dict(self, command):
290        """Get the option dictionary for a given command.  If that
291        command's option dictionary hasn't been created yet, then create it
292        and return the new dictionary; otherwise, return the existing
293        option dictionary.
294        """
295        dict = self.command_options.get(command)
296        if dict is None:
297            dict = self.command_options[command] = {}
298        return dict
299
300    def dump_option_dicts(self, header=None, commands=None, indent=""):
301        from pprint import pformat
302
303        if commands is None:             # dump all command option dicts
304            commands = self.command_options.keys()
305            commands.sort()
306
307        if header is not None:
308            self.announce(indent + header)
309            indent = indent + "  "
310
311        if not commands:
312            self.announce(indent + "no commands known yet")
313            return
314
315        for cmd_name in commands:
316            opt_dict = self.command_options.get(cmd_name)
317            if opt_dict is None:
318                self.announce(indent +
319                              "no option dict for '%s' command" % cmd_name)
320            else:
321                self.announce(indent +
322                              "option dict for '%s' command:" % cmd_name)
323                out = pformat(opt_dict)
324                for line in out.split('\n'):
325                    self.announce(indent + "  " + line)
326
327    # -- Config file finding/parsing methods ---------------------------
328
329    def find_config_files(self):
330        """Find as many configuration files as should be processed for this
331        platform, and return a list of filenames in the order in which they
332        should be parsed.  The filenames returned are guaranteed to exist
333        (modulo nasty race conditions).
334
335        There are three possible config files: distutils.cfg in the
336        Distutils installation directory (ie. where the top-level
337        Distutils __inst__.py file lives), a file in the user's home
338        directory named .pydistutils.cfg on Unix and pydistutils.cfg
339        on Windows/Mac; and setup.cfg in the current directory.
340
341        The file in the user's home directory can be disabled with the
342        --no-user-cfg option.
343        """
344        files = []
345        check_environ()
346
347        # Where to look for the system-wide Distutils config file
348        sys_dir = os.path.dirname(sys.modules['distutils'].__file__)
349
350        # Look for the system config file
351        sys_file = os.path.join(sys_dir, "distutils.cfg")
352        if os.path.isfile(sys_file):
353            files.append(sys_file)
354
355        # What to call the per-user config file
356        if os.name == 'posix':
357            user_filename = ".pydistutils.cfg"
358        else:
359            user_filename = "pydistutils.cfg"
360
361        # And look for the user config file
362        if self.want_user_cfg:
363            user_file = os.path.join(os.path.expanduser('~'), user_filename)
364            if os.path.isfile(user_file):
365                files.append(user_file)
366
367        # All platforms support local setup.cfg
368        local_file = "setup.cfg"
369        if os.path.isfile(local_file):
370            files.append(local_file)
371
372        if DEBUG:
373            self.announce("using config files: %s" % ', '.join(files))
374
375        return files
376
377    def parse_config_files(self, filenames=None):
378        from ConfigParser import ConfigParser
379
380        if filenames is None:
381            filenames = self.find_config_files()
382
383        if DEBUG:
384            self.announce("Distribution.parse_config_files():")
385
386        parser = ConfigParser()
387        for filename in filenames:
388            if DEBUG:
389                self.announce("  reading %s" % filename)
390            parser.read(filename)
391            for section in parser.sections():
392                options = parser.options(section)
393                opt_dict = self.get_option_dict(section)
394
395                for opt in options:
396                    if opt != '__name__':
397                        val = parser.get(section,opt)
398                        opt = opt.replace('-', '_')
399                        opt_dict[opt] = (filename, val)
400
401            # Make the ConfigParser forget everything (so we retain
402            # the original filenames that options come from)
403            parser.__init__()
404
405        # If there was a "global" section in the config file, use it
406        # to set Distribution options.
407
408        if 'global' in self.command_options:
409            for (opt, (src, val)) in self.command_options['global'].items():
410                alias = self.negative_opt.get(opt)
411                try:
412                    if alias:
413                        setattr(self, alias, not strtobool(val))
414                    elif opt in ('verbose', 'dry_run'): # ugh!
415                        setattr(self, opt, strtobool(val))
416                    else:
417                        setattr(self, opt, val)
418                except ValueError, msg:
419                    raise DistutilsOptionError, msg
420
421    # -- Command-line parsing methods ----------------------------------
422
423    def parse_command_line(self):
424        """Parse the setup script's command line, taken from the
425        'script_args' instance attribute (which defaults to 'sys.argv[1:]'
426        -- see 'setup()' in core.py).  This list is first processed for
427        "global options" -- options that set attributes of the Distribution
428        instance.  Then, it is alternately scanned for Distutils commands
429        and options for that command.  Each new command terminates the
430        options for the previous command.  The allowed options for a
431        command are determined by the 'user_options' attribute of the
432        command class -- thus, we have to be able to load command classes
433        in order to parse the command line.  Any error in that 'options'
434        attribute raises DistutilsGetoptError; any error on the
435        command-line raises DistutilsArgError.  If no Distutils commands
436        were found on the command line, raises DistutilsArgError.  Return
437        true if command-line was successfully parsed and we should carry
438        on with executing commands; false if no errors but we shouldn't
439        execute commands (currently, this only happens if user asks for
440        help).
441        """
442        #
443        # We now have enough information to show the Macintosh dialog
444        # that allows the user to interactively specify the "command line".
445        #
446        toplevel_options = self._get_toplevel_options()
447
448        # We have to parse the command line a bit at a time -- global
449        # options, then the first command, then its options, and so on --
450        # because each command will be handled by a different class, and
451        # the options that are valid for a particular class aren't known
452        # until we have loaded the command class, which doesn't happen
453        # until we know what the command is.
454
455        self.commands = []
456        parser = FancyGetopt(toplevel_options + self.display_options)
457        parser.set_negative_aliases(self.negative_opt)
458        parser.set_aliases({'licence': 'license'})
459        args = parser.getopt(args=self.script_args, object=self)
460        option_order = parser.get_option_order()
461        log.set_verbosity(self.verbose)
462
463        # for display options we return immediately
464        if self.handle_display_options(option_order):
465            return
466        while args:
467            args = self._parse_command_opts(parser, args)
468            if args is None:            # user asked for help (and got it)
469                return
470
471        # Handle the cases of --help as a "global" option, ie.
472        # "setup.py --help" and "setup.py --help command ...".  For the
473        # former, we show global options (--verbose, --dry-run, etc.)
474        # and display-only options (--name, --version, etc.); for the
475        # latter, we omit the display-only options and show help for
476        # each command listed on the command line.
477        if self.help:
478            self._show_help(parser,
479                            display_options=len(self.commands) == 0,
480                            commands=self.commands)
481            return
482
483        # Oops, no commands found -- an end-user error
484        if not self.commands:
485            raise DistutilsArgError, "no commands supplied"
486
487        # All is well: return true
488        return 1
489
490    def _get_toplevel_options(self):
491        """Return the non-display options recognized at the top level.
492
493        This includes options that are recognized *only* at the top
494        level as well as options recognized for commands.
495        """
496        return self.global_options + [
497            ("command-packages=", None,
498             "list of packages that provide distutils commands"),
499            ]
500
501    def _parse_command_opts(self, parser, args):
502        """Parse the command-line options for a single command.
503        'parser' must be a FancyGetopt instance; 'args' must be the list
504        of arguments, starting with the current command (whose options
505        we are about to parse).  Returns a new version of 'args' with
506        the next command at the front of the list; will be the empty
507        list if there are no more commands on the command line.  Returns
508        None if the user asked for help on this command.
509        """
510        # late import because of mutual dependence between these modules
511        from distutils.cmd import Command
512
513        # Pull the current command from the head of the command line
514        command = args[0]
515        if not command_re.match(command):
516            raise SystemExit, "invalid command name '%s'" % command
517        self.commands.append(command)
518
519        # Dig up the command class that implements this command, so we
520        # 1) know that it's a valid command, and 2) know which options
521        # it takes.
522        try:
523            cmd_class = self.get_command_class(command)
524        except DistutilsModuleError, msg:
525            raise DistutilsArgError, msg
526
527        # Require that the command class be derived from Command -- want
528        # to be sure that the basic "command" interface is implemented.
529        if not issubclass(cmd_class, Command):
530            raise DistutilsClassError, \
531                  "command class %s must subclass Command" % cmd_class
532
533        # Also make sure that the command object provides a list of its
534        # known options.
535        if not (hasattr(cmd_class, 'user_options') and
536                isinstance(cmd_class.user_options, list)):
537            raise DistutilsClassError, \
538                  ("command class %s must provide " +
539                   "'user_options' attribute (a list of tuples)") % \
540                  cmd_class
541
542        # If the command class has a list of negative alias options,
543        # merge it in with the global negative aliases.
544        negative_opt = self.negative_opt
545        if hasattr(cmd_class, 'negative_opt'):
546            negative_opt = negative_opt.copy()
547            negative_opt.update(cmd_class.negative_opt)
548
549        # Check for help_options in command class.  They have a different
550        # format (tuple of four) so we need to preprocess them here.
551        if (hasattr(cmd_class, 'help_options') and
552            isinstance(cmd_class.help_options, list)):
553            help_options = fix_help_options(cmd_class.help_options)
554        else:
555            help_options = []
556
557
558        # All commands support the global options too, just by adding
559        # in 'global_options'.
560        parser.set_option_table(self.global_options +
561                                cmd_class.user_options +
562                                help_options)
563        parser.set_negative_aliases(negative_opt)
564        (args, opts) = parser.getopt(args[1:])
565        if hasattr(opts, 'help') and opts.help:
566            self._show_help(parser, display_options=0, commands=[cmd_class])
567            return
568
569        if (hasattr(cmd_class, 'help_options') and
570            isinstance(cmd_class.help_options, list)):
571            help_option_found=0
572            for (help_option, short, desc, func) in cmd_class.help_options:
573                if hasattr(opts, parser.get_attr_name(help_option)):
574                    help_option_found=1
575                    if hasattr(func, '__call__'):
576                        func()
577                    else:
578                        raise DistutilsClassError(
579                            "invalid help function %r for help option '%s': "
580                            "must be a callable object (function, etc.)"
581                            % (func, help_option))
582
583            if help_option_found:
584                return
585
586        # Put the options from the command-line into their official
587        # holding pen, the 'command_options' dictionary.
588        opt_dict = self.get_option_dict(command)
589        for (name, value) in vars(opts).items():
590            opt_dict[name] = ("command line", value)
591
592        return args
593
594    def finalize_options(self):
595        """Set final values for all the options on the Distribution
596        instance, analogous to the .finalize_options() method of Command
597        objects.
598        """
599        for attr in ('keywords', 'platforms'):
600            value = getattr(self.metadata, attr)
601            if value is None:
602                continue
603            if isinstance(value, str):
604                value = [elm.strip() for elm in value.split(',')]
605                setattr(self.metadata, attr, value)
606
607    def _show_help(self, parser, global_options=1, display_options=1,
608                   commands=[]):
609        """Show help for the setup script command-line in the form of
610        several lists of command-line options.  'parser' should be a
611        FancyGetopt instance; do not expect it to be returned in the
612        same state, as its option table will be reset to make it
613        generate the correct help text.
614
615        If 'global_options' is true, lists the global options:
616        --verbose, --dry-run, etc.  If 'display_options' is true, lists
617        the "display-only" options: --name, --version, etc.  Finally,
618        lists per-command help for every command name or command class
619        in 'commands'.
620        """
621        # late import because of mutual dependence between these modules
622        from distutils.core import gen_usage
623        from distutils.cmd import Command
624
625        if global_options:
626            if display_options:
627                options = self._get_toplevel_options()
628            else:
629                options = self.global_options
630            parser.set_option_table(options)
631            parser.print_help(self.common_usage + "\nGlobal options:")
632            print('')
633
634        if display_options:
635            parser.set_option_table(self.display_options)
636            parser.print_help(
637                "Information display options (just display " +
638                "information, ignore any commands)")
639            print('')
640
641        for command in self.commands:
642            if isinstance(command, type) and issubclass(command, Command):
643                klass = command
644            else:
645                klass = self.get_command_class(command)
646            if (hasattr(klass, 'help_options') and
647                isinstance(klass.help_options, list)):
648                parser.set_option_table(klass.user_options +
649                                        fix_help_options(klass.help_options))
650            else:
651                parser.set_option_table(klass.user_options)
652            parser.print_help("Options for '%s' command:" % klass.__name__)
653            print('')
654
655        print(gen_usage(self.script_name))
656
657    def handle_display_options(self, option_order):
658        """If there were any non-global "display-only" options
659        (--help-commands or the metadata display options) on the command
660        line, display the requested info and return true; else return
661        false.
662        """
663        from distutils.core import gen_usage
664
665        # User just wants a list of commands -- we'll print it out and stop
666        # processing now (ie. if they ran "setup --help-commands foo bar",
667        # we ignore "foo bar").
668        if self.help_commands:
669            self.print_commands()
670            print('')
671            print(gen_usage(self.script_name))
672            return 1
673
674        # If user supplied any of the "display metadata" options, then
675        # display that metadata in the order in which the user supplied the
676        # metadata options.
677        any_display_options = 0
678        is_display_option = {}
679        for option in self.display_options:
680            is_display_option[option[0]] = 1
681
682        for (opt, val) in option_order:
683            if val and is_display_option.get(opt):
684                opt = translate_longopt(opt)
685                value = getattr(self.metadata, "get_"+opt)()
686                if opt in ['keywords', 'platforms']:
687                    print(','.join(value))
688                elif opt in ('classifiers', 'provides', 'requires',
689                             'obsoletes'):
690                    print('\n'.join(value))
691                else:
692                    print(value)
693                any_display_options = 1
694
695        return any_display_options
696
697    def print_command_list(self, commands, header, max_length):
698        """Print a subset of the list of all commands -- used by
699        'print_commands()'.
700        """
701        print(header + ":")
702
703        for cmd in commands:
704            klass = self.cmdclass.get(cmd)
705            if not klass:
706                klass = self.get_command_class(cmd)
707            try:
708                description = klass.description
709            except AttributeError:
710                description = "(no description available)"
711
712            print("  %-*s  %s" % (max_length, cmd, description))
713
714    def print_commands(self):
715        """Print out a help message listing all available commands with a
716        description of each.  The list is divided into "standard commands"
717        (listed in distutils.command.__all__) and "extra commands"
718        (mentioned in self.cmdclass, but not a standard command).  The
719        descriptions come from the command class attribute
720        'description'.
721        """
722        import distutils.command
723        std_commands = distutils.command.__all__
724        is_std = {}
725        for cmd in std_commands:
726            is_std[cmd] = 1
727
728        extra_commands = []
729        for cmd in self.cmdclass.keys():
730            if not is_std.get(cmd):
731                extra_commands.append(cmd)
732
733        max_length = 0
734        for cmd in (std_commands + extra_commands):
735            if len(cmd) > max_length:
736                max_length = len(cmd)
737
738        self.print_command_list(std_commands,
739                                "Standard commands",
740                                max_length)
741        if extra_commands:
742            print
743            self.print_command_list(extra_commands,
744                                    "Extra commands",
745                                    max_length)
746
747    def get_command_list(self):
748        """Get a list of (command, description) tuples.
749        The list is divided into "standard commands" (listed in
750        distutils.command.__all__) and "extra commands" (mentioned in
751        self.cmdclass, but not a standard command).  The descriptions come
752        from the command class attribute 'description'.
753        """
754        # Currently this is only used on Mac OS, for the Mac-only GUI
755        # Distutils interface (by Jack Jansen)
756
757        import distutils.command
758        std_commands = distutils.command.__all__
759        is_std = {}
760        for cmd in std_commands:
761            is_std[cmd] = 1
762
763        extra_commands = []
764        for cmd in self.cmdclass.keys():
765            if not is_std.get(cmd):
766                extra_commands.append(cmd)
767
768        rv = []
769        for cmd in (std_commands + extra_commands):
770            klass = self.cmdclass.get(cmd)
771            if not klass:
772                klass = self.get_command_class(cmd)
773            try:
774                description = klass.description
775            except AttributeError:
776                description = "(no description available)"
777            rv.append((cmd, description))
778        return rv
779
780    # -- Command class/object methods ----------------------------------
781
782    def get_command_packages(self):
783        """Return a list of packages from which commands are loaded."""
784        pkgs = self.command_packages
785        if not isinstance(pkgs, list):
786            if pkgs is None:
787                pkgs = ''
788            pkgs = [pkg.strip() for pkg in pkgs.split(',') if pkg != '']
789            if "distutils.command" not in pkgs:
790                pkgs.insert(0, "distutils.command")
791            self.command_packages = pkgs
792        return pkgs
793
794    def get_command_class(self, command):
795        """Return the class that implements the Distutils command named by
796        'command'.  First we check the 'cmdclass' dictionary; if the
797        command is mentioned there, we fetch the class object from the
798        dictionary and return it.  Otherwise we load the command module
799        ("distutils.command." + command) and fetch the command class from
800        the module.  The loaded class is also stored in 'cmdclass'
801        to speed future calls to 'get_command_class()'.
802
803        Raises DistutilsModuleError if the expected module could not be
804        found, or if that module does not define the expected class.
805        """
806        klass = self.cmdclass.get(command)
807        if klass:
808            return klass
809
810        for pkgname in self.get_command_packages():
811            module_name = "%s.%s" % (pkgname, command)
812            klass_name = command
813
814            try:
815                __import__ (module_name)
816                module = sys.modules[module_name]
817            except ImportError:
818                continue
819
820            try:
821                klass = getattr(module, klass_name)
822            except AttributeError:
823                raise DistutilsModuleError, \
824                      "invalid command '%s' (no class '%s' in module '%s')" \
825                      % (command, klass_name, module_name)
826
827            self.cmdclass[command] = klass
828            return klass
829
830        raise DistutilsModuleError("invalid command '%s'" % command)
831
832
833    def get_command_obj(self, command, create=1):
834        """Return the command object for 'command'.  Normally this object
835        is cached on a previous call to 'get_command_obj()'; if no command
836        object for 'command' is in the cache, then we either create and
837        return it (if 'create' is true) or return None.
838        """
839        cmd_obj = self.command_obj.get(command)
840        if not cmd_obj and create:
841            if DEBUG:
842                self.announce("Distribution.get_command_obj(): " \
843                              "creating '%s' command object" % command)
844
845            klass = self.get_command_class(command)
846            cmd_obj = self.command_obj[command] = klass(self)
847            self.have_run[command] = 0
848
849            # Set any options that were supplied in config files
850            # or on the command line.  (NB. support for error
851            # reporting is lame here: any errors aren't reported
852            # until 'finalize_options()' is called, which means
853            # we won't report the source of the error.)
854            options = self.command_options.get(command)
855            if options:
856                self._set_command_options(cmd_obj, options)
857
858        return cmd_obj
859
860    def _set_command_options(self, command_obj, option_dict=None):
861        """Set the options for 'command_obj' from 'option_dict'.  Basically
862        this means copying elements of a dictionary ('option_dict') to
863        attributes of an instance ('command').
864
865        'command_obj' must be a Command instance.  If 'option_dict' is not
866        supplied, uses the standard option dictionary for this command
867        (from 'self.command_options').
868        """
869        command_name = command_obj.get_command_name()
870        if option_dict is None:
871            option_dict = self.get_option_dict(command_name)
872
873        if DEBUG:
874            self.announce("  setting options for '%s' command:" % command_name)
875        for (option, (source, value)) in option_dict.items():
876            if DEBUG:
877                self.announce("    %s = %s (from %s)" % (option, value,
878                                                         source))
879            try:
880                bool_opts = map(translate_longopt, command_obj.boolean_options)
881            except AttributeError:
882                bool_opts = []
883            try:
884                neg_opt = command_obj.negative_opt
885            except AttributeError:
886                neg_opt = {}
887
888            try:
889                is_string = isinstance(value, str)
890                if option in neg_opt and is_string:
891                    setattr(command_obj, neg_opt[option], not strtobool(value))
892                elif option in bool_opts and is_string:
893                    setattr(command_obj, option, strtobool(value))
894                elif hasattr(command_obj, option):
895                    setattr(command_obj, option, value)
896                else:
897                    raise DistutilsOptionError, \
898                          ("error in %s: command '%s' has no such option '%s'"
899                           % (source, command_name, option))
900            except ValueError, msg:
901                raise DistutilsOptionError, msg
902
903    def reinitialize_command(self, command, reinit_subcommands=0):
904        """Reinitializes a command to the state it was in when first
905        returned by 'get_command_obj()': ie., initialized but not yet
906        finalized.  This provides the opportunity to sneak option
907        values in programmatically, overriding or supplementing
908        user-supplied values from the config files and command line.
909        You'll have to re-finalize the command object (by calling
910        'finalize_options()' or 'ensure_finalized()') before using it for
911        real.
912
913        'command' should be a command name (string) or command object.  If
914        'reinit_subcommands' is true, also reinitializes the command's
915        sub-commands, as declared by the 'sub_commands' class attribute (if
916        it has one).  See the "install" command for an example.  Only
917        reinitializes the sub-commands that actually matter, ie. those
918        whose test predicates return true.
919
920        Returns the reinitialized command object.
921        """
922        from distutils.cmd import Command
923        if not isinstance(command, Command):
924            command_name = command
925            command = self.get_command_obj(command_name)
926        else:
927            command_name = command.get_command_name()
928
929        if not command.finalized:
930            return command
931        command.initialize_options()
932        command.finalized = 0
933        self.have_run[command_name] = 0
934        self._set_command_options(command)
935
936        if reinit_subcommands:
937            for sub in command.get_sub_commands():
938                self.reinitialize_command(sub, reinit_subcommands)
939
940        return command
941
942    # -- Methods that operate on the Distribution ----------------------
943
944    def announce(self, msg, level=log.INFO):
945        log.log(level, msg)
946
947    def run_commands(self):
948        """Run each command that was seen on the setup script command line.
949        Uses the list of commands found and cache of command objects
950        created by 'get_command_obj()'.
951        """
952        for cmd in self.commands:
953            self.run_command(cmd)
954
955    # -- Methods that operate on its Commands --------------------------
956
957    def run_command(self, command):
958        """Do whatever it takes to run a command (including nothing at all,
959        if the command has already been run).  Specifically: if we have
960        already created and run the command named by 'command', return
961        silently without doing anything.  If the command named by 'command'
962        doesn't even have a command object yet, create one.  Then invoke
963        'run()' on that command object (or an existing one).
964        """
965        # Already been here, done that? then return silently.
966        if self.have_run.get(command):
967            return
968
969        log.info("running %s", command)
970        cmd_obj = self.get_command_obj(command)
971        cmd_obj.ensure_finalized()
972        cmd_obj.run()
973        self.have_run[command] = 1
974
975
976    # -- Distribution query methods ------------------------------------
977
978    def has_pure_modules(self):
979        return len(self.packages or self.py_modules or []) > 0
980
981    def has_ext_modules(self):
982        return self.ext_modules and len(self.ext_modules) > 0
983
984    def has_c_libraries(self):
985        return self.libraries and len(self.libraries) > 0
986
987    def has_modules(self):
988        return self.has_pure_modules() or self.has_ext_modules()
989
990    def has_headers(self):
991        return self.headers and len(self.headers) > 0
992
993    def has_scripts(self):
994        return self.scripts and len(self.scripts) > 0
995
996    def has_data_files(self):
997        return self.data_files and len(self.data_files) > 0
998
999    def is_pure(self):
1000        return (self.has_pure_modules() and
1001                not self.has_ext_modules() and
1002                not self.has_c_libraries())
1003
1004    # -- Metadata query methods ----------------------------------------
1005
1006    # If you're looking for 'get_name()', 'get_version()', and so forth,
1007    # they are defined in a sneaky way: the constructor binds self.get_XXX
1008    # to self.metadata.get_XXX.  The actual code is in the
1009    # DistributionMetadata class, below.
1010
1011class DistributionMetadata:
1012    """Dummy class to hold the distribution meta-data: name, version,
1013    author, and so forth.
1014    """
1015
1016    _METHOD_BASENAMES = ("name", "version", "author", "author_email",
1017                         "maintainer", "maintainer_email", "url",
1018                         "license", "description", "long_description",
1019                         "keywords", "platforms", "fullname", "contact",
1020                         "contact_email", "license", "classifiers",
1021                         "download_url",
1022                         # PEP 314
1023                         "provides", "requires", "obsoletes",
1024                         )
1025
1026    def __init__(self, path=None):
1027        if path is not None:
1028            self.read_pkg_file(open(path))
1029        else:
1030            self.name = None
1031            self.version = None
1032            self.author = None
1033            self.author_email = None
1034            self.maintainer = None
1035            self.maintainer_email = None
1036            self.url = None
1037            self.license = None
1038            self.description = None
1039            self.long_description = None
1040            self.keywords = None
1041            self.platforms = None
1042            self.classifiers = None
1043            self.download_url = None
1044            # PEP 314
1045            self.provides = None
1046            self.requires = None
1047            self.obsoletes = None
1048
1049    def read_pkg_file(self, file):
1050        """Reads the metadata values from a file object."""
1051        msg = message_from_file(file)
1052
1053        def _read_field(name):
1054            value = msg[name]
1055            if value == 'UNKNOWN':
1056                return None
1057            return value
1058
1059        def _read_list(name):
1060            values = msg.get_all(name, None)
1061            if values == []:
1062                return None
1063            return values
1064
1065        metadata_version = msg['metadata-version']
1066        self.name = _read_field('name')
1067        self.version = _read_field('version')
1068        self.description = _read_field('summary')
1069        # we are filling author only.
1070        self.author = _read_field('author')
1071        self.maintainer = None
1072        self.author_email = _read_field('author-email')
1073        self.maintainer_email = None
1074        self.url = _read_field('home-page')
1075        self.license = _read_field('license')
1076
1077        if 'download-url' in msg:
1078            self.download_url = _read_field('download-url')
1079        else:
1080            self.download_url = None
1081
1082        self.long_description = _read_field('description')
1083        self.description = _read_field('summary')
1084
1085        if 'keywords' in msg:
1086            self.keywords = _read_field('keywords').split(',')
1087
1088        self.platforms = _read_list('platform')
1089        self.classifiers = _read_list('classifier')
1090
1091        # PEP 314 - these fields only exist in 1.1
1092        if metadata_version == '1.1':
1093            self.requires = _read_list('requires')
1094            self.provides = _read_list('provides')
1095            self.obsoletes = _read_list('obsoletes')
1096        else:
1097            self.requires = None
1098            self.provides = None
1099            self.obsoletes = None
1100
1101    def write_pkg_info(self, base_dir):
1102        """Write the PKG-INFO file into the release tree.
1103        """
1104        pkg_info = open(os.path.join(base_dir, 'PKG-INFO'), 'w')
1105        try:
1106            self.write_pkg_file(pkg_info)
1107        finally:
1108            pkg_info.close()
1109
1110    def write_pkg_file(self, file):
1111        """Write the PKG-INFO format data to a file object.
1112        """
1113        version = '1.0'
1114        if (self.provides or self.requires or self.obsoletes or
1115            self.classifiers or self.download_url):
1116            version = '1.1'
1117
1118        self._write_field(file, 'Metadata-Version', version)
1119        self._write_field(file, 'Name', self.get_name())
1120        self._write_field(file, 'Version', self.get_version())
1121        self._write_field(file, 'Summary', self.get_description())
1122        self._write_field(file, 'Home-page', self.get_url())
1123        self._write_field(file, 'Author', self.get_contact())
1124        self._write_field(file, 'Author-email', self.get_contact_email())
1125        self._write_field(file, 'License', self.get_license())
1126        if self.download_url:
1127            self._write_field(file, 'Download-URL', self.download_url)
1128
1129        long_desc = rfc822_escape(self.get_long_description())
1130        self._write_field(file, 'Description', long_desc)
1131
1132        keywords = ','.join(self.get_keywords())
1133        if keywords:
1134            self._write_field(file, 'Keywords', keywords)
1135
1136        self._write_list(file, 'Platform', self.get_platforms())
1137        self._write_list(file, 'Classifier', self.get_classifiers())
1138
1139        # PEP 314
1140        self._write_list(file, 'Requires', self.get_requires())
1141        self._write_list(file, 'Provides', self.get_provides())
1142        self._write_list(file, 'Obsoletes', self.get_obsoletes())
1143
1144    def _write_field(self, file, name, value):
1145        file.write('%s: %s\n' % (name, self._encode_field(value)))
1146
1147    def _write_list (self, file, name, values):
1148        for value in values:
1149            self._write_field(file, name, value)
1150
1151    def _encode_field(self, value):
1152        if value is None:
1153            return None
1154        if isinstance(value, unicode):
1155            return value.encode(PKG_INFO_ENCODING)
1156        return str(value)
1157
1158    # -- Metadata query methods ----------------------------------------
1159
1160    def get_name(self):
1161        return self.name or "UNKNOWN"
1162
1163    def get_version(self):
1164        return self.version or "0.0.0"
1165
1166    def get_fullname(self):
1167        return "%s-%s" % (self.get_name(), self.get_version())
1168
1169    def get_author(self):
1170        return self._encode_field(self.author) or "UNKNOWN"
1171
1172    def get_author_email(self):
1173        return self.author_email or "UNKNOWN"
1174
1175    def get_maintainer(self):
1176        return self._encode_field(self.maintainer) or "UNKNOWN"
1177
1178    def get_maintainer_email(self):
1179        return self.maintainer_email or "UNKNOWN"
1180
1181    def get_contact(self):
1182        return (self._encode_field(self.maintainer) or
1183                self._encode_field(self.author) or "UNKNOWN")
1184
1185    def get_contact_email(self):
1186        return self.maintainer_email or self.author_email or "UNKNOWN"
1187
1188    def get_url(self):
1189        return self.url or "UNKNOWN"
1190
1191    def get_license(self):
1192        return self.license or "UNKNOWN"
1193    get_licence = get_license
1194
1195    def get_description(self):
1196        return self._encode_field(self.description) or "UNKNOWN"
1197
1198    def get_long_description(self):
1199        return self._encode_field(self.long_description) or "UNKNOWN"
1200
1201    def get_keywords(self):
1202        return self.keywords or []
1203
1204    def get_platforms(self):
1205        return self.platforms or ["UNKNOWN"]
1206
1207    def get_classifiers(self):
1208        return self.classifiers or []
1209
1210    def get_download_url(self):
1211        return self.download_url or "UNKNOWN"
1212
1213    # PEP 314
1214    def get_requires(self):
1215        return self.requires or []
1216
1217    def set_requires(self, value):
1218        import distutils.versionpredicate
1219        for v in value:
1220            distutils.versionpredicate.VersionPredicate(v)
1221        self.requires = value
1222
1223    def get_provides(self):
1224        return self.provides or []
1225
1226    def set_provides(self, value):
1227        value = [v.strip() for v in value]
1228        for v in value:
1229            import distutils.versionpredicate
1230            distutils.versionpredicate.split_provision(v)
1231        self.provides = value
1232
1233    def get_obsoletes(self):
1234        return self.obsoletes or []
1235
1236    def set_obsoletes(self, value):
1237        import distutils.versionpredicate
1238        for v in value:
1239            distutils.versionpredicate.VersionPredicate(v)
1240        self.obsoletes = value
1241
1242def fix_help_options(options):
1243    """Convert a 4-tuple 'help_options' list as found in various command
1244    classes to the 3-tuple form required by FancyGetopt.
1245    """
1246    new_options = []
1247    for help_tuple in options:
1248        new_options.append(help_tuple[0:3])
1249    return new_options
1250