1 """distutils.dist 2 3 Provides the Distribution class, which represents the module distribution 4 being built/installed/distributed. 5 """ 6 7 import sys 8 import os 9 import re 10 from email import message_from_file 11 12 try: 13 import warnings 14 except ImportError: 15 warnings = None 16 17 from distutils.errors import * 18 from distutils.fancy_getopt import FancyGetopt, translate_longopt 19 from distutils.util import check_environ, strtobool, rfc822_escape 20 from distutils import log 21 from 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. 27 command_re = re.compile(r'^[a-zA-Z]([a-zA-Z0-9_]*)$') 28 29 30 class 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 = """\ 64 Common 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 1012 class 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 1229 def 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