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