This commit was manufactured by cvs2svn to create tag
[python/dscho.git] / Lib / distutils / dist.py
blobb648f24eb7e09c5595634e19115ee6863b2d0a92
1 """distutils.dist
3 Provides the Distribution class, which represents the module distribution
4 being built/installed/distributed.
5 """
7 # created 2000/04/03, Greg Ward
8 # (extricated from core.py; actually dates back to the beginning)
10 __revision__ = "$Id$"
12 import sys, os, string, re
13 from types import *
14 from copy import copy
15 from distutils.errors import *
16 from distutils.fancy_getopt import FancyGetopt, translate_longopt
17 from distutils.util import check_environ, strtobool, rfc822_escape
20 # Regex to define acceptable Distutils command names. This is not *quite*
21 # the same as a Python NAME -- I don't allow leading underscores. The fact
22 # that they're very similar is no coincidence; the default naming scheme is
23 # to look for a Python module named after the command.
24 command_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$')
27 class Distribution:
28 """The core of the Distutils. Most of the work hiding behind 'setup'
29 is really done within a Distribution instance, which farms the work out
30 to the Distutils commands specified on the command line.
32 Setup scripts will almost never instantiate Distribution directly,
33 unless the 'setup()' function is totally inadequate to their needs.
34 However, it is conceivable that a setup script might wish to subclass
35 Distribution for some specialized purpose, and then pass the subclass
36 to 'setup()' as the 'distclass' keyword argument. If so, it is
37 necessary to respect the expectations that 'setup' has of Distribution.
38 See the code for 'setup()', in core.py, for details.
39 """
42 # 'global_options' describes the command-line options that may be
43 # supplied to the setup script prior to any actual commands.
44 # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of
45 # these global options. This list should be kept to a bare minimum,
46 # since every global option is also valid as a command option -- and we
47 # don't want to pollute the commands with too many options that they
48 # have minimal control over.
49 global_options = [('verbose', 'v', "run verbosely (default)"),
50 ('quiet', 'q', "run quietly (turns verbosity off)"),
51 ('dry-run', 'n', "don't actually do anything"),
52 ('help', 'h', "show detailed help message"),
55 # options that are not propagated to the commands
56 display_options = [
57 ('help-commands', None,
58 "list all available commands"),
59 ('name', None,
60 "print package name"),
61 ('version', 'V',
62 "print package version"),
63 ('fullname', None,
64 "print <package name>-<version>"),
65 ('author', None,
66 "print the author's name"),
67 ('author-email', None,
68 "print the author's email address"),
69 ('maintainer', None,
70 "print the maintainer's name"),
71 ('maintainer-email', None,
72 "print the maintainer's email address"),
73 ('contact', None,
74 "print the maintainer's name if known, else the author's"),
75 ('contact-email', None,
76 "print the maintainer's email address if known, else the author's"),
77 ('url', None,
78 "print the URL for this package"),
79 ('license', None,
80 "print the license of the package"),
81 ('licence', None,
82 "alias for --license"),
83 ('description', None,
84 "print the package description"),
85 ('long-description', None,
86 "print the long package description"),
87 ('platforms', None,
88 "print the list of platforms"),
89 ('keywords', None,
90 "print the list of keywords"),
92 display_option_names = map(lambda x: translate_longopt(x[0]),
93 display_options)
95 # negative options are options that exclude other options
96 negative_opt = {'quiet': 'verbose'}
99 # -- Creation/initialization methods -------------------------------
101 def __init__ (self, attrs=None):
102 """Construct a new Distribution instance: initialize all the
103 attributes of a Distribution, and then use 'attrs' (a dictionary
104 mapping attribute names to values) to assign some of those
105 attributes their "real" values. (Any attributes not mentioned in
106 'attrs' will be assigned to some null value: 0, None, an empty list
107 or dictionary, etc.) Most importantly, initialize the
108 'command_obj' attribute to the empty dictionary; this will be
109 filled in with real command objects by 'parse_command_line()'.
112 # Default values for our command-line options
113 self.verbose = 1
114 self.dry_run = 0
115 self.help = 0
116 for attr in self.display_option_names:
117 setattr(self, attr, 0)
119 # Store the distribution meta-data (name, version, author, and so
120 # forth) in a separate object -- we're getting to have enough
121 # information here (and enough command-line options) that it's
122 # worth it. Also delegate 'get_XXX()' methods to the 'metadata'
123 # object in a sneaky and underhanded (but efficient!) way.
124 self.metadata = DistributionMetadata()
125 for basename in self.metadata._METHOD_BASENAMES:
126 method_name = "get_" + basename
127 setattr(self, method_name, getattr(self.metadata, method_name))
129 # 'cmdclass' maps command names to class objects, so we
130 # can 1) quickly figure out which class to instantiate when
131 # we need to create a new command object, and 2) have a way
132 # for the setup script to override command classes
133 self.cmdclass = {}
135 # 'script_name' and 'script_args' are usually set to sys.argv[0]
136 # and sys.argv[1:], but they can be overridden when the caller is
137 # not necessarily a setup script run from the command-line.
138 self.script_name = None
139 self.script_args = None
141 # 'command_options' is where we store command options between
142 # parsing them (from config files, the command-line, etc.) and when
143 # they are actually needed -- ie. when the command in question is
144 # instantiated. It is a dictionary of dictionaries of 2-tuples:
145 # command_options = { command_name : { option : (source, value) } }
146 self.command_options = {}
148 # These options are really the business of various commands, rather
149 # than of the Distribution itself. We provide aliases for them in
150 # Distribution as a convenience to the developer.
151 self.packages = None
152 self.package_dir = None
153 self.py_modules = None
154 self.libraries = None
155 self.headers = None
156 self.ext_modules = None
157 self.ext_package = None
158 self.include_dirs = None
159 self.extra_path = None
160 self.scripts = None
161 self.data_files = None
163 # And now initialize bookkeeping stuff that can't be supplied by
164 # the caller at all. 'command_obj' maps command names to
165 # Command instances -- that's how we enforce that every command
166 # class is a singleton.
167 self.command_obj = {}
169 # 'have_run' maps command names to boolean values; it keeps track
170 # of whether we have actually run a particular command, to make it
171 # cheap to "run" a command whenever we think we might need to -- if
172 # it's already been done, no need for expensive filesystem
173 # operations, we just check the 'have_run' dictionary and carry on.
174 # It's only safe to query 'have_run' for a command class that has
175 # been instantiated -- a false value will be inserted when the
176 # command object is created, and replaced with a true value when
177 # the command is successfully run. Thus it's probably best to use
178 # '.get()' rather than a straight lookup.
179 self.have_run = {}
181 # Now we'll use the attrs dictionary (ultimately, keyword args from
182 # the setup script) to possibly override any or all of these
183 # distribution options.
185 if attrs:
187 # Pull out the set of command options and work on them
188 # specifically. Note that this order guarantees that aliased
189 # command options will override any supplied redundantly
190 # through the general options dictionary.
191 options = attrs.get('options')
192 if options:
193 del attrs['options']
194 for (command, cmd_options) in options.items():
195 opt_dict = self.get_option_dict(command)
196 for (opt, val) in cmd_options.items():
197 opt_dict[opt] = ("setup script", val)
199 # Now work on the rest of the attributes. Any attribute that's
200 # not already defined is invalid!
201 for (key,val) in attrs.items():
202 if hasattr(self.metadata, key):
203 setattr(self.metadata, key, val)
204 elif hasattr(self, key):
205 setattr(self, key, val)
206 else:
207 raise DistutilsSetupError, \
208 "invalid distribution option '%s'" % key
210 self.finalize_options()
212 # __init__ ()
215 def get_option_dict (self, command):
216 """Get the option dictionary for a given command. If that
217 command's option dictionary hasn't been created yet, then create it
218 and return the new dictionary; otherwise, return the existing
219 option dictionary.
222 dict = self.command_options.get(command)
223 if dict is None:
224 dict = self.command_options[command] = {}
225 return dict
228 def dump_option_dicts (self, header=None, commands=None, indent=""):
229 from pprint import pformat
231 if commands is None: # dump all command option dicts
232 commands = self.command_options.keys()
233 commands.sort()
235 if header is not None:
236 print indent + header
237 indent = indent + " "
239 if not commands:
240 print indent + "no commands known yet"
241 return
243 for cmd_name in commands:
244 opt_dict = self.command_options.get(cmd_name)
245 if opt_dict is None:
246 print indent + "no option dict for '%s' command" % cmd_name
247 else:
248 print indent + "option dict for '%s' command:" % cmd_name
249 out = pformat(opt_dict)
250 for line in string.split(out, "\n"):
251 print indent + " " + line
253 # dump_option_dicts ()
257 # -- Config file finding/parsing methods ---------------------------
259 def find_config_files (self):
260 """Find as many configuration files as should be processed for this
261 platform, and return a list of filenames in the order in which they
262 should be parsed. The filenames returned are guaranteed to exist
263 (modulo nasty race conditions).
265 There are three possible config files: distutils.cfg in the
266 Distutils installation directory (ie. where the top-level
267 Distutils __inst__.py file lives), a file in the user's home
268 directory named .pydistutils.cfg on Unix and pydistutils.cfg
269 on Windows/Mac, and setup.cfg in the current directory.
271 files = []
272 check_environ()
274 # Where to look for the system-wide Distutils config file
275 sys_dir = os.path.dirname(sys.modules['distutils'].__file__)
277 # Look for the system config file
278 sys_file = os.path.join(sys_dir, "distutils.cfg")
279 if os.path.isfile(sys_file):
280 files.append(sys_file)
282 # What to call the per-user config file
283 if os.name == 'posix':
284 user_filename = ".pydistutils.cfg"
285 else:
286 user_filename = "pydistutils.cfg"
288 # And look for the user config file
289 if os.environ.has_key('HOME'):
290 user_file = os.path.join(os.environ.get('HOME'), user_filename)
291 if os.path.isfile(user_file):
292 files.append(user_file)
294 # All platforms support local setup.cfg
295 local_file = "setup.cfg"
296 if os.path.isfile(local_file):
297 files.append(local_file)
299 return files
301 # find_config_files ()
304 def parse_config_files (self, filenames=None):
306 from ConfigParser import ConfigParser
307 from distutils.core import DEBUG
309 if filenames is None:
310 filenames = self.find_config_files()
312 if DEBUG: print "Distribution.parse_config_files():"
314 parser = ConfigParser()
315 for filename in filenames:
316 if DEBUG: print " reading", filename
317 parser.read(filename)
318 for section in parser.sections():
319 options = parser.options(section)
320 opt_dict = self.get_option_dict(section)
322 for opt in options:
323 if opt != '__name__':
324 val = parser.get(section,opt)
325 opt = string.replace(opt, '-', '_')
326 opt_dict[opt] = (filename, val)
328 # Make the ConfigParser forget everything (so we retain
329 # the original filenames that options come from) -- gag,
330 # retch, puke -- another good reason for a distutils-
331 # specific config parser (sigh...)
332 parser.__init__()
334 # If there was a "global" section in the config file, use it
335 # to set Distribution options.
337 if self.command_options.has_key('global'):
338 for (opt, (src, val)) in self.command_options['global'].items():
339 alias = self.negative_opt.get(opt)
340 try:
341 if alias:
342 setattr(self, alias, not strtobool(val))
343 elif opt in ('verbose', 'dry_run'): # ugh!
344 setattr(self, opt, strtobool(val))
345 except ValueError, msg:
346 raise DistutilsOptionError, msg
348 # parse_config_files ()
351 # -- Command-line parsing methods ----------------------------------
353 def parse_command_line (self):
354 """Parse the setup script's command line, taken from the
355 'script_args' instance attribute (which defaults to 'sys.argv[1:]'
356 -- see 'setup()' in core.py). This list is first processed for
357 "global options" -- options that set attributes of the Distribution
358 instance. Then, it is alternately scanned for Distutils commands
359 and options for that command. Each new command terminates the
360 options for the previous command. The allowed options for a
361 command are determined by the 'user_options' attribute of the
362 command class -- thus, we have to be able to load command classes
363 in order to parse the command line. Any error in that 'options'
364 attribute raises DistutilsGetoptError; any error on the
365 command-line raises DistutilsArgError. If no Distutils commands
366 were found on the command line, raises DistutilsArgError. Return
367 true if command-line was successfully parsed and we should carry
368 on with executing commands; false if no errors but we shouldn't
369 execute commands (currently, this only happens if user asks for
370 help).
373 # We now have enough information to show the Macintosh dialog
374 # that allows the user to interactively specify the "command line".
376 if sys.platform == 'mac':
377 import EasyDialogs
378 cmdlist = self.get_command_list()
379 self.script_args = EasyDialogs.GetArgv(
380 self.global_options + self.display_options, cmdlist)
382 # We have to parse the command line a bit at a time -- global
383 # options, then the first command, then its options, and so on --
384 # because each command will be handled by a different class, and
385 # the options that are valid for a particular class aren't known
386 # until we have loaded the command class, which doesn't happen
387 # until we know what the command is.
389 self.commands = []
390 parser = FancyGetopt(self.global_options + self.display_options)
391 parser.set_negative_aliases(self.negative_opt)
392 parser.set_aliases({'licence': 'license'})
393 args = parser.getopt(args=self.script_args, object=self)
394 option_order = parser.get_option_order()
396 # for display options we return immediately
397 if self.handle_display_options(option_order):
398 return
400 while args:
401 args = self._parse_command_opts(parser, args)
402 if args is None: # user asked for help (and got it)
403 return
405 # Handle the cases of --help as a "global" option, ie.
406 # "setup.py --help" and "setup.py --help command ...". For the
407 # former, we show global options (--verbose, --dry-run, etc.)
408 # and display-only options (--name, --version, etc.); for the
409 # latter, we omit the display-only options and show help for
410 # each command listed on the command line.
411 if self.help:
412 self._show_help(parser,
413 display_options=len(self.commands) == 0,
414 commands=self.commands)
415 return
417 # Oops, no commands found -- an end-user error
418 if not self.commands:
419 raise DistutilsArgError, "no commands supplied"
421 # All is well: return true
422 return 1
424 # parse_command_line()
426 def _parse_command_opts (self, parser, args):
427 """Parse the command-line options for a single command.
428 'parser' must be a FancyGetopt instance; 'args' must be the list
429 of arguments, starting with the current command (whose options
430 we are about to parse). Returns a new version of 'args' with
431 the next command at the front of the list; will be the empty
432 list if there are no more commands on the command line. Returns
433 None if the user asked for help on this command.
435 # late import because of mutual dependence between these modules
436 from distutils.cmd import Command
438 # Pull the current command from the head of the command line
439 command = args[0]
440 if not command_re.match(command):
441 raise SystemExit, "invalid command name '%s'" % command
442 self.commands.append(command)
444 # Dig up the command class that implements this command, so we
445 # 1) know that it's a valid command, and 2) know which options
446 # it takes.
447 try:
448 cmd_class = self.get_command_class(command)
449 except DistutilsModuleError, msg:
450 raise DistutilsArgError, msg
452 # Require that the command class be derived from Command -- want
453 # to be sure that the basic "command" interface is implemented.
454 if not issubclass(cmd_class, Command):
455 raise DistutilsClassError, \
456 "command class %s must subclass Command" % cmd_class
458 # Also make sure that the command object provides a list of its
459 # known options.
460 if not (hasattr(cmd_class, 'user_options') and
461 type(cmd_class.user_options) is ListType):
462 raise DistutilsClassError, \
463 ("command class %s must provide " +
464 "'user_options' attribute (a list of tuples)") % \
465 cmd_class
467 # If the command class has a list of negative alias options,
468 # merge it in with the global negative aliases.
469 negative_opt = self.negative_opt
470 if hasattr(cmd_class, 'negative_opt'):
471 negative_opt = copy(negative_opt)
472 negative_opt.update(cmd_class.negative_opt)
474 # Check for help_options in command class. They have a different
475 # format (tuple of four) so we need to preprocess them here.
476 if (hasattr(cmd_class, 'help_options') and
477 type(cmd_class.help_options) is ListType):
478 help_options = fix_help_options(cmd_class.help_options)
479 else:
480 help_options = []
483 # All commands support the global options too, just by adding
484 # in 'global_options'.
485 parser.set_option_table(self.global_options +
486 cmd_class.user_options +
487 help_options)
488 parser.set_negative_aliases(negative_opt)
489 (args, opts) = parser.getopt(args[1:])
490 if hasattr(opts, 'help') and opts.help:
491 self._show_help(parser, display_options=0, commands=[cmd_class])
492 return
494 if (hasattr(cmd_class, 'help_options') and
495 type(cmd_class.help_options) is ListType):
496 help_option_found=0
497 for (help_option, short, desc, func) in cmd_class.help_options:
498 if hasattr(opts, parser.get_attr_name(help_option)):
499 help_option_found=1
500 #print "showing help for option %s of command %s" % \
501 # (help_option[0],cmd_class)
503 if callable(func):
504 func()
505 else:
506 raise DistutilsClassError(
507 "invalid help function %s for help option '%s': "
508 "must be a callable object (function, etc.)"
509 % (`func`, help_option))
511 if help_option_found:
512 return
514 # Put the options from the command-line into their official
515 # holding pen, the 'command_options' dictionary.
516 opt_dict = self.get_option_dict(command)
517 for (name, value) in vars(opts).items():
518 opt_dict[name] = ("command line", value)
520 return args
522 # _parse_command_opts ()
525 def finalize_options (self):
526 """Set final values for all the options on the Distribution
527 instance, analogous to the .finalize_options() method of Command
528 objects.
531 keywords = self.metadata.keywords
532 if keywords is not None:
533 if type(keywords) is StringType:
534 keywordlist = string.split(keywords, ',')
535 self.metadata.keywords = map(string.strip, keywordlist)
537 platforms = self.metadata.platforms
538 if platforms is not None:
539 if type(platforms) is StringType:
540 platformlist = string.split(platforms, ',')
541 self.metadata.platforms = map(string.strip, platformlist)
543 def _show_help (self,
544 parser,
545 global_options=1,
546 display_options=1,
547 commands=[]):
548 """Show help for the setup script command-line in the form of
549 several lists of command-line options. 'parser' should be a
550 FancyGetopt instance; do not expect it to be returned in the
551 same state, as its option table will be reset to make it
552 generate the correct help text.
554 If 'global_options' is true, lists the global options:
555 --verbose, --dry-run, etc. If 'display_options' is true, lists
556 the "display-only" options: --name, --version, etc. Finally,
557 lists per-command help for every command name or command class
558 in 'commands'.
560 # late import because of mutual dependence between these modules
561 from distutils.core import gen_usage
562 from distutils.cmd import Command
564 if global_options:
565 parser.set_option_table(self.global_options)
566 parser.print_help("Global options:")
567 print
569 if display_options:
570 parser.set_option_table(self.display_options)
571 parser.print_help(
572 "Information display options (just display " +
573 "information, ignore any commands)")
574 print
576 for command in self.commands:
577 if type(command) is ClassType and issubclass(command, Command):
578 klass = command
579 else:
580 klass = self.get_command_class(command)
581 if (hasattr(klass, 'help_options') and
582 type(klass.help_options) is ListType):
583 parser.set_option_table(klass.user_options +
584 fix_help_options(klass.help_options))
585 else:
586 parser.set_option_table(klass.user_options)
587 parser.print_help("Options for '%s' command:" % klass.__name__)
588 print
590 print gen_usage(self.script_name)
591 return
593 # _show_help ()
596 def handle_display_options (self, option_order):
597 """If there were any non-global "display-only" options
598 (--help-commands or the metadata display options) on the command
599 line, display the requested info and return true; else return
600 false.
602 from distutils.core import gen_usage
604 # User just wants a list of commands -- we'll print it out and stop
605 # processing now (ie. if they ran "setup --help-commands foo bar",
606 # we ignore "foo bar").
607 if self.help_commands:
608 self.print_commands()
609 print
610 print gen_usage(self.script_name)
611 return 1
613 # If user supplied any of the "display metadata" options, then
614 # display that metadata in the order in which the user supplied the
615 # metadata options.
616 any_display_options = 0
617 is_display_option = {}
618 for option in self.display_options:
619 is_display_option[option[0]] = 1
621 for (opt, val) in option_order:
622 if val and is_display_option.get(opt):
623 opt = translate_longopt(opt)
624 value = getattr(self.metadata, "get_"+opt)()
625 if opt in ['keywords', 'platforms']:
626 print string.join(value, ',')
627 else:
628 print value
629 any_display_options = 1
631 return any_display_options
633 # handle_display_options()
635 def print_command_list (self, commands, header, max_length):
636 """Print a subset of the list of all commands -- used by
637 'print_commands()'.
640 print header + ":"
642 for cmd in commands:
643 klass = self.cmdclass.get(cmd)
644 if not klass:
645 klass = self.get_command_class(cmd)
646 try:
647 description = klass.description
648 except AttributeError:
649 description = "(no description available)"
651 print " %-*s %s" % (max_length, cmd, description)
653 # print_command_list ()
656 def print_commands (self):
657 """Print out a help message listing all available commands with a
658 description of each. The list is divided into "standard commands"
659 (listed in distutils.command.__all__) and "extra commands"
660 (mentioned in self.cmdclass, but not a standard command). The
661 descriptions come from the command class attribute
662 'description'.
665 import distutils.command
666 std_commands = distutils.command.__all__
667 is_std = {}
668 for cmd in std_commands:
669 is_std[cmd] = 1
671 extra_commands = []
672 for cmd in self.cmdclass.keys():
673 if not is_std.get(cmd):
674 extra_commands.append(cmd)
676 max_length = 0
677 for cmd in (std_commands + extra_commands):
678 if len(cmd) > max_length:
679 max_length = len(cmd)
681 self.print_command_list(std_commands,
682 "Standard commands",
683 max_length)
684 if extra_commands:
685 print
686 self.print_command_list(extra_commands,
687 "Extra commands",
688 max_length)
690 # print_commands ()
692 def get_command_list (self):
693 """Get a list of (command, description) tuples.
694 The list is divided into "standard commands" (listed in
695 distutils.command.__all__) and "extra commands" (mentioned in
696 self.cmdclass, but not a standard command). The descriptions come
697 from the command class attribute 'description'.
699 # Currently this is only used on Mac OS, for the Mac-only GUI
700 # Distutils interface (by Jack Jansen)
702 import distutils.command
703 std_commands = distutils.command.__all__
704 is_std = {}
705 for cmd in std_commands:
706 is_std[cmd] = 1
708 extra_commands = []
709 for cmd in self.cmdclass.keys():
710 if not is_std.get(cmd):
711 extra_commands.append(cmd)
713 rv = []
714 for cmd in (std_commands + extra_commands):
715 klass = self.cmdclass.get(cmd)
716 if not klass:
717 klass = self.get_command_class(cmd)
718 try:
719 description = klass.description
720 except AttributeError:
721 description = "(no description available)"
722 rv.append((cmd, description))
723 return rv
725 # -- Command class/object methods ----------------------------------
727 def get_command_class (self, command):
728 """Return the class that implements the Distutils command named by
729 'command'. First we check the 'cmdclass' dictionary; if the
730 command is mentioned there, we fetch the class object from the
731 dictionary and return it. Otherwise we load the command module
732 ("distutils.command." + command) and fetch the command class from
733 the module. The loaded class is also stored in 'cmdclass'
734 to speed future calls to 'get_command_class()'.
736 Raises DistutilsModuleError if the expected module could not be
737 found, or if that module does not define the expected class.
739 klass = self.cmdclass.get(command)
740 if klass:
741 return klass
743 module_name = 'distutils.command.' + command
744 klass_name = command
746 try:
747 __import__ (module_name)
748 module = sys.modules[module_name]
749 except ImportError:
750 raise DistutilsModuleError, \
751 "invalid command '%s' (no module named '%s')" % \
752 (command, module_name)
754 try:
755 klass = getattr(module, klass_name)
756 except AttributeError:
757 raise DistutilsModuleError, \
758 "invalid command '%s' (no class '%s' in module '%s')" \
759 % (command, klass_name, module_name)
761 self.cmdclass[command] = klass
762 return klass
764 # get_command_class ()
766 def get_command_obj (self, command, create=1):
767 """Return the command object for 'command'. Normally this object
768 is cached on a previous call to 'get_command_obj()'; if no command
769 object for 'command' is in the cache, then we either create and
770 return it (if 'create' is true) or return None.
772 from distutils.core import DEBUG
773 cmd_obj = self.command_obj.get(command)
774 if not cmd_obj and create:
775 if DEBUG:
776 print "Distribution.get_command_obj(): " \
777 "creating '%s' command object" % command
779 klass = self.get_command_class(command)
780 cmd_obj = self.command_obj[command] = klass(self)
781 self.have_run[command] = 0
783 # Set any options that were supplied in config files
784 # or on the command line. (NB. support for error
785 # reporting is lame here: any errors aren't reported
786 # until 'finalize_options()' is called, which means
787 # we won't report the source of the error.)
788 options = self.command_options.get(command)
789 if options:
790 self._set_command_options(cmd_obj, options)
792 return cmd_obj
794 def _set_command_options (self, command_obj, option_dict=None):
795 """Set the options for 'command_obj' from 'option_dict'. Basically
796 this means copying elements of a dictionary ('option_dict') to
797 attributes of an instance ('command').
799 'command_obj' must be a Command instance. If 'option_dict' is not
800 supplied, uses the standard option dictionary for this command
801 (from 'self.command_options').
803 from distutils.core import DEBUG
805 command_name = command_obj.get_command_name()
806 if option_dict is None:
807 option_dict = self.get_option_dict(command_name)
809 if DEBUG: print " setting options for '%s' command:" % command_name
810 for (option, (source, value)) in option_dict.items():
811 if DEBUG: print " %s = %s (from %s)" % (option, value, source)
812 try:
813 bool_opts = map(translate_longopt, command_obj.boolean_options)
814 except AttributeError:
815 bool_opts = []
816 try:
817 neg_opt = command_obj.negative_opt
818 except AttributeError:
819 neg_opt = {}
821 try:
822 is_string = type(value) is StringType
823 if neg_opt.has_key(option) and is_string:
824 setattr(command_obj, neg_opt[option], not strtobool(value))
825 elif option in bool_opts and is_string:
826 setattr(command_obj, option, strtobool(value))
827 elif hasattr(command_obj, option):
828 setattr(command_obj, option, value)
829 else:
830 raise DistutilsOptionError, \
831 ("error in %s: command '%s' has no such option '%s'"
832 % (source, command_name, option))
833 except ValueError, msg:
834 raise DistutilsOptionError, msg
836 def reinitialize_command (self, command, reinit_subcommands=0):
837 """Reinitializes a command to the state it was in when first
838 returned by 'get_command_obj()': ie., initialized but not yet
839 finalized. This provides the opportunity to sneak option
840 values in programmatically, overriding or supplementing
841 user-supplied values from the config files and command line.
842 You'll have to re-finalize the command object (by calling
843 'finalize_options()' or 'ensure_finalized()') before using it for
844 real.
846 'command' should be a command name (string) or command object. If
847 'reinit_subcommands' is true, also reinitializes the command's
848 sub-commands, as declared by the 'sub_commands' class attribute (if
849 it has one). See the "install" command for an example. Only
850 reinitializes the sub-commands that actually matter, ie. those
851 whose test predicates return true.
853 Returns the reinitialized command object.
855 from distutils.cmd import Command
856 if not isinstance(command, Command):
857 command_name = command
858 command = self.get_command_obj(command_name)
859 else:
860 command_name = command.get_command_name()
862 if not command.finalized:
863 return command
864 command.initialize_options()
865 command.finalized = 0
866 self.have_run[command_name] = 0
867 self._set_command_options(command)
869 if reinit_subcommands:
870 for sub in command.get_sub_commands():
871 self.reinitialize_command(sub, reinit_subcommands)
873 return command
876 # -- Methods that operate on the Distribution ----------------------
878 def announce (self, msg, level=1):
879 """Print 'msg' if 'level' is greater than or equal to the verbosity
880 level recorded in the 'verbose' attribute (which, currently, can be
881 only 0 or 1).
883 if self.verbose >= level:
884 print msg
887 def run_commands (self):
888 """Run each command that was seen on the setup script command line.
889 Uses the list of commands found and cache of command objects
890 created by 'get_command_obj()'.
892 for cmd in self.commands:
893 self.run_command(cmd)
896 # -- Methods that operate on its Commands --------------------------
898 def run_command (self, command):
899 """Do whatever it takes to run a command (including nothing at all,
900 if the command has already been run). Specifically: if we have
901 already created and run the command named by 'command', return
902 silently without doing anything. If the command named by 'command'
903 doesn't even have a command object yet, create one. Then invoke
904 'run()' on that command object (or an existing one).
906 # Already been here, done that? then return silently.
907 if self.have_run.get(command):
908 return
910 self.announce("running " + command)
911 cmd_obj = self.get_command_obj(command)
912 cmd_obj.ensure_finalized()
913 cmd_obj.run()
914 self.have_run[command] = 1
917 # -- Distribution query methods ------------------------------------
919 def has_pure_modules (self):
920 return len(self.packages or self.py_modules or []) > 0
922 def has_ext_modules (self):
923 return self.ext_modules and len(self.ext_modules) > 0
925 def has_c_libraries (self):
926 return self.libraries and len(self.libraries) > 0
928 def has_modules (self):
929 return self.has_pure_modules() or self.has_ext_modules()
931 def has_headers (self):
932 return self.headers and len(self.headers) > 0
934 def has_scripts (self):
935 return self.scripts and len(self.scripts) > 0
937 def has_data_files (self):
938 return self.data_files and len(self.data_files) > 0
940 def is_pure (self):
941 return (self.has_pure_modules() and
942 not self.has_ext_modules() and
943 not self.has_c_libraries())
945 # -- Metadata query methods ----------------------------------------
947 # If you're looking for 'get_name()', 'get_version()', and so forth,
948 # they are defined in a sneaky way: the constructor binds self.get_XXX
949 # to self.metadata.get_XXX. The actual code is in the
950 # DistributionMetadata class, below.
952 # class Distribution
955 class DistributionMetadata:
956 """Dummy class to hold the distribution meta-data: name, version,
957 author, and so forth.
960 _METHOD_BASENAMES = ("name", "version", "author", "author_email",
961 "maintainer", "maintainer_email", "url",
962 "license", "description", "long_description",
963 "keywords", "platforms", "fullname", "contact",
964 "contact_email", "licence")
966 def __init__ (self):
967 self.name = None
968 self.version = None
969 self.author = None
970 self.author_email = None
971 self.maintainer = None
972 self.maintainer_email = None
973 self.url = None
974 self.license = None
975 self.description = None
976 self.long_description = None
977 self.keywords = None
978 self.platforms = None
980 def write_pkg_info (self, base_dir):
981 """Write the PKG-INFO file into the release tree.
984 pkg_info = open( os.path.join(base_dir, 'PKG-INFO'), 'w')
986 pkg_info.write('Metadata-Version: 1.0\n')
987 pkg_info.write('Name: %s\n' % self.get_name() )
988 pkg_info.write('Version: %s\n' % self.get_version() )
989 pkg_info.write('Summary: %s\n' % self.get_description() )
990 pkg_info.write('Home-page: %s\n' % self.get_url() )
991 pkg_info.write('Author: %s\n' % self.get_contact() )
992 pkg_info.write('Author-email: %s\n' % self.get_contact_email() )
993 pkg_info.write('License: %s\n' % self.get_license() )
995 long_desc = rfc822_escape( self.get_long_description() )
996 pkg_info.write('Description: %s\n' % long_desc)
998 keywords = string.join( self.get_keywords(), ',')
999 if keywords:
1000 pkg_info.write('Keywords: %s\n' % keywords )
1002 for platform in self.get_platforms():
1003 pkg_info.write('Platform: %s\n' % platform )
1005 pkg_info.close()
1007 # write_pkg_info ()
1009 # -- Metadata query methods ----------------------------------------
1011 def get_name (self):
1012 return self.name or "UNKNOWN"
1014 def get_version(self):
1015 return self.version or "0.0.0"
1017 def get_fullname (self):
1018 return "%s-%s" % (self.get_name(), self.get_version())
1020 def get_author(self):
1021 return self.author or "UNKNOWN"
1023 def get_author_email(self):
1024 return self.author_email or "UNKNOWN"
1026 def get_maintainer(self):
1027 return self.maintainer or "UNKNOWN"
1029 def get_maintainer_email(self):
1030 return self.maintainer_email or "UNKNOWN"
1032 def get_contact(self):
1033 return (self.maintainer or
1034 self.author or
1035 "UNKNOWN")
1037 def get_contact_email(self):
1038 return (self.maintainer_email or
1039 self.author_email or
1040 "UNKNOWN")
1042 def get_url(self):
1043 return self.url or "UNKNOWN"
1045 def get_license(self):
1046 return self.license or "UNKNOWN"
1047 get_licence = get_license
1049 def get_description(self):
1050 return self.description or "UNKNOWN"
1052 def get_long_description(self):
1053 return self.long_description or "UNKNOWN"
1055 def get_keywords(self):
1056 return self.keywords or []
1058 def get_platforms(self):
1059 return self.platforms or ["UNKNOWN"]
1061 # class DistributionMetadata
1064 def fix_help_options (options):
1065 """Convert a 4-tuple 'help_options' list as found in various command
1066 classes to the 3-tuple form required by FancyGetopt.
1068 new_options = []
1069 for help_tuple in options:
1070 new_options.append(help_tuple[0:3])
1071 return new_options
1074 if __name__ == "__main__":
1075 dist = Distribution()
1076 print "ok"