0001 """distutils.dist 0002 0003 Provides the Distribution class, which represents the module distribution 0004 being built/installed/distributed. 0005 """ 0006 0007 # This module should be kept compatible with Python 1.5.2. 0008 0009 __revision__ = "$Id: dist.py,v 1.71 2004/10/13 13:22:34 anthonybaxter Exp $" 0010 0011 import sys, os, string, re 0012 from types import * 0013 from copy import copy 0014 0015 try: 0016 import warnings 0017 except ImportError: 0018 warnings = None 0019 0020 from distutils.errors import * 0021 from distutils.fancy_getopt import FancyGetopt, translate_longopt 0022 from distutils.util import check_environ, strtobool, rfc822_escape 0023 from distutils import log 0024 from distutils.debug import DEBUG 0025 0026 # Regex to define acceptable Distutils command names. This is not *quite* 0027 # the same as a Python NAME -- I don't allow leading underscores. The fact 0028 # that they're very similar is no coincidence; the default naming scheme is 0029 # to look for a Python module named after the command. 0030 command_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$') 0031 0032 0033 class Distribution: 0034 """The core of the Distutils. Most of the work hiding behind 'setup' 0035 is really done within a Distribution instance, which farms the work out 0036 to the Distutils commands specified on the command line. 0037 0038 Setup scripts will almost never instantiate Distribution directly, 0039 unless the 'setup()' function is totally inadequate to their needs. 0040 However, it is conceivable that a setup script might wish to subclass 0041 Distribution for some specialized purpose, and then pass the subclass 0042 to 'setup()' as the 'distclass' keyword argument. If so, it is 0043 necessary to respect the expectations that 'setup' has of Distribution. 0044 See the code for 'setup()', in core.py, for details. 0045 """ 0046 0047 0048 # 'global_options' describes the command-line options that may be 0049 # supplied to the setup script prior to any actual commands. 0050 # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of 0051 # these global options. This list should be kept to a bare minimum, 0052 # since every global option is also valid as a command option -- and we 0053 # don't want to pollute the commands with too many options that they 0054 # have minimal control over. 0055 # The fourth entry for verbose means that it can be repeated. 0056 global_options = [('verbose', 'v', "run verbosely (default)", 1), 0057 ('quiet', 'q', "run quietly (turns verbosity off)"), 0058 ('dry-run', 'n', "don't actually do anything"), 0059 ('help', 'h', "show detailed help message"), 0060 ] 0061 0062 # options that are not propagated to the commands 0063 display_options = [ 0064 ('help-commands', None, 0065 "list all available commands"), 0066 ('name', None, 0067 "print package name"), 0068 ('version', 'V', 0069 "print package version"), 0070 ('fullname', None, 0071 "print <package name>-<version>"), 0072 ('author', None, 0073 "print the author's name"), 0074 ('author-email', None, 0075 "print the author's email address"), 0076 ('maintainer', None, 0077 "print the maintainer's name"), 0078 ('maintainer-email', None, 0079 "print the maintainer's email address"), 0080 ('contact', None, 0081 "print the maintainer's name if known, else the author's"), 0082 ('contact-email', None, 0083 "print the maintainer's email address if known, else the author's"), 0084 ('url', None, 0085 "print the URL for this package"), 0086 ('license', None, 0087 "print the license of the package"), 0088 ('licence', None, 0089 "alias for --license"), 0090 ('description', None, 0091 "print the package description"), 0092 ('long-description', None, 0093 "print the long package description"), 0094 ('platforms', None, 0095 "print the list of platforms"), 0096 ('classifiers', None, 0097 "print the list of classifiers"), 0098 ('keywords', None, 0099 "print the list of keywords"), 0100 ] 0101 display_option_names = map(lambda x: translate_longopt(x[0]), 0102 display_options) 0103 0104 # negative options are options that exclude other options 0105 negative_opt = {'quiet': 'verbose'} 0106 0107 0108 # -- Creation/initialization methods ------------------------------- 0109 0110 def __init__ (self, attrs=None): 0111 """Construct a new Distribution instance: initialize all the 0112 attributes of a Distribution, and then use 'attrs' (a dictionary 0113 mapping attribute names to values) to assign some of those 0114 attributes their "real" values. (Any attributes not mentioned in 0115 'attrs' will be assigned to some null value: 0, None, an empty list 0116 or dictionary, etc.) Most importantly, initialize the 0117 'command_obj' attribute to the empty dictionary; this will be 0118 filled in with real command objects by 'parse_command_line()'. 0119 """ 0120 0121 # Default values for our command-line options 0122 self.verbose = 1 0123 self.dry_run = 0 0124 self.help = 0 0125 for attr in self.display_option_names: 0126 setattr(self, attr, 0) 0127 0128 # Store the distribution meta-data (name, version, author, and so 0129 # forth) in a separate object -- we're getting to have enough 0130 # information here (and enough command-line options) that it's 0131 # worth it. Also delegate 'get_XXX()' methods to the 'metadata' 0132 # object in a sneaky and underhanded (but efficient!) way. 0133 self.metadata = DistributionMetadata() 0134 for basename in self.metadata._METHOD_BASENAMES: 0135 method_name = "get_" + basename 0136 setattr(self, method_name, getattr(self.metadata, method_name)) 0137 0138 # 'cmdclass' maps command names to class objects, so we 0139 # can 1) quickly figure out which class to instantiate when 0140 # we need to create a new command object, and 2) have a way 0141 # for the setup script to override command classes 0142 self.cmdclass = {} 0143 0144 # 'command_packages' is a list of packages in which commands 0145 # are searched for. The factory for command 'foo' is expected 0146 # to be named 'foo' in the module 'foo' in one of the packages 0147 # named here. This list is searched from the left; an error 0148 # is raised if no named package provides the command being 0149 # searched for. (Always access using get_command_packages().) 0150 self.command_packages = None 0151 0152 # 'script_name' and 'script_args' are usually set to sys.argv[0] 0153 # and sys.argv[1:], but they can be overridden when the caller is 0154 # not necessarily a setup script run from the command-line. 0155 self.script_name = None 0156 self.script_args = None 0157 0158 # 'command_options' is where we store command options between 0159 # parsing them (from config files, the command-line, etc.) and when 0160 # they are actually needed -- ie. when the command in question is 0161 # instantiated. It is a dictionary of dictionaries of 2-tuples: 0162 # command_options = { command_name : { option : (source, value) } } 0163 self.command_options = {} 0164 0165 # These options are really the business of various commands, rather 0166 # than of the Distribution itself. We provide aliases for them in 0167 # Distribution as a convenience to the developer. 0168 self.packages = None 0169 self.package_data = {} 0170 self.package_dir = None 0171 self.py_modules = None 0172 self.libraries = None 0173 self.headers = None 0174 self.ext_modules = None 0175 self.ext_package = None 0176 self.include_dirs = None 0177 self.extra_path = None 0178 self.scripts = None 0179 self.data_files = None 0180 0181 # And now initialize bookkeeping stuff that can't be supplied by 0182 # the caller at all. 'command_obj' maps command names to 0183 # Command instances -- that's how we enforce that every command 0184 # class is a singleton. 0185 self.command_obj = {} 0186 0187 # 'have_run' maps command names to boolean values; it keeps track 0188 # of whether we have actually run a particular command, to make it 0189 # cheap to "run" a command whenever we think we might need to -- if 0190 # it's already been done, no need for expensive filesystem 0191 # operations, we just check the 'have_run' dictionary and carry on. 0192 # It's only safe to query 'have_run' for a command class that has 0193 # been instantiated -- a false value will be inserted when the 0194 # command object is created, and replaced with a true value when 0195 # the command is successfully run. Thus it's probably best to use 0196 # '.get()' rather than a straight lookup. 0197 self.have_run = {} 0198 0199 # Now we'll use the attrs dictionary (ultimately, keyword args from 0200 # the setup script) to possibly override any or all of these 0201 # distribution options. 0202 0203 if attrs: 0204 0205 # Pull out the set of command options and work on them 0206 # specifically. Note that this order guarantees that aliased 0207 # command options will override any supplied redundantly 0208 # through the general options dictionary. 0209 options = attrs.get('options') 0210 if options: 0211 del attrs['options'] 0212 for (command, cmd_options) in options.items(): 0213 opt_dict = self.get_option_dict(command) 0214 for (opt, val) in cmd_options.items(): 0215 opt_dict[opt] = ("setup script", val) 0216 0217 if attrs.has_key('licence'): 0218 attrs['license'] = attrs['licence'] 0219 del attrs['licence'] 0220 msg = "'licence' distribution option is deprecated; use 'license'" 0221 if warnings is not None: 0222 warnings.warn(msg) 0223 else: 0224 sys.stderr.write(msg + "\n") 0225 0226 # Now work on the rest of the attributes. Any attribute that's 0227 # not already defined is invalid! 0228 for (key,val) in attrs.items(): 0229 if hasattr(self.metadata, key): 0230 setattr(self.metadata, key, val) 0231 elif hasattr(self, key): 0232 setattr(self, key, val) 0233 else: 0234 msg = "Unknown distribution option: %s" % repr(key) 0235 if warnings is not None: 0236 warnings.warn(msg) 0237 else: 0238 sys.stderr.write(msg + "\n") 0239 0240 self.finalize_options() 0241 0242 # __init__ () 0243 0244 0245 def get_option_dict (self, command): 0246 """Get the option dictionary for a given command. If that 0247 command's option dictionary hasn't been created yet, then create it 0248 and return the new dictionary; otherwise, return the existing 0249 option dictionary. 0250 """ 0251 0252 dict = self.command_options.get(command) 0253 if dict is None: 0254 dict = self.command_options[command] = {} 0255 return dict 0256 0257 0258 def dump_option_dicts (self, header=None, commands=None, indent=""): 0259 from pprint import pformat 0260 0261 if commands is None: # dump all command option dicts 0262 commands = self.command_options.keys() 0263 commands.sort() 0264 0265 if header is not None: 0266 print indent + header 0267 indent = indent + " " 0268 0269 if not commands: 0270 print indent + "no commands known yet" 0271 return 0272 0273 for cmd_name in commands: 0274 opt_dict = self.command_options.get(cmd_name) 0275 if opt_dict is None: 0276 print indent + "no option dict for '%s' command" % cmd_name 0277 else: 0278 print indent + "option dict for '%s' command:" % cmd_name 0279 out = pformat(opt_dict) 0280 for line in string.split(out, "\n"): 0281 print indent + " " + line 0282 0283 # dump_option_dicts () 0284 0285 0286 0287 # -- Config file finding/parsing methods --------------------------- 0288 0289 def find_config_files (self): 0290 """Find as many configuration files as should be processed for this 0291 platform, and return a list of filenames in the order in which they 0292 should be parsed. The filenames returned are guaranteed to exist 0293 (modulo nasty race conditions). 0294 0295 There are three possible config files: distutils.cfg in the 0296 Distutils installation directory (ie. where the top-level 0297 Distutils __inst__.py file lives), a file in the user's home 0298 directory named .pydistutils.cfg on Unix and pydistutils.cfg 0299 on Windows/Mac, and setup.cfg in the current directory. 0300 """ 0301 files = [] 0302 check_environ() 0303 0304 # Where to look for the system-wide Distutils config file 0305 sys_dir = os.path.dirname(sys.modules['distutils'].__file__) 0306 0307 # Look for the system config file 0308 sys_file = os.path.join(sys_dir, "distutils.cfg") 0309 if os.path.isfile(sys_file): 0310 files.append(sys_file) 0311 0312 # What to call the per-user config file 0313 if os.name == 'posix': 0314 user_filename = ".pydistutils.cfg" 0315 else: 0316 user_filename = "pydistutils.cfg" 0317 0318 # And look for the user config file 0319 if os.environ.has_key('HOME'): 0320 user_file = os.path.join(os.environ.get('HOME'), user_filename) 0321 if os.path.isfile(user_file): 0322 files.append(user_file) 0323 0324 # All platforms support local setup.cfg 0325 local_file = "setup.cfg" 0326 if os.path.isfile(local_file): 0327 files.append(local_file) 0328 0329 return files 0330 0331 # find_config_files () 0332 0333 0334 def parse_config_files (self, filenames=None): 0335 0336 from ConfigParser import ConfigParser 0337 0338 if filenames is None: 0339 filenames = self.find_config_files() 0340 0341 if DEBUG: print "Distribution.parse_config_files():" 0342 0343 parser = ConfigParser() 0344 for filename in filenames: 0345 if DEBUG: print " reading", filename 0346 parser.read(filename) 0347 for section in parser.sections(): 0348 options = parser.options(section) 0349 opt_dict = self.get_option_dict(section) 0350 0351 for opt in options: 0352 if opt != '__name__': 0353 val = parser.get(section,opt) 0354 opt = string.replace(opt, '-', '_') 0355 opt_dict[opt] = (filename, val) 0356 0357 # Make the ConfigParser forget everything (so we retain 0358 # the original filenames that options come from) 0359 parser.__init__() 0360 0361 # If there was a "global" section in the config file, use it 0362 # to set Distribution options. 0363 0364 if self.command_options.has_key('global'): 0365 for (opt, (src, val)) in self.command_options['global'].items(): 0366 alias = self.negative_opt.get(opt) 0367 try: 0368 if alias: 0369 setattr(self, alias, not strtobool(val)) 0370 elif opt in ('verbose', 'dry_run'): # ugh! 0371 setattr(self, opt, strtobool(val)) 0372 else: 0373 setattr(self, opt, val) 0374 except ValueError, msg: 0375 raise DistutilsOptionError, msg 0376 0377 # parse_config_files () 0378 0379 0380 # -- Command-line parsing methods ---------------------------------- 0381 0382 def parse_command_line (self): 0383 """Parse the setup script's command line, taken from the 0384 'script_args' instance attribute (which defaults to 'sys.argv[1:]' 0385 -- see 'setup()' in core.py). This list is first processed for 0386 "global options" -- options that set attributes of the Distribution 0387 instance. Then, it is alternately scanned for Distutils commands 0388 and options for that command. Each new command terminates the 0389 options for the previous command. The allowed options for a 0390 command are determined by the 'user_options' attribute of the 0391 command class -- thus, we have to be able to load command classes 0392 in order to parse the command line. Any error in that 'options' 0393 attribute raises DistutilsGetoptError; any error on the 0394 command-line raises DistutilsArgError. If no Distutils commands 0395 were found on the command line, raises DistutilsArgError. Return 0396 true if command-line was successfully parsed and we should carry 0397 on with executing commands; false if no errors but we shouldn't 0398 execute commands (currently, this only happens if user asks for 0399 help). 0400 """ 0401 # 0402 # We now have enough information to show the Macintosh dialog 0403 # that allows the user to interactively specify the "command line". 0404 # 0405 toplevel_options = self._get_toplevel_options() 0406 if sys.platform == 'mac': 0407 import EasyDialogs 0408 cmdlist = self.get_command_list() 0409 self.script_args = EasyDialogs.GetArgv( 0410 toplevel_options + self.display_options, cmdlist) 0411 0412 # We have to parse the command line a bit at a time -- global 0413 # options, then the first command, then its options, and so on -- 0414 # because each command will be handled by a different class, and 0415 # the options that are valid for a particular class aren't known 0416 # until we have loaded the command class, which doesn't happen 0417 # until we know what the command is. 0418 0419 self.commands = [] 0420 parser = FancyGetopt(toplevel_options + self.display_options) 0421 parser.set_negative_aliases(self.negative_opt) 0422 parser.set_aliases({'licence': 'license'}) 0423 args = parser.getopt(args=self.script_args, object=self) 0424 option_order = parser.get_option_order() 0425 log.set_verbosity(self.verbose) 0426 0427 # for display options we return immediately 0428 if self.handle_display_options(option_order): 0429 return 0430 0431 while args: 0432 args = self._parse_command_opts(parser, args) 0433 if args is None: # user asked for help (and got it) 0434 return 0435 0436 # Handle the cases of --help as a "global" option, ie. 0437 # "setup.py --help" and "setup.py --help command ...". For the 0438 # former, we show global options (--verbose, --dry-run, etc.) 0439 # and display-only options (--name, --version, etc.); for the 0440 # latter, we omit the display-only options and show help for 0441 # each command listed on the command line. 0442 if self.help: 0443 self._show_help(parser, 0444 display_options=len(self.commands) == 0, 0445 commands=self.commands) 0446 return 0447 0448 # Oops, no commands found -- an end-user error 0449 if not self.commands: 0450 raise DistutilsArgError, "no commands supplied" 0451 0452 # All is well: return true 0453 return 1 0454 0455 # parse_command_line() 0456 0457 def _get_toplevel_options (self): 0458 """Return the non-display options recognized at the top level. 0459 0460 This includes options that are recognized *only* at the top 0461 level as well as options recognized for commands. 0462 """ 0463 return self.global_options + [ 0464 ("command-packages=", None, 0465 "list of packages that provide distutils commands"), 0466 ] 0467 0468 def _parse_command_opts (self, parser, args): 0469 """Parse the command-line options for a single command. 0470 'parser' must be a FancyGetopt instance; 'args' must be the list 0471 of arguments, starting with the current command (whose options 0472 we are about to parse). Returns a new version of 'args' with 0473 the next command at the front of the list; will be the empty 0474 list if there are no more commands on the command line. Returns 0475 None if the user asked for help on this command. 0476 """ 0477 # late import because of mutual dependence between these modules 0478 from distutils.cmd import Command 0479 0480 # Pull the current command from the head of the command line 0481 command = args[0] 0482 if not command_re.match(command): 0483 raise SystemExit, "invalid command name '%s'" % command 0484 self.commands.append(command) 0485 0486 # Dig up the command class that implements this command, so we 0487 # 1) know that it's a valid command, and 2) know which options 0488 # it takes. 0489 try: 0490 cmd_class = self.get_command_class(command) 0491 except DistutilsModuleError, msg: 0492 raise DistutilsArgError, msg 0493 0494 # Require that the command class be derived from Command -- want 0495 # to be sure that the basic "command" interface is implemented. 0496 if not issubclass(cmd_class, Command): 0497 raise DistutilsClassError, \ 0498 "command class %s must subclass Command" % cmd_class 0499 0500 # Also make sure that the command object provides a list of its 0501 # known options. 0502 if not (hasattr(cmd_class, 'user_options') and 0503 type(cmd_class.user_options) is ListType): 0504 raise DistutilsClassError, \ 0505 ("command class %s must provide " + 0506 "'user_options' attribute (a list of tuples)") % \ 0507 cmd_class 0508 0509 # If the command class has a list of negative alias options, 0510 # merge it in with the global negative aliases. 0511 negative_opt = self.negative_opt 0512 if hasattr(cmd_class, 'negative_opt'): 0513 negative_opt = copy(negative_opt) 0514 negative_opt.update(cmd_class.negative_opt) 0515 0516 # Check for help_options in command class. They have a different 0517 # format (tuple of four) so we need to preprocess them here. 0518 if (hasattr(cmd_class, 'help_options') and 0519 type(cmd_class.help_options) is ListType): 0520 help_options = fix_help_options(cmd_class.help_options) 0521 else: 0522 help_options = [] 0523 0524 0525 # All commands support the global options too, just by adding 0526 # in 'global_options'. 0527 parser.set_option_table(self.global_options + 0528 cmd_class.user_options + 0529 help_options) 0530 parser.set_negative_aliases(negative_opt) 0531 (args, opts) = parser.getopt(args[1:]) 0532 if hasattr(opts, 'help') and opts.help: 0533 self._show_help(parser, display_options=0, commands=[cmd_class]) 0534 return 0535 0536 if (hasattr(cmd_class, 'help_options') and 0537 type(cmd_class.help_options) is ListType): 0538 help_option_found=0 0539 for (help_option, short, desc, func) in cmd_class.help_options: 0540 if hasattr(opts, parser.get_attr_name(help_option)): 0541 help_option_found=1 0542 #print "showing help for option %s of command %s" % \ 0543 # (help_option[0],cmd_class) 0544 0545 if callable(func): 0546 func() 0547 else: 0548 raise DistutilsClassError( 0549 "invalid help function %r for help option '%s': " 0550 "must be a callable object (function, etc.)" 0551 % (func, help_option)) 0552 0553 if help_option_found: 0554 return 0555 0556 # Put the options from the command-line into their official 0557 # holding pen, the 'command_options' dictionary. 0558 opt_dict = self.get_option_dict(command) 0559 for (name, value) in vars(opts).items(): 0560 opt_dict[name] = ("command line", value) 0561 0562 return args 0563 0564 # _parse_command_opts () 0565 0566 def finalize_options (self): 0567 """Set final values for all the options on the Distribution 0568 instance, analogous to the .finalize_options() method of Command 0569 objects. 0570 """ 0571 0572 keywords = self.metadata.keywords 0573 if keywords is not None: 0574 if type(keywords) is StringType: 0575 keywordlist = string.split(keywords, ',') 0576 self.metadata.keywords = map(string.strip, keywordlist) 0577 0578 platforms = self.metadata.platforms 0579 if platforms is not None: 0580 if type(platforms) is StringType: 0581 platformlist = string.split(platforms, ',') 0582 self.metadata.platforms = map(string.strip, platformlist) 0583 0584 def _show_help (self, 0585 parser, 0586 global_options=1, 0587 display_options=1, 0588 commands=[]): 0589 """Show help for the setup script command-line in the form of 0590 several lists of command-line options. 'parser' should be a 0591 FancyGetopt instance; do not expect it to be returned in the 0592 same state, as its option table will be reset to make it 0593 generate the correct help text. 0594 0595 If 'global_options' is true, lists the global options: 0596 --verbose, --dry-run, etc. If 'display_options' is true, lists 0597 the "display-only" options: --name, --version, etc. Finally, 0598 lists per-command help for every command name or command class 0599 in 'commands'. 0600 """ 0601 # late import because of mutual dependence between these modules 0602 from distutils.core import gen_usage 0603 from distutils.cmd import Command 0604 0605 if global_options: 0606 if display_options: 0607 options = self._get_toplevel_options() 0608 else: 0609 options = self.global_options 0610 parser.set_option_table(options) 0611 parser.print_help("Global options:") 0612 print 0613 0614 if display_options: 0615 parser.set_option_table(self.display_options) 0616 parser.print_help( 0617 "Information display options (just display " + 0618 "information, ignore any commands)") 0619 print 0620 0621 for command in self.commands: 0622 if type(command) is ClassType and issubclass(command, Command): 0623 klass = command 0624 else: 0625 klass = self.get_command_class(command) 0626 if (hasattr(klass, 'help_options') and 0627 type(klass.help_options) is ListType): 0628 parser.set_option_table(klass.user_options + 0629 fix_help_options(klass.help_options)) 0630 else: 0631 parser.set_option_table(klass.user_options) 0632 parser.print_help("Options for '%s' command:" % klass.__name__) 0633 print 0634 0635 print gen_usage(self.script_name) 0636 return 0637 0638 # _show_help () 0639 0640 0641 def handle_display_options (self, option_order): 0642 """If there were any non-global "display-only" options 0643 (--help-commands or the metadata display options) on the command 0644 line, display the requested info and return true; else return 0645 false. 0646 """ 0647 from distutils.core import gen_usage 0648 0649 # User just wants a list of commands -- we'll print it out and stop 0650 # processing now (ie. if they ran "setup --help-commands foo bar", 0651 # we ignore "foo bar"). 0652 if self.help_commands: 0653 self.print_commands() 0654 print 0655 print gen_usage(self.script_name) 0656 return 1 0657 0658 # If user supplied any of the "display metadata" options, then 0659 # display that metadata in the order in which the user supplied the 0660 # metadata options. 0661 any_display_options = 0 0662 is_display_option = {} 0663 for option in self.display_options: 0664 is_display_option[option[0]] = 1 0665 0666 for (opt, val) in option_order: 0667 if val and is_display_option.get(opt): 0668 opt = translate_longopt(opt) 0669 value = getattr(self.metadata, "get_"+opt)() 0670 if opt in ['keywords', 'platforms']: 0671 print string.join(value, ',') 0672 elif opt == 'classifiers': 0673 print string.join(value, '\n') 0674 else: 0675 print value 0676 any_display_options = 1 0677 0678 return any_display_options 0679 0680 # handle_display_options() 0681 0682 def print_command_list (self, commands, header, max_length): 0683 """Print a subset of the list of all commands -- used by 0684 'print_commands()'. 0685 """ 0686 0687 print header + ":" 0688 0689 for cmd in commands: 0690 klass = self.cmdclass.get(cmd) 0691 if not klass: 0692 klass = self.get_command_class(cmd) 0693 try: 0694 description = klass.description 0695 except AttributeError: 0696 description = "(no description available)" 0697 0698 print " %-*s %s" % (max_length, cmd, description) 0699 0700 # print_command_list () 0701 0702 0703 def print_commands (self): 0704 """Print out a help message listing all available commands with a 0705 description of each. The list is divided into "standard commands" 0706 (listed in distutils.command.__all__) and "extra commands" 0707 (mentioned in self.cmdclass, but not a standard command). The 0708 descriptions come from the command class attribute 0709 'description'. 0710 """ 0711 0712 import distutils.command 0713 std_commands = distutils.command.__all__ 0714 is_std = {} 0715 for cmd in std_commands: 0716 is_std[cmd] = 1 0717 0718 extra_commands = [] 0719 for cmd in self.cmdclass.keys(): 0720 if not is_std.get(cmd): 0721 extra_commands.append(cmd) 0722 0723 max_length = 0 0724 for cmd in (std_commands + extra_commands): 0725 if len(cmd) > max_length: 0726 max_length = len(cmd) 0727 0728 self.print_command_list(std_commands, 0729 "Standard commands", 0730 max_length) 0731 if extra_commands: 0732 print 0733 self.print_command_list(extra_commands, 0734 "Extra commands", 0735 max_length) 0736 0737 # print_commands () 0738 0739 def get_command_list (self): 0740 """Get a list of (command, description) tuples. 0741 The list is divided into "standard commands" (listed in 0742 distutils.command.__all__) and "extra commands" (mentioned in 0743 self.cmdclass, but not a standard command). The descriptions come 0744 from the command class attribute 'description'. 0745 """ 0746 # Currently this is only used on Mac OS, for the Mac-only GUI 0747 # Distutils interface (by Jack Jansen) 0748 0749 import distutils.command 0750 std_commands = distutils.command.__all__ 0751 is_std = {} 0752 for cmd in std_commands: 0753 is_std[cmd] = 1 0754 0755 extra_commands = [] 0756 for cmd in self.cmdclass.keys(): 0757 if not is_std.get(cmd): 0758 extra_commands.append(cmd) 0759 0760 rv = [] 0761 for cmd in (std_commands + extra_commands): 0762 klass = self.cmdclass.get(cmd) 0763 if not klass: 0764 klass = self.get_command_class(cmd) 0765 try: 0766 description = klass.description 0767 except AttributeError: 0768 description = "(no description available)" 0769 rv.append((cmd, description)) 0770 return rv 0771 0772 # -- Command class/object methods ---------------------------------- 0773 0774 def get_command_packages (self): 0775 """Return a list of packages from which commands are loaded.""" 0776 pkgs = self.command_packages 0777 if not isinstance(pkgs, type([])): 0778 pkgs = string.split(pkgs or "", ",") 0779 for i in range(len(pkgs)): 0780 pkgs[i] = string.strip(pkgs[i]) 0781 pkgs = filter(None, pkgs) 0782 if "distutils.command" not in pkgs: 0783 pkgs.insert(0, "distutils.command") 0784 self.command_packages = pkgs 0785 return pkgs 0786 0787 def get_command_class (self, command): 0788 """Return the class that implements the Distutils command named by 0789 'command'. First we check the 'cmdclass' dictionary; if the 0790 command is mentioned there, we fetch the class object from the 0791 dictionary and return it. Otherwise we load the command module 0792 ("distutils.command." + command) and fetch the command class from 0793 the module. The loaded class is also stored in 'cmdclass' 0794 to speed future calls to 'get_command_class()'. 0795 0796 Raises DistutilsModuleError if the expected module could not be 0797 found, or if that module does not define the expected class. 0798 """ 0799 klass = self.cmdclass.get(command) 0800 if klass: 0801 return klass 0802 0803 for pkgname in self.get_command_packages(): 0804 module_name = "%s.%s" % (pkgname, command) 0805 klass_name = command 0806 0807 try: 0808 __import__ (module_name) 0809 module = sys.modules[module_name] 0810 except ImportError: 0811 continue 0812 0813 try: 0814 klass = getattr(module, klass_name) 0815 except AttributeError: 0816 raise DistutilsModuleError, \ 0817 "invalid command '%s' (no class '%s' in module '%s')" \ 0818 % (command, klass_name, module_name) 0819 0820 self.cmdclass[command] = klass 0821 return klass 0822 0823 raise DistutilsModuleError("invalid command '%s'" % command) 0824 0825 0826 # get_command_class () 0827 0828 def get_command_obj (self, command, create=1): 0829 """Return the command object for 'command'. Normally this object 0830 is cached on a previous call to 'get_command_obj()'; if no command 0831 object for 'command' is in the cache, then we either create and 0832 return it (if 'create' is true) or return None. 0833 """ 0834 cmd_obj = self.command_obj.get(command) 0835 if not cmd_obj and create: 0836 if DEBUG: 0837 print "Distribution.get_command_obj(): " \ 0838 "creating '%s' command object" % command 0839 0840 klass = self.get_command_class(command) 0841 cmd_obj = self.command_obj[command] = klass(self) 0842 self.have_run[command] = 0 0843 0844 # Set any options that were supplied in config files 0845 # or on the command line. (NB. support for error 0846 # reporting is lame here: any errors aren't reported 0847 # until 'finalize_options()' is called, which means 0848 # we won't report the source of the error.) 0849 options = self.command_options.get(command) 0850 if options: 0851 self._set_command_options(cmd_obj, options) 0852 0853 return cmd_obj 0854 0855 def _set_command_options (self, command_obj, option_dict=None): 0856 """Set the options for 'command_obj' from 'option_dict'. Basically 0857 this means copying elements of a dictionary ('option_dict') to 0858 attributes of an instance ('command'). 0859 0860 'command_obj' must be a Command instance. If 'option_dict' is not 0861 supplied, uses the standard option dictionary for this command 0862 (from 'self.command_options'). 0863 """ 0864 command_name = command_obj.get_command_name() 0865 if option_dict is None: 0866 option_dict = self.get_option_dict(command_name) 0867 0868 if DEBUG: print " setting options for '%s' command:" % command_name 0869 for (option, (source, value)) in option_dict.items(): 0870 if DEBUG: print " %s = %s (from %s)" % (option, value, source) 0871 try: 0872 bool_opts = map(translate_longopt, command_obj.boolean_options) 0873 except AttributeError: 0874 bool_opts = [] 0875 try: 0876 neg_opt = command_obj.negative_opt 0877 except AttributeError: 0878 neg_opt = {} 0879 0880 try: 0881 is_string = type(value) is StringType 0882 if neg_opt.has_key(option) and is_string: 0883 setattr(command_obj, neg_opt[option], not strtobool(value)) 0884 elif option in bool_opts and is_string: 0885 setattr(command_obj, option, strtobool(value)) 0886 elif hasattr(command_obj, option): 0887 setattr(command_obj, option, value) 0888 else: 0889 raise DistutilsOptionError, \ 0890 ("error in %s: command '%s' has no such option '%s'" 0891 % (source, command_name, option)) 0892 except ValueError, msg: 0893 raise DistutilsOptionError, msg 0894 0895 def reinitialize_command (self, command, reinit_subcommands=0): 0896 """Reinitializes a command to the state it was in when first 0897 returned by 'get_command_obj()': ie., initialized but not yet 0898 finalized. This provides the opportunity to sneak option 0899 values in programmatically, overriding or supplementing 0900 user-supplied values from the config files and command line. 0901 You'll have to re-finalize the command object (by calling 0902 'finalize_options()' or 'ensure_finalized()') before using it for 0903 real. 0904 0905 'command' should be a command name (string) or command object. If 0906 'reinit_subcommands' is true, also reinitializes the command's 0907 sub-commands, as declared by the 'sub_commands' class attribute (if 0908 it has one). See the "install" command for an example. Only 0909 reinitializes the sub-commands that actually matter, ie. those 0910 whose test predicates return true. 0911 0912 Returns the reinitialized command object. 0913 """ 0914 from distutils.cmd import Command 0915 if not isinstance(command, Command): 0916 command_name = command 0917 command = self.get_command_obj(command_name) 0918 else: 0919 command_name = command.get_command_name() 0920 0921 if not command.finalized: 0922 return command 0923 command.initialize_options() 0924 command.finalized = 0 0925 self.have_run[command_name] = 0 0926 self._set_command_options(command) 0927 0928 if reinit_subcommands: 0929 for sub in command.get_sub_commands(): 0930 self.reinitialize_command(sub, reinit_subcommands) 0931 0932 return command 0933 0934 0935 # -- Methods that operate on the Distribution ---------------------- 0936 0937 def announce (self, msg, level=1): 0938 log.debug(msg) 0939 0940 def run_commands (self): 0941 """Run each command that was seen on the setup script command line. 0942 Uses the list of commands found and cache of command objects 0943 created by 'get_command_obj()'. 0944 """ 0945 for cmd in self.commands: 0946 self.run_command(cmd) 0947 0948 0949 # -- Methods that operate on its Commands -------------------------- 0950 0951 def run_command (self, command): 0952 """Do whatever it takes to run a command (including nothing at all, 0953 if the command has already been run). Specifically: if we have 0954 already created and run the command named by 'command', return 0955 silently without doing anything. If the command named by 'command' 0956 doesn't even have a command object yet, create one. Then invoke 0957 'run()' on that command object (or an existing one). 0958 """ 0959 # Already been here, done that? then return silently. 0960 if self.have_run.get(command): 0961 return 0962 0963 log.info("running %s", command) 0964 cmd_obj = self.get_command_obj(command) 0965 cmd_obj.ensure_finalized() 0966 cmd_obj.run() 0967 self.have_run[command] = 1 0968 0969 0970 # -- Distribution query methods ------------------------------------ 0971 0972 def has_pure_modules (self): 0973 return len(self.packages or self.py_modules or []) > 0 0974 0975 def has_ext_modules (self): 0976 return self.ext_modules and len(self.ext_modules) > 0 0977 0978 def has_c_libraries (self): 0979 return self.libraries and len(self.libraries) > 0 0980 0981 def has_modules (self): 0982 return self.has_pure_modules() or self.has_ext_modules() 0983 0984 def has_headers (self): 0985 return self.headers and len(self.headers) > 0 0986 0987 def has_scripts (self): 0988 return self.scripts and len(self.scripts) > 0 0989 0990 def has_data_files (self): 0991 return self.data_files and len(self.data_files) > 0 0992 0993 def is_pure (self): 0994 return (self.has_pure_modules() and 0995 not self.has_ext_modules() and 0996 not self.has_c_libraries()) 0997 0998 # -- Metadata query methods ---------------------------------------- 0999 1000 # If you're looking for 'get_name()', 'get_version()', and so forth, 1001 # they are defined in a sneaky way: the constructor binds self.get_XXX 1002 # to self.metadata.get_XXX. The actual code is in the 1003 # DistributionMetadata class, below. 1004 1005 # class Distribution 1006 1007 1008 class DistributionMetadata: 1009 """Dummy class to hold the distribution meta-data: name, version, 1010 author, and so forth. 1011 """ 1012 1013 _METHOD_BASENAMES = ("name", "version", "author", "author_email", 1014 "maintainer", "maintainer_email", "url", 1015 "license", "description", "long_description", 1016 "keywords", "platforms", "fullname", "contact", 1017 "contact_email", "license", "classifiers", 1018 "download_url") 1019 1020 def __init__ (self): 1021 self.name = None 1022 self.version = None 1023 self.author = None 1024 self.author_email = None 1025 self.maintainer = None 1026 self.maintainer_email = None 1027 self.url = None 1028 self.license = None 1029 self.description = None 1030 self.long_description = None 1031 self.keywords = None 1032 self.platforms = None 1033 self.classifiers = None 1034 self.download_url = None 1035 1036 def write_pkg_info (self, base_dir): 1037 """Write the PKG-INFO file into the release tree. 1038 """ 1039 1040 pkg_info = open( os.path.join(base_dir, 'PKG-INFO'), 'w') 1041 1042 pkg_info.write('Metadata-Version: 1.0\n') 1043 pkg_info.write('Name: %s\n' % self.get_name() ) 1044 pkg_info.write('Version: %s\n' % self.get_version() ) 1045 pkg_info.write('Summary: %s\n' % self.get_description() ) 1046 pkg_info.write('Home-page: %s\n' % self.get_url() ) 1047 pkg_info.write('Author: %s\n' % self.get_contact() ) 1048 pkg_info.write('Author-email: %s\n' % self.get_contact_email() ) 1049 pkg_info.write('License: %s\n' % self.get_license() ) 1050 if self.download_url: 1051 pkg_info.write('Download-URL: %s\n' % self.download_url) 1052 1053 long_desc = rfc822_escape( self.get_long_description() ) 1054 pkg_info.write('Description: %s\n' % long_desc) 1055 1056 keywords = string.join( self.get_keywords(), ',') 1057 if keywords: 1058 pkg_info.write('Keywords: %s\n' % keywords ) 1059 1060 for platform in self.get_platforms(): 1061 pkg_info.write('Platform: %s\n' % platform ) 1062 1063 for classifier in self.get_classifiers(): 1064 pkg_info.write('Classifier: %s\n' % classifier ) 1065 1066 pkg_info.close() 1067 1068 # write_pkg_info () 1069 1070 # -- Metadata query methods ---------------------------------------- 1071 1072 def get_name (self): 1073 return self.name or "UNKNOWN" 1074 1075 def get_version(self): 1076 return self.version or "0.0.0" 1077 1078 def get_fullname (self): 1079 return "%s-%s" % (self.get_name(), self.get_version()) 1080 1081 def get_author(self): 1082 return self.author or "UNKNOWN" 1083 1084 def get_author_email(self): 1085 return self.author_email or "UNKNOWN" 1086 1087 def get_maintainer(self): 1088 return self.maintainer or "UNKNOWN" 1089 1090 def get_maintainer_email(self): 1091 return self.maintainer_email or "UNKNOWN" 1092 1093 def get_contact(self): 1094 return (self.maintainer or 1095 self.author or 1096 "UNKNOWN") 1097 1098 def get_contact_email(self): 1099 return (self.maintainer_email or 1100 self.author_email or 1101 "UNKNOWN") 1102 1103 def get_url(self): 1104 return self.url or "UNKNOWN" 1105 1106 def get_license(self): 1107 return self.license or "UNKNOWN" 1108 get_licence = get_license 1109 1110 def get_description(self): 1111 return self.description or "UNKNOWN" 1112 1113 def get_long_description(self): 1114 return self.long_description or "UNKNOWN" 1115 1116 def get_keywords(self): 1117 return self.keywords or [] 1118 1119 def get_platforms(self): 1120 return self.platforms or ["UNKNOWN"] 1121 1122 def get_classifiers(self): 1123 return self.classifiers or [] 1124 1125 def get_download_url(self): 1126 return self.download_url or "UNKNOWN" 1127 1128 # class DistributionMetadata 1129 1130 1131 def fix_help_options (options): 1132 """Convert a 4-tuple 'help_options' list as found in various command 1133 classes to the 3-tuple form required by FancyGetopt. 1134 """ 1135 new_options = [] 1136 for help_tuple in options: 1137 new_options.append(help_tuple[0:3]) 1138 return new_options 1139 1140 1141 if __name__ == "__main__": 1142 dist = Distribution() 1143 print "ok" 1144
Generated by PyXR 0.9.4