blob: 03b20e1f570cd5c812db4f8f3ec6ec81a346a6cc [file] [log] [blame]
Greg Wardfe6462c2000-04-04 01:40:52 +00001"""distutils.dist
2
3Provides the Distribution class, which represents the module distribution
4being built/installed/distributed."""
5
6# created 2000/04/03, Greg Ward
7# (extricated from core.py; actually dates back to the beginning)
8
9__revision__ = "$Id$"
10
Gregory P. Smith14263542000-05-12 00:41:33 +000011import sys, os, string, re
Greg Wardfe6462c2000-04-04 01:40:52 +000012from types import *
13from copy import copy
14from distutils.errors import *
Greg Ward36c36fe2000-05-20 14:07:59 +000015from distutils import sysconfig
Greg Ward82715e12000-04-21 02:28:14 +000016from distutils.fancy_getopt import FancyGetopt, longopt_xlate
Gregory P. Smith14263542000-05-12 00:41:33 +000017from distutils.util import check_environ
Greg Wardfe6462c2000-04-04 01:40:52 +000018
19
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.
24command_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$')
25
26
27class Distribution:
28 """The core of the Distutils. Most of the work hiding behind
29 'setup' is really done within a Distribution instance, which
30 farms the work out to the Distutils commands specified on the
31 command line.
32
33 Clients will almost never instantiate Distribution directly,
34 unless the 'setup' function is totally inadequate to their needs.
35 However, it is conceivable that a client might wish to subclass
36 Distribution for some specialized purpose, and then pass the
37 subclass to 'setup' as the 'distclass' keyword argument. If so,
38 it is necessary to respect the expectations that 'setup' has of
39 Distribution: it must have a constructor and methods
40 'parse_command_line()' and 'run_commands()' with signatures like
41 those described below."""
42
43
44 # 'global_options' describes the command-line options that may be
Greg Ward82715e12000-04-21 02:28:14 +000045 # supplied to the setup script prior to any actual commands.
46 # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of
Greg Wardfe6462c2000-04-04 01:40:52 +000047 # 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 global_options = [('verbose', 'v',
52 "run verbosely (default)"),
53 ('quiet', 'q',
54 "run quietly (turns verbosity off)"),
55 ('dry-run', 'n',
56 "don't actually do anything"),
Greg Wardfe6462c2000-04-04 01:40:52 +000057 ('help', 'h',
Greg Ward82715e12000-04-21 02:28:14 +000058 "show this help message, plus help for any commands " +
59 "given on the command-line"),
Greg Wardfe6462c2000-04-04 01:40:52 +000060 ]
Greg Ward82715e12000-04-21 02:28:14 +000061
62 # options that are not propagated to the commands
63 display_options = [
64 ('help-commands', None,
65 "list all available commands"),
66 ('name', None,
67 "print package name"),
68 ('version', 'V',
69 "print package version"),
70 ('fullname', None,
71 "print <package name>-<version>"),
72 ('author', None,
73 "print the author's name"),
74 ('author-email', None,
75 "print the author's email address"),
76 ('maintainer', None,
77 "print the maintainer's name"),
78 ('maintainer-email', None,
79 "print the maintainer's email address"),
80 ('contact', None,
81 "print the name of the maintainer if present, "
82 "else author"),
83 ('contact-email', None,
84 "print the email of the maintainer if present, "
85 "else author"),
86 ('url', None,
87 "print the URL for this package"),
88 ('licence', None,
89 "print the licence of the package"),
90 ('license', None,
91 "alias for --licence"),
92 ('description', None,
93 "print the package description"),
Greg Warde5a584e2000-04-26 02:26:55 +000094 ('long-description', None,
95 "print the long package description"),
Greg Ward82715e12000-04-21 02:28:14 +000096 ]
97 display_option_names = map(lambda x: string.translate(x[0], longopt_xlate),
98 display_options)
99
100 # negative options are options that exclude other options
Greg Wardfe6462c2000-04-04 01:40:52 +0000101 negative_opt = {'quiet': 'verbose'}
102
103
104 # -- Creation/initialization methods -------------------------------
105
106 def __init__ (self, attrs=None):
107 """Construct a new Distribution instance: initialize all the
108 attributes of a Distribution, and then uses 'attrs' (a
109 dictionary mapping attribute names to values) to assign
110 some of those attributes their "real" values. (Any attributes
111 not mentioned in 'attrs' will be assigned to some null
112 value: 0, None, an empty list or dictionary, etc.) Most
113 importantly, initialize the 'command_obj' attribute
114 to the empty dictionary; this will be filled in with real
115 command objects by 'parse_command_line()'."""
116
117 # Default values for our command-line options
118 self.verbose = 1
119 self.dry_run = 0
Greg Wardfe6462c2000-04-04 01:40:52 +0000120 self.help = 0
Greg Ward82715e12000-04-21 02:28:14 +0000121 for attr in self.display_option_names:
122 setattr(self, attr, 0)
Greg Wardfe6462c2000-04-04 01:40:52 +0000123
Greg Ward82715e12000-04-21 02:28:14 +0000124 # Store the distribution meta-data (name, version, author, and so
125 # forth) in a separate object -- we're getting to have enough
126 # information here (and enough command-line options) that it's
127 # worth it. Also delegate 'get_XXX()' methods to the 'metadata'
128 # object in a sneaky and underhanded (but efficient!) way.
129 self.metadata = DistributionMetadata ()
Greg Ward4982f982000-04-22 02:52:44 +0000130 method_basenames = dir(self.metadata) + \
131 ['fullname', 'contact', 'contact_email']
132 for basename in method_basenames:
133 method_name = "get_" + basename
134 setattr(self, method_name, getattr(self.metadata, method_name))
Greg Wardfe6462c2000-04-04 01:40:52 +0000135
136 # 'cmdclass' maps command names to class objects, so we
137 # can 1) quickly figure out which class to instantiate when
138 # we need to create a new command object, and 2) have a way
Greg Ward82715e12000-04-21 02:28:14 +0000139 # for the setup script to override command classes
Greg Wardfe6462c2000-04-04 01:40:52 +0000140 self.cmdclass = {}
141
Gregory P. Smith14263542000-05-12 00:41:33 +0000142 # Store options for commands here between parsing them (from config
143 # files, the command-line, etc.) and actually putting them into the
144 # command object that needs them.
145 self.command_options = {}
146
Greg Wardfe6462c2000-04-04 01:40:52 +0000147 # These options are really the business of various commands, rather
148 # than of the Distribution itself. We provide aliases for them in
149 # Distribution as a convenience to the developer.
Greg Wardfe6462c2000-04-04 01:40:52 +0000150 self.packages = None
151 self.package_dir = None
152 self.py_modules = None
153 self.libraries = None
154 self.ext_modules = None
155 self.ext_package = None
156 self.include_dirs = None
157 self.extra_path = None
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000158 self.scripts = None
Gregory P. Smith6a901dd2000-05-13 03:09:50 +0000159 self.data_files = None
Greg Wardfe6462c2000-04-04 01:40:52 +0000160
161 # And now initialize bookkeeping stuff that can't be supplied by
162 # the caller at all. 'command_obj' maps command names to
163 # Command instances -- that's how we enforce that every command
164 # class is a singleton.
165 self.command_obj = {}
166
167 # 'have_run' maps command names to boolean values; it keeps track
168 # of whether we have actually run a particular command, to make it
169 # cheap to "run" a command whenever we think we might need to -- if
170 # it's already been done, no need for expensive filesystem
171 # operations, we just check the 'have_run' dictionary and carry on.
172 # It's only safe to query 'have_run' for a command class that has
173 # been instantiated -- a false value will be inserted when the
174 # command object is created, and replaced with a true value when
175 # the command is succesfully run. Thus it's probably best to use
176 # '.get()' rather than a straight lookup.
177 self.have_run = {}
178
179 # Now we'll use the attrs dictionary (ultimately, keyword args from
Greg Ward82715e12000-04-21 02:28:14 +0000180 # the setup script) to possibly override any or all of these
181 # distribution options.
182
Greg Wardfe6462c2000-04-04 01:40:52 +0000183 if attrs:
184
185 # Pull out the set of command options and work on them
186 # specifically. Note that this order guarantees that aliased
187 # command options will override any supplied redundantly
188 # through the general options dictionary.
189 options = attrs.get ('options')
190 if options:
191 del attrs['options']
192 for (command, cmd_options) in options.items():
193 cmd_obj = self.find_command_obj (command)
194 for (key, val) in cmd_options.items():
195 cmd_obj.set_option (key, val)
196 # loop over commands
197 # if any command options
198
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():
Greg Ward82715e12000-04-21 02:28:14 +0000202 if hasattr (self.metadata, key):
203 setattr (self.metadata, key, val)
204 elif hasattr (self, key):
Greg Wardfe6462c2000-04-04 01:40:52 +0000205 setattr (self, key, val)
206 else:
Greg Ward02a1a2b2000-04-15 22:15:07 +0000207 raise DistutilsSetupError, \
Greg Wardfe6462c2000-04-04 01:40:52 +0000208 "invalid distribution option '%s'" % key
209
210 # __init__ ()
211
212
Gregory P. Smith14263542000-05-12 00:41:33 +0000213 def find_config_files (self):
214 """Find as many configuration files as should be processed for this
215 platform, and return a list of filenames in the order in which they
216 should be parsed. The filenames returned are guaranteed to exist
217 (modulo nasty race conditions).
218
219 On Unix, there are three possible config files: pydistutils.cfg in
220 the Distutils installation directory (ie. where the top-level
221 Distutils __inst__.py file lives), .pydistutils.cfg in the user's
222 home directory, and setup.cfg in the current directory.
223
224 On Windows and Mac OS, there are two possible config files:
225 pydistutils.cfg in the Python installation directory (sys.prefix)
226 and setup.cfg in the current directory."""
227
228 files = []
229 if os.name == "posix":
230 check_environ()
231
232 sys_dir = os.path.dirname(sys.modules['distutils'].__file__)
233 sys_file = os.path.join(sys_dir, "pydistutils.cfg")
234 if os.path.isfile(sys_file):
235 files.append(sys_file)
236
237 user_file = os.path.join(os.environ.get('HOME'),
238 ".pydistutils.cfg")
239 if os.path.isfile(user_file):
240 files.append(user_file)
241
242 else:
243 sys_file = os.path.join (sysconfig.PREFIX, "pydistutils.cfg")
244 if os.path.isfile(sys_file):
245 files.append(sys_file)
246
247 # All platforms support local setup.cfg
248 local_file = "setup.cfg"
249 if os.path.isfile(local_file):
250 files.append(local_file)
251
252 return files
253
254 # find_config_files ()
255
256
257 def parse_config_files (self, filenames=None):
258
259 from ConfigParser import ConfigParser
260
261 if filenames is None:
262 filenames = self.find_config_files()
263
264 parser = ConfigParser()
265 parser.read(filenames)
266 for section in parser.sections():
267 options = parser.options(section)
268 if not self.command_options.has_key(section) is None:
269 self.command_options[section] = {}
270 cmd_opts = self.command_options[section]
271
272 for opt in options:
273 if opt != '__name__':
274 cmd_opts[opt] = parser.get(section,opt)
275
276 from pprint import pprint
277 print "configuration options:"
278 pprint (self.command_options)
279
280
Greg Wardfe6462c2000-04-04 01:40:52 +0000281 def parse_command_line (self, args):
282 """Parse the setup script's command line: set any Distribution
283 attributes tied to command-line options, create all command
284 objects, and set their options from the command-line. 'args'
285 must be a list of command-line arguments, most likely
286 'sys.argv[1:]' (see the 'setup()' function). This list is first
287 processed for "global options" -- options that set attributes of
288 the Distribution instance. Then, it is alternately scanned for
289 Distutils command and options for that command. Each new
290 command terminates the options for the previous command. The
291 allowed options for a command are determined by the 'options'
292 attribute of the command object -- thus, we instantiate (and
293 cache) every command object here, in order to access its
294 'options' attribute. Any error in that 'options' attribute
295 raises DistutilsGetoptError; any error on the command-line
296 raises DistutilsArgError. If no Distutils commands were found
297 on the command line, raises DistutilsArgError. Return true if
298 command-line successfully parsed and we should carry on with
299 executing commands; false if no errors but we shouldn't execute
300 commands (currently, this only happens if user asks for
301 help)."""
302
Greg Ward7d508fe2000-04-06 02:07:41 +0000303 # late import because of mutual dependence between these modules
Greg Wardfe6462c2000-04-04 01:40:52 +0000304 from distutils.cmd import Command
Greg Ward7d508fe2000-04-06 02:07:41 +0000305 from distutils.core import usage
Greg Wardfe6462c2000-04-04 01:40:52 +0000306
307 # We have to parse the command line a bit at a time -- global
308 # options, then the first command, then its options, and so on --
309 # because each command will be handled by a different class, and
310 # the options that are valid for a particular class aren't
311 # known until we instantiate the command class, which doesn't
312 # happen until we know what the command is.
313
314 self.commands = []
Greg Ward82715e12000-04-21 02:28:14 +0000315 parser = FancyGetopt (self.global_options + self.display_options)
316 parser.set_negative_aliases (self.negative_opt)
Greg Ward58ec6ed2000-04-21 04:22:49 +0000317 parser.set_aliases ({'license': 'licence'})
Greg Ward82715e12000-04-21 02:28:14 +0000318 args = parser.getopt (object=self)
319 option_order = parser.get_option_order()
Greg Wardfe6462c2000-04-04 01:40:52 +0000320
Greg Ward82715e12000-04-21 02:28:14 +0000321 # for display options we return immediately
322 if self.handle_display_options(option_order):
Greg Wardfe6462c2000-04-04 01:40:52 +0000323 return
324
325 while args:
326 # Pull the current command from the head of the command line
327 command = args[0]
328 if not command_re.match (command):
329 raise SystemExit, "invalid command name '%s'" % command
330 self.commands.append (command)
331
332 # Make sure we have a command object to put the options into
333 # (this either pulls it out of a cache of command objects,
334 # or finds and instantiates the command class).
335 try:
336 cmd_obj = self.find_command_obj (command)
337 except DistutilsModuleError, msg:
338 raise DistutilsArgError, msg
339
340 # Require that the command class be derived from Command --
Greg Wardc4537ac2000-05-07 15:30:31 +0000341 # want to be sure that the basic "command" interface is
342 # implemented.
Greg Wardfe6462c2000-04-04 01:40:52 +0000343 if not isinstance (cmd_obj, Command):
344 raise DistutilsClassError, \
345 "command class %s must subclass Command" % \
346 cmd_obj.__class__
347
348 # Also make sure that the command object provides a list of its
349 # known options
350 if not (hasattr (cmd_obj, 'user_options') and
351 type (cmd_obj.user_options) is ListType):
352 raise DistutilsClassError, \
353 ("command class %s must provide " +
354 "'user_options' attribute (a list of tuples)") % \
355 cmd_obj.__class__
356
357 # Poof! like magic, all commands support the global
358 # options too, just by adding in 'global_options'.
359 negative_opt = self.negative_opt
360 if hasattr (cmd_obj, 'negative_opt'):
361 negative_opt = copy (negative_opt)
362 negative_opt.update (cmd_obj.negative_opt)
363
Greg Ward82715e12000-04-21 02:28:14 +0000364 parser.set_option_table (self.global_options +
365 cmd_obj.user_options)
366 parser.set_negative_aliases (negative_opt)
367 args = parser.getopt (args[1:], cmd_obj)
Greg Wardfe6462c2000-04-04 01:40:52 +0000368 if cmd_obj.help:
Greg Ward82715e12000-04-21 02:28:14 +0000369 parser.set_option_table (self.global_options)
370 parser.print_help ("Global options:")
Greg Wardfe6462c2000-04-04 01:40:52 +0000371 print
Greg Ward82715e12000-04-21 02:28:14 +0000372
373 parser.set_option_table (cmd_obj.user_options)
374 parser.print_help ("Options for '%s' command:" % command)
Greg Wardfe6462c2000-04-04 01:40:52 +0000375 print
376 print usage
377 return
378
379 self.command_obj[command] = cmd_obj
380 self.have_run[command] = 0
381
382 # while args
383
384 # If the user wants help -- ie. they gave the "--help" option --
385 # give it to 'em. We do this *after* processing the commands in
386 # case they want help on any particular command, eg.
387 # "setup.py --help foo". (This isn't the documented way to
388 # get help on a command, but I support it because that's how
389 # CVS does it -- might as well be consistent.)
390 if self.help:
Greg Ward82715e12000-04-21 02:28:14 +0000391 parser.set_option_table (self.global_options)
392 parser.print_help (
393 "Global options (apply to all commands, " +
394 "or can be used per command):")
Greg Wardfe6462c2000-04-04 01:40:52 +0000395 print
396
Greg Ward82715e12000-04-21 02:28:14 +0000397 if not self.commands:
398 parser.set_option_table (self.display_options)
399 parser.print_help (
400 "Information display options (just display " +
401 "information, ignore any commands)")
402 print
403
Greg Wardfe6462c2000-04-04 01:40:52 +0000404 for command in self.commands:
405 klass = self.find_command_class (command)
Greg Ward82715e12000-04-21 02:28:14 +0000406 parser.set_option_table (klass.user_options)
407 parser.print_help ("Options for '%s' command:" % command)
Greg Wardfe6462c2000-04-04 01:40:52 +0000408 print
409
410 print usage
411 return
412
413 # Oops, no commands found -- an end-user error
414 if not self.commands:
415 raise DistutilsArgError, "no commands supplied"
416
417 # All is well: return true
418 return 1
419
420 # parse_command_line()
421
Greg Ward82715e12000-04-21 02:28:14 +0000422 def handle_display_options (self, option_order):
423 """If there were any non-global "display-only" options
424 (--help-commands or the metadata display options) on the command
425 line, display the requested info and return true; else return
426 false."""
427
428 from distutils.core import usage
429
430 # User just wants a list of commands -- we'll print it out and stop
431 # processing now (ie. if they ran "setup --help-commands foo bar",
432 # we ignore "foo bar").
433 if self.help_commands:
434 self.print_commands ()
435 print
436 print usage
437 return 1
438
439 # If user supplied any of the "display metadata" options, then
440 # display that metadata in the order in which the user supplied the
441 # metadata options.
442 any_display_options = 0
443 is_display_option = {}
444 for option in self.display_options:
445 is_display_option[option[0]] = 1
446
447 for (opt, val) in option_order:
448 if val and is_display_option.get(opt):
449 opt = string.translate (opt, longopt_xlate)
450 print getattr(self.metadata, "get_"+opt)()
451 any_display_options = 1
452
453 return any_display_options
454
455 # handle_display_options()
Greg Wardfe6462c2000-04-04 01:40:52 +0000456
457 def print_command_list (self, commands, header, max_length):
458 """Print a subset of the list of all commands -- used by
459 'print_commands()'."""
460
461 print header + ":"
462
463 for cmd in commands:
464 klass = self.cmdclass.get (cmd)
465 if not klass:
466 klass = self.find_command_class (cmd)
467 try:
468 description = klass.description
469 except AttributeError:
470 description = "(no description available)"
471
472 print " %-*s %s" % (max_length, cmd, description)
473
474 # print_command_list ()
475
476
477 def print_commands (self):
478 """Print out a help message listing all available commands with
479 a description of each. The list is divided into "standard
480 commands" (listed in distutils.command.__all__) and "extra
481 commands" (mentioned in self.cmdclass, but not a standard
482 command). The descriptions come from the command class
483 attribute 'description'."""
484
485 import distutils.command
486 std_commands = distutils.command.__all__
487 is_std = {}
488 for cmd in std_commands:
489 is_std[cmd] = 1
490
491 extra_commands = []
492 for cmd in self.cmdclass.keys():
493 if not is_std.get(cmd):
494 extra_commands.append (cmd)
495
496 max_length = 0
497 for cmd in (std_commands + extra_commands):
498 if len (cmd) > max_length:
499 max_length = len (cmd)
500
501 self.print_command_list (std_commands,
502 "Standard commands",
503 max_length)
504 if extra_commands:
505 print
506 self.print_command_list (extra_commands,
507 "Extra commands",
508 max_length)
509
510 # print_commands ()
511
512
513
514 # -- Command class/object methods ----------------------------------
515
Greg Wardfe6462c2000-04-04 01:40:52 +0000516 def find_command_class (self, command):
Gregory P. Smith14263542000-05-12 00:41:33 +0000517 """Given a command name, attempts to load the module and class that
518 implements that command. This is done by importing a module
519 "distutils.command." + command, and a class named 'command' in that
520 module.
Greg Wardfe6462c2000-04-04 01:40:52 +0000521
Gregory P. Smith14263542000-05-12 00:41:33 +0000522 Raises DistutilsModuleError if the expected module could not be
523 found, or if that module does not define the expected class."""
Greg Wardfe6462c2000-04-04 01:40:52 +0000524
525 module_name = 'distutils.command.' + command
526 klass_name = command
527
528 try:
529 __import__ (module_name)
530 module = sys.modules[module_name]
531 except ImportError:
532 raise DistutilsModuleError, \
533 "invalid command '%s' (no module named '%s')" % \
534 (command, module_name)
535
536 try:
537 klass = vars(module)[klass_name]
538 except KeyError:
539 raise DistutilsModuleError, \
540 "invalid command '%s' (no class '%s' in module '%s')" \
541 % (command, klass_name, module_name)
542
543 return klass
544
545 # find_command_class ()
546
547
548 def create_command_obj (self, command):
549 """Figure out the class that should implement a command,
550 instantiate it, cache and return the new "command object".
551 The "command class" is determined either by looking it up in
552 the 'cmdclass' attribute (this is the mechanism whereby
553 clients may override default Distutils commands or add their
554 own), or by calling the 'find_command_class()' method (if the
555 command name is not in 'cmdclass'."""
556
557 # Determine the command class -- either it's in the command_class
558 # dictionary, or we have to divine the module and class name
559 klass = self.cmdclass.get(command)
560 if not klass:
561 klass = self.find_command_class (command)
562 self.cmdclass[command] = klass
563
564 # Found the class OK -- instantiate it
565 cmd_obj = klass (self)
566 return cmd_obj
567
568
569 def find_command_obj (self, command, create=1):
570 """Look up and return a command object in the cache maintained by
571 'create_command_obj()'. If none found, the action taken
572 depends on 'create': if true (the default), create a new
573 command object by calling 'create_command_obj()' and return
574 it; otherwise, return None. If 'command' is an invalid
575 command name, then DistutilsModuleError will be raised."""
576
577 cmd_obj = self.command_obj.get (command)
578 if not cmd_obj and create:
579 cmd_obj = self.create_command_obj (command)
580 self.command_obj[command] = cmd_obj
581
582 return cmd_obj
583
584
585 # -- Methods that operate on the Distribution ----------------------
586
587 def announce (self, msg, level=1):
588 """Print 'msg' if 'level' is greater than or equal to the verbosity
589 level recorded in the 'verbose' attribute (which, currently,
590 can be only 0 or 1)."""
591
592 if self.verbose >= level:
593 print msg
594
595
596 def run_commands (self):
Greg Ward82715e12000-04-21 02:28:14 +0000597 """Run each command that was seen on the setup script command line.
Greg Wardfe6462c2000-04-04 01:40:52 +0000598 Uses the list of commands found and cache of command objects
599 created by 'create_command_obj()'."""
600
601 for cmd in self.commands:
602 self.run_command (cmd)
603
604
Greg Wardfe6462c2000-04-04 01:40:52 +0000605 # -- Methods that operate on its Commands --------------------------
606
607 def run_command (self, command):
608
609 """Do whatever it takes to run a command (including nothing at all,
610 if the command has already been run). Specifically: if we have
611 already created and run the command named by 'command', return
612 silently without doing anything. If the command named by
613 'command' doesn't even have a command object yet, create one.
614 Then invoke 'run()' on that command object (or an existing
615 one)."""
616
617 # Already been here, done that? then return silently.
618 if self.have_run.get (command):
619 return
620
621 self.announce ("running " + command)
622 cmd_obj = self.find_command_obj (command)
623 cmd_obj.ensure_ready ()
624 cmd_obj.run ()
625 self.have_run[command] = 1
626
627
Greg Wardfe6462c2000-04-04 01:40:52 +0000628 # -- Distribution query methods ------------------------------------
629
630 def has_pure_modules (self):
631 return len (self.packages or self.py_modules or []) > 0
632
633 def has_ext_modules (self):
634 return self.ext_modules and len (self.ext_modules) > 0
635
636 def has_c_libraries (self):
637 return self.libraries and len (self.libraries) > 0
638
639 def has_modules (self):
640 return self.has_pure_modules() or self.has_ext_modules()
641
Greg Ward44a61bb2000-05-20 15:06:48 +0000642 def has_scripts (self):
643 return self.scripts and len(self.scripts) > 0
644
645 def has_data_files (self):
646 return self.data_files and len(self.data_files) > 0
647
Greg Wardfe6462c2000-04-04 01:40:52 +0000648 def is_pure (self):
649 return (self.has_pure_modules() and
650 not self.has_ext_modules() and
651 not self.has_c_libraries())
652
Greg Ward82715e12000-04-21 02:28:14 +0000653 # -- Metadata query methods ----------------------------------------
654
655 # If you're looking for 'get_name()', 'get_version()', and so forth,
656 # they are defined in a sneaky way: the constructor binds self.get_XXX
657 # to self.metadata.get_XXX. The actual code is in the
658 # DistributionMetadata class, below.
659
660# class Distribution
661
662
663class DistributionMetadata:
664 """Dummy class to hold the distribution meta-data: name, version,
665 author, and so forth."""
666
667 def __init__ (self):
668 self.name = None
669 self.version = None
670 self.author = None
671 self.author_email = None
672 self.maintainer = None
673 self.maintainer_email = None
674 self.url = None
675 self.licence = None
676 self.description = None
Greg Warde5a584e2000-04-26 02:26:55 +0000677 self.long_description = None
Greg Ward82715e12000-04-21 02:28:14 +0000678
679 # -- Metadata query methods ----------------------------------------
680
Greg Wardfe6462c2000-04-04 01:40:52 +0000681 def get_name (self):
682 return self.name or "UNKNOWN"
683
Greg Ward82715e12000-04-21 02:28:14 +0000684 def get_version(self):
685 return self.version or "???"
Greg Wardfe6462c2000-04-04 01:40:52 +0000686
Greg Ward82715e12000-04-21 02:28:14 +0000687 def get_fullname (self):
688 return "%s-%s" % (self.get_name(), self.get_version())
689
690 def get_author(self):
691 return self.author or "UNKNOWN"
692
693 def get_author_email(self):
694 return self.author_email or "UNKNOWN"
695
696 def get_maintainer(self):
697 return self.maintainer or "UNKNOWN"
698
699 def get_maintainer_email(self):
700 return self.maintainer_email or "UNKNOWN"
701
702 def get_contact(self):
703 return (self.maintainer or
704 self.author or
705 "UNKNOWN")
706
707 def get_contact_email(self):
708 return (self.maintainer_email or
709 self.author_email or
710 "UNKNOWN")
711
712 def get_url(self):
713 return self.url or "UNKNOWN"
714
715 def get_licence(self):
716 return self.licence or "UNKNOWN"
717
718 def get_description(self):
719 return self.description or "UNKNOWN"
Greg Warde5a584e2000-04-26 02:26:55 +0000720
721 def get_long_description(self):
722 return self.long_description or "UNKNOWN"
723
Greg Ward82715e12000-04-21 02:28:14 +0000724# class DistributionMetadata
Greg Wardfe6462c2000-04-04 01:40:52 +0000725
726if __name__ == "__main__":
727 dist = Distribution ()
728 print "ok"