blob: 408b9f5c50b4a8d92f33495b63be2cb73a1b7fd9 [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
11import sys, string, re
12from types import *
13from copy import copy
14from distutils.errors import *
15from distutils.fancy_getopt import fancy_getopt, print_help
16
17
18# Regex to define acceptable Distutils command names. This is not *quite*
19# the same as a Python NAME -- I don't allow leading underscores. The fact
20# that they're very similar is no coincidence; the default naming scheme is
21# to look for a Python module named after the command.
22command_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$')
23
24
25class Distribution:
26 """The core of the Distutils. Most of the work hiding behind
27 'setup' is really done within a Distribution instance, which
28 farms the work out to the Distutils commands specified on the
29 command line.
30
31 Clients will almost never instantiate Distribution directly,
32 unless the 'setup' function is totally inadequate to their needs.
33 However, it is conceivable that a client might wish to subclass
34 Distribution for some specialized purpose, and then pass the
35 subclass to 'setup' as the 'distclass' keyword argument. If so,
36 it is necessary to respect the expectations that 'setup' has of
37 Distribution: it must have a constructor and methods
38 'parse_command_line()' and 'run_commands()' with signatures like
39 those described below."""
40
41
42 # 'global_options' describes the command-line options that may be
43 # supplied to the client (setup.py) prior to any actual commands.
44 # Eg. "./setup.py -nv" or "./setup.py --verbose" both take advantage of
45 # these global options. This list should be kept to a bare minimum,
46 # since every global option is also valid as a command option -- and we
47 # don't want to pollute the commands with too many options that they
48 # have minimal control over.
49 global_options = [('verbose', 'v',
50 "run verbosely (default)"),
51 ('quiet', 'q',
52 "run quietly (turns verbosity off)"),
53 ('dry-run', 'n',
54 "don't actually do anything"),
Greg Wardfe6462c2000-04-04 01:40:52 +000055 ('help', 'h',
56 "show this help message"),
57 ]
58 negative_opt = {'quiet': 'verbose'}
59
60
61 # -- Creation/initialization methods -------------------------------
62
63 def __init__ (self, attrs=None):
64 """Construct a new Distribution instance: initialize all the
65 attributes of a Distribution, and then uses 'attrs' (a
66 dictionary mapping attribute names to values) to assign
67 some of those attributes their "real" values. (Any attributes
68 not mentioned in 'attrs' will be assigned to some null
69 value: 0, None, an empty list or dictionary, etc.) Most
70 importantly, initialize the 'command_obj' attribute
71 to the empty dictionary; this will be filled in with real
72 command objects by 'parse_command_line()'."""
73
74 # Default values for our command-line options
75 self.verbose = 1
76 self.dry_run = 0
Greg Wardfe6462c2000-04-04 01:40:52 +000077 self.help = 0
78 self.help_commands = 0
79
80 # And the "distribution meta-data" options -- these can only
81 # come from setup.py (the caller), not the command line
82 # (or a hypothetical config file).
83 self.name = None
84 self.version = None
85 self.author = None
86 self.author_email = None
87 self.maintainer = None
88 self.maintainer_email = None
89 self.url = None
90 self.licence = None
91 self.description = None
92
93 # 'cmdclass' maps command names to class objects, so we
94 # can 1) quickly figure out which class to instantiate when
95 # we need to create a new command object, and 2) have a way
96 # for the client to override command classes
97 self.cmdclass = {}
98
99 # These options are really the business of various commands, rather
100 # than of the Distribution itself. We provide aliases for them in
101 # Distribution as a convenience to the developer.
102 # dictionary.
103 self.packages = None
104 self.package_dir = None
105 self.py_modules = None
106 self.libraries = None
107 self.ext_modules = None
108 self.ext_package = None
109 self.include_dirs = None
110 self.extra_path = None
111
112 # And now initialize bookkeeping stuff that can't be supplied by
113 # the caller at all. 'command_obj' maps command names to
114 # Command instances -- that's how we enforce that every command
115 # class is a singleton.
116 self.command_obj = {}
117
118 # 'have_run' maps command names to boolean values; it keeps track
119 # of whether we have actually run a particular command, to make it
120 # cheap to "run" a command whenever we think we might need to -- if
121 # it's already been done, no need for expensive filesystem
122 # operations, we just check the 'have_run' dictionary and carry on.
123 # It's only safe to query 'have_run' for a command class that has
124 # been instantiated -- a false value will be inserted when the
125 # command object is created, and replaced with a true value when
126 # the command is succesfully run. Thus it's probably best to use
127 # '.get()' rather than a straight lookup.
128 self.have_run = {}
129
130 # Now we'll use the attrs dictionary (ultimately, keyword args from
131 # the client) to possibly override any or all of these distribution
132 # options.
133 if attrs:
134
135 # Pull out the set of command options and work on them
136 # specifically. Note that this order guarantees that aliased
137 # command options will override any supplied redundantly
138 # through the general options dictionary.
139 options = attrs.get ('options')
140 if options:
141 del attrs['options']
142 for (command, cmd_options) in options.items():
143 cmd_obj = self.find_command_obj (command)
144 for (key, val) in cmd_options.items():
145 cmd_obj.set_option (key, val)
146 # loop over commands
147 # if any command options
148
149 # Now work on the rest of the attributes. Any attribute that's
150 # not already defined is invalid!
151 for (key,val) in attrs.items():
152 if hasattr (self, key):
153 setattr (self, key, val)
154 else:
Greg Ward02a1a2b2000-04-15 22:15:07 +0000155 raise DistutilsSetupError, \
Greg Wardfe6462c2000-04-04 01:40:52 +0000156 "invalid distribution option '%s'" % key
157
158 # __init__ ()
159
160
161 def parse_command_line (self, args):
162 """Parse the setup script's command line: set any Distribution
163 attributes tied to command-line options, create all command
164 objects, and set their options from the command-line. 'args'
165 must be a list of command-line arguments, most likely
166 'sys.argv[1:]' (see the 'setup()' function). This list is first
167 processed for "global options" -- options that set attributes of
168 the Distribution instance. Then, it is alternately scanned for
169 Distutils command and options for that command. Each new
170 command terminates the options for the previous command. The
171 allowed options for a command are determined by the 'options'
172 attribute of the command object -- thus, we instantiate (and
173 cache) every command object here, in order to access its
174 'options' attribute. Any error in that 'options' attribute
175 raises DistutilsGetoptError; any error on the command-line
176 raises DistutilsArgError. If no Distutils commands were found
177 on the command line, raises DistutilsArgError. Return true if
178 command-line successfully parsed and we should carry on with
179 executing commands; false if no errors but we shouldn't execute
180 commands (currently, this only happens if user asks for
181 help)."""
182
Greg Ward7d508fe2000-04-06 02:07:41 +0000183 # late import because of mutual dependence between these modules
Greg Wardfe6462c2000-04-04 01:40:52 +0000184 from distutils.cmd import Command
Greg Ward7d508fe2000-04-06 02:07:41 +0000185 from distutils.core import usage
Greg Wardfe6462c2000-04-04 01:40:52 +0000186
187 # We have to parse the command line a bit at a time -- global
188 # options, then the first command, then its options, and so on --
189 # because each command will be handled by a different class, and
190 # the options that are valid for a particular class aren't
191 # known until we instantiate the command class, which doesn't
192 # happen until we know what the command is.
193
194 self.commands = []
195 options = self.global_options + \
196 [('help-commands', None,
197 "list all available commands")]
198 args = fancy_getopt (options, self.negative_opt,
199 self, sys.argv[1:])
200
201 # User just wants a list of commands -- we'll print it out and stop
202 # processing now (ie. if they ran "setup --help-commands foo bar",
203 # we ignore "foo bar").
204 if self.help_commands:
205 self.print_commands ()
206 print
207 print usage
208 return
209
210 while args:
211 # Pull the current command from the head of the command line
212 command = args[0]
213 if not command_re.match (command):
214 raise SystemExit, "invalid command name '%s'" % command
215 self.commands.append (command)
216
217 # Make sure we have a command object to put the options into
218 # (this either pulls it out of a cache of command objects,
219 # or finds and instantiates the command class).
220 try:
221 cmd_obj = self.find_command_obj (command)
222 except DistutilsModuleError, msg:
223 raise DistutilsArgError, msg
224
225 # Require that the command class be derived from Command --
226 # that way, we can be sure that we at least have the 'run'
227 # and 'get_option' methods.
228 if not isinstance (cmd_obj, Command):
229 raise DistutilsClassError, \
230 "command class %s must subclass Command" % \
231 cmd_obj.__class__
232
233 # Also make sure that the command object provides a list of its
234 # known options
235 if not (hasattr (cmd_obj, 'user_options') and
236 type (cmd_obj.user_options) is ListType):
237 raise DistutilsClassError, \
238 ("command class %s must provide " +
239 "'user_options' attribute (a list of tuples)") % \
240 cmd_obj.__class__
241
242 # Poof! like magic, all commands support the global
243 # options too, just by adding in 'global_options'.
244 negative_opt = self.negative_opt
245 if hasattr (cmd_obj, 'negative_opt'):
246 negative_opt = copy (negative_opt)
247 negative_opt.update (cmd_obj.negative_opt)
248
249 options = self.global_options + cmd_obj.user_options
250 args = fancy_getopt (options, negative_opt,
251 cmd_obj, args[1:])
252 if cmd_obj.help:
253 print_help (self.global_options,
254 header="Global options:")
255 print
256 print_help (cmd_obj.user_options,
257 header="Options for '%s' command:" % command)
258 print
259 print usage
260 return
261
262 self.command_obj[command] = cmd_obj
263 self.have_run[command] = 0
264
265 # while args
266
267 # If the user wants help -- ie. they gave the "--help" option --
268 # give it to 'em. We do this *after* processing the commands in
269 # case they want help on any particular command, eg.
270 # "setup.py --help foo". (This isn't the documented way to
271 # get help on a command, but I support it because that's how
272 # CVS does it -- might as well be consistent.)
273 if self.help:
274 print_help (self.global_options, header="Global options:")
275 print
276
277 for command in self.commands:
278 klass = self.find_command_class (command)
279 print_help (klass.user_options,
280 header="Options for '%s' command:" % command)
281 print
282
283 print usage
284 return
285
286 # Oops, no commands found -- an end-user error
287 if not self.commands:
288 raise DistutilsArgError, "no commands supplied"
289
290 # All is well: return true
291 return 1
292
293 # parse_command_line()
294
295
296 def print_command_list (self, commands, header, max_length):
297 """Print a subset of the list of all commands -- used by
298 'print_commands()'."""
299
300 print header + ":"
301
302 for cmd in commands:
303 klass = self.cmdclass.get (cmd)
304 if not klass:
305 klass = self.find_command_class (cmd)
306 try:
307 description = klass.description
308 except AttributeError:
309 description = "(no description available)"
310
311 print " %-*s %s" % (max_length, cmd, description)
312
313 # print_command_list ()
314
315
316 def print_commands (self):
317 """Print out a help message listing all available commands with
318 a description of each. The list is divided into "standard
319 commands" (listed in distutils.command.__all__) and "extra
320 commands" (mentioned in self.cmdclass, but not a standard
321 command). The descriptions come from the command class
322 attribute 'description'."""
323
324 import distutils.command
325 std_commands = distutils.command.__all__
326 is_std = {}
327 for cmd in std_commands:
328 is_std[cmd] = 1
329
330 extra_commands = []
331 for cmd in self.cmdclass.keys():
332 if not is_std.get(cmd):
333 extra_commands.append (cmd)
334
335 max_length = 0
336 for cmd in (std_commands + extra_commands):
337 if len (cmd) > max_length:
338 max_length = len (cmd)
339
340 self.print_command_list (std_commands,
341 "Standard commands",
342 max_length)
343 if extra_commands:
344 print
345 self.print_command_list (extra_commands,
346 "Extra commands",
347 max_length)
348
349 # print_commands ()
350
351
352
353 # -- Command class/object methods ----------------------------------
354
355 # This is a method just so it can be overridden if desired; it doesn't
356 # actually use or change any attributes of the Distribution instance.
357 def find_command_class (self, command):
358 """Given a command, derives the names of the module and class
359 expected to implement the command: eg. 'foo_bar' becomes
360 'distutils.command.foo_bar' (the module) and 'FooBar' (the
361 class within that module). Loads the module, extracts the
362 class from it, and returns the class object.
363
364 Raises DistutilsModuleError with a semi-user-targeted error
365 message if the expected module could not be loaded, or the
366 expected class was not found in it."""
367
368 module_name = 'distutils.command.' + command
369 klass_name = command
370
371 try:
372 __import__ (module_name)
373 module = sys.modules[module_name]
374 except ImportError:
375 raise DistutilsModuleError, \
376 "invalid command '%s' (no module named '%s')" % \
377 (command, module_name)
378
379 try:
380 klass = vars(module)[klass_name]
381 except KeyError:
382 raise DistutilsModuleError, \
383 "invalid command '%s' (no class '%s' in module '%s')" \
384 % (command, klass_name, module_name)
385
386 return klass
387
388 # find_command_class ()
389
390
391 def create_command_obj (self, command):
392 """Figure out the class that should implement a command,
393 instantiate it, cache and return the new "command object".
394 The "command class" is determined either by looking it up in
395 the 'cmdclass' attribute (this is the mechanism whereby
396 clients may override default Distutils commands or add their
397 own), or by calling the 'find_command_class()' method (if the
398 command name is not in 'cmdclass'."""
399
400 # Determine the command class -- either it's in the command_class
401 # dictionary, or we have to divine the module and class name
402 klass = self.cmdclass.get(command)
403 if not klass:
404 klass = self.find_command_class (command)
405 self.cmdclass[command] = klass
406
407 # Found the class OK -- instantiate it
408 cmd_obj = klass (self)
409 return cmd_obj
410
411
412 def find_command_obj (self, command, create=1):
413 """Look up and return a command object in the cache maintained by
414 'create_command_obj()'. If none found, the action taken
415 depends on 'create': if true (the default), create a new
416 command object by calling 'create_command_obj()' and return
417 it; otherwise, return None. If 'command' is an invalid
418 command name, then DistutilsModuleError will be raised."""
419
420 cmd_obj = self.command_obj.get (command)
421 if not cmd_obj and create:
422 cmd_obj = self.create_command_obj (command)
423 self.command_obj[command] = cmd_obj
424
425 return cmd_obj
426
427
428 # -- Methods that operate on the Distribution ----------------------
429
430 def announce (self, msg, level=1):
431 """Print 'msg' if 'level' is greater than or equal to the verbosity
432 level recorded in the 'verbose' attribute (which, currently,
433 can be only 0 or 1)."""
434
435 if self.verbose >= level:
436 print msg
437
438
439 def run_commands (self):
440 """Run each command that was seen on the client command line.
441 Uses the list of commands found and cache of command objects
442 created by 'create_command_obj()'."""
443
444 for cmd in self.commands:
445 self.run_command (cmd)
446
447
448 def get_option (self, option):
449 """Return the value of a distribution option. Raise
Greg Ward02a1a2b2000-04-15 22:15:07 +0000450 AttributeError if 'option' is not known."""
451 return getattr (self, opt)
Greg Wardfe6462c2000-04-04 01:40:52 +0000452
453
454 def get_options (self, *options):
455 """Return (as a tuple) the values of several distribution
Greg Ward02a1a2b2000-04-15 22:15:07 +0000456 options. Raise AttributeError if any element of
Greg Wardfe6462c2000-04-04 01:40:52 +0000457 'options' is not known."""
458
459 values = []
Greg Ward02a1a2b2000-04-15 22:15:07 +0000460 for opt in options:
461 values.append (getattr (self, opt))
Greg Wardfe6462c2000-04-04 01:40:52 +0000462
463 return tuple (values)
464
465
466 # -- Methods that operate on its Commands --------------------------
467
468 def run_command (self, command):
469
470 """Do whatever it takes to run a command (including nothing at all,
471 if the command has already been run). Specifically: if we have
472 already created and run the command named by 'command', return
473 silently without doing anything. If the command named by
474 'command' doesn't even have a command object yet, create one.
475 Then invoke 'run()' on that command object (or an existing
476 one)."""
477
478 # Already been here, done that? then return silently.
479 if self.have_run.get (command):
480 return
481
482 self.announce ("running " + command)
483 cmd_obj = self.find_command_obj (command)
484 cmd_obj.ensure_ready ()
485 cmd_obj.run ()
486 self.have_run[command] = 1
487
488
489 def get_command_option (self, command, option):
490 """Create a command object for 'command' if necessary, ensure that
491 its option values are all set to their final values, and return
Greg Ward02a1a2b2000-04-15 22:15:07 +0000492 the value of its 'option' option. Raise AttributeError if
Greg Wardfe6462c2000-04-04 01:40:52 +0000493 'option' is not known for that 'command'."""
494
495 cmd_obj = self.find_command_obj (command)
496 cmd_obj.ensure_ready ()
497 return cmd_obj.get_option (option)
Greg Wardfe6462c2000-04-04 01:40:52 +0000498
499
500 def get_command_options (self, command, *options):
501 """Create a command object for 'command' if necessary, ensure that
502 its option values are all set to their final values, and return
503 a tuple containing the values of all the options listed in
504 'options' for that command. Raise DistutilsOptionError if any
505 invalid option is supplied in 'options'."""
506
507 cmd_obj = self.find_command_obj (command)
508 cmd_obj.ensure_ready ()
509 values = []
Greg Ward02a1a2b2000-04-15 22:15:07 +0000510 for opt in options:
511 values.append (getattr (cmd_obj, option))
Greg Wardfe6462c2000-04-04 01:40:52 +0000512
513 return tuple (values)
514
515
516 # -- Distribution query methods ------------------------------------
517
518 def has_pure_modules (self):
519 return len (self.packages or self.py_modules or []) > 0
520
521 def has_ext_modules (self):
522 return self.ext_modules and len (self.ext_modules) > 0
523
524 def has_c_libraries (self):
525 return self.libraries and len (self.libraries) > 0
526
527 def has_modules (self):
528 return self.has_pure_modules() or self.has_ext_modules()
529
530 def is_pure (self):
531 return (self.has_pure_modules() and
532 not self.has_ext_modules() and
533 not self.has_c_libraries())
534
535 def get_name (self):
536 return self.name or "UNKNOWN"
537
538 def get_full_name (self):
539 return "%s-%s" % ((self.name or "UNKNOWN"), (self.version or "???"))
540
541# class Distribution
542
543
544if __name__ == "__main__":
545 dist = Distribution ()
546 print "ok"