Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 1 | """distutils.core |
| 2 | |
| 3 | The only module that needs to be imported to use the Distutils; provides |
| 4 | the 'setup' function (which must be called); the 'Distribution' class |
| 5 | (which may be subclassed if additional functionality is desired), and |
| 6 | the 'Command' class (which is used both internally by Distutils, and |
| 7 | may be subclassed by clients for still more flexibility).""" |
| 8 | |
| 9 | # created 1999/03/01, Greg Ward |
| 10 | |
| 11 | __rcsid__ = "$Id$" |
| 12 | |
Greg Ward | 06ca948 | 1999-04-04 02:58:07 +0000 | [diff] [blame] | 13 | import sys, os |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 14 | import string, re |
Greg Ward | 1ea8af2 | 1999-08-29 18:20:32 +0000 | [diff] [blame] | 15 | from types import * |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 16 | from distutils.errors import * |
| 17 | from distutils.fancy_getopt import fancy_getopt |
Greg Ward | 06ca948 | 1999-04-04 02:58:07 +0000 | [diff] [blame] | 18 | from distutils import util |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 19 | |
| 20 | # This is not *quite* the same as a Python NAME; I don't allow leading |
| 21 | # underscores. The fact that they're very similar is no coincidence... |
| 22 | command_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$') |
| 23 | |
| 24 | # Defining this as a global is probably inadequate -- what about |
| 25 | # listing the available options (or even commands, which can vary |
| 26 | # quite late as well) |
| 27 | usage = '%s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]' % sys.argv[0] |
| 28 | |
| 29 | |
| 30 | |
| 31 | def setup (**attrs): |
| 32 | """The gateway to the Distutils: do everything your setup script |
| 33 | needs to do, in a highly flexible and user-driven way. Briefly: |
| 34 | create a Distribution instance; parse the command-line, creating |
| 35 | and customizing instances of the command class for each command |
| 36 | found on the command-line; run each of those commands. |
| 37 | |
| 38 | The Distribution instance might be an instance of a class |
| 39 | supplied via the 'distclass' keyword argument to 'setup'; if no |
| 40 | such class is supplied, then the 'Distribution' class (also in |
| 41 | this module) is instantiated. All other arguments to 'setup' |
| 42 | (except for 'cmdclass') are used to set attributes of the |
| 43 | Distribution instance. |
| 44 | |
| 45 | The 'cmdclass' argument, if supplied, is a dictionary mapping |
| 46 | command names to command classes. Each command encountered on the |
| 47 | command line will be turned into a command class, which is in turn |
| 48 | instantiated; any class found in 'cmdclass' is used in place of the |
| 49 | default, which is (for command 'foo_bar') class 'FooBar' in module |
| 50 | 'distutils.command.foo_bar'. The command object must provide an |
| 51 | 'options' attribute which is a list of option specifiers for |
| 52 | 'distutils.fancy_getopt'. Any command-line options between the |
| 53 | current and the next command are used to set attributes in the |
| 54 | current command object. |
| 55 | |
| 56 | When the entire command-line has been successfully parsed, calls the |
| 57 | 'run' method on each command object in turn. This method will be |
| 58 | driven entirely by the Distribution object (which each command |
| 59 | object has a reference to, thanks to its constructor), and the |
| 60 | command-specific options that became attributes of each command |
| 61 | object.""" |
| 62 | |
| 63 | # Determine the distribution class -- either caller-supplied or |
| 64 | # our Distribution (see below). |
| 65 | klass = attrs.get ('distclass') |
| 66 | if klass: |
| 67 | del attrs['distclass'] |
| 68 | else: |
| 69 | klass = Distribution |
| 70 | |
| 71 | # Create the Distribution instance, using the remaining arguments |
| 72 | # (ie. everything except distclass) to initialize it |
| 73 | dist = klass (attrs) |
| 74 | |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 75 | # If we had a config file, this is where we would parse it: override |
| 76 | # the client-supplied command options, but be overridden by the |
| 77 | # command line. |
| 78 | |
| 79 | # Parse the command line; any command-line errors are the end-users |
| 80 | # fault, so turn them into SystemExit to suppress tracebacks. |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 81 | try: |
| 82 | dist.parse_command_line (sys.argv[1:]) |
| 83 | except DistutilsArgError, msg: |
| 84 | raise SystemExit, msg |
| 85 | |
| 86 | # And finally, run all the commands found on the command line. |
| 87 | dist.run_commands () |
| 88 | |
| 89 | # setup () |
| 90 | |
| 91 | |
| 92 | class Distribution: |
| 93 | """The core of the Distutils. Most of the work hiding behind |
| 94 | 'setup' is really done within a Distribution instance, which |
| 95 | farms the work out to the Distutils commands specified on the |
| 96 | command line. |
| 97 | |
| 98 | Clients will almost never instantiate Distribution directly, |
| 99 | unless the 'setup' function is totally inadequate to their needs. |
| 100 | However, it is conceivable that a client might wish to subclass |
| 101 | Distribution for some specialized purpose, and then pass the |
| 102 | subclass to 'setup' as the 'distclass' keyword argument. If so, |
| 103 | it is necessary to respect the expectations that 'setup' has of |
| 104 | Distribution: it must have a constructor and methods |
| 105 | 'parse_command_line()' and 'run_commands()' with signatures like |
| 106 | those described below.""" |
| 107 | |
| 108 | |
| 109 | # 'global_options' describes the command-line options that may |
| 110 | # be supplied to the client (setup.py) prior to any actual |
| 111 | # commands. Eg. "./setup.py -nv" or "./setup.py --verbose" |
| 112 | # both take advantage of these global options. |
| 113 | global_options = [('verbose', 'v', "run verbosely"), |
| 114 | ('dry-run', 'n', "don't actually do anything"), |
| 115 | ] |
| 116 | |
| 117 | |
| 118 | # -- Creation/initialization methods ------------------------------- |
| 119 | |
| 120 | def __init__ (self, attrs=None): |
| 121 | """Construct a new Distribution instance: initialize all the |
| 122 | attributes of a Distribution, and then uses 'attrs' (a |
| 123 | dictionary mapping attribute names to values) to assign |
| 124 | some of those attributes their "real" values. (Any attributes |
| 125 | not mentioned in 'attrs' will be assigned to some null |
| 126 | value: 0, None, an empty list or dictionary, etc.) Most |
| 127 | importantly, initialize the 'command_obj' attribute |
| 128 | to the empty dictionary; this will be filled in with real |
| 129 | command objects by 'parse_command_line()'.""" |
| 130 | |
| 131 | # Default values for our command-line options |
| 132 | self.verbose = 0 |
| 133 | self.dry_run = 0 |
| 134 | |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 135 | # And the "distribution meta-data" options -- these can only |
| 136 | # come from setup.py (the caller), not the command line |
| 137 | # (or a hypothetical config file).. |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 138 | self.name = None |
| 139 | self.version = None |
| 140 | self.author = None |
Greg Ward | df0d335 | 1999-09-21 18:41:36 +0000 | [diff] [blame] | 141 | self.author_email = None |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 142 | self.url = None |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 143 | self.licence = None |
| 144 | self.description = None |
| 145 | |
Greg Ward | c997334 | 1999-06-08 02:02:00 +0000 | [diff] [blame] | 146 | # 'cmdclass' maps command names to class objects, so we |
| 147 | # can 1) quickly figure out which class to instantiate when |
| 148 | # we need to create a new command object, and 2) have a way |
| 149 | # for the client to override command classes |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 150 | self.cmdclass = {} |
| 151 | |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 152 | # These options are really the business of various commands, rather |
| 153 | # than of the Distribution itself. We provide aliases for them in |
| 154 | # Distribution as a convenience to the developer. |
| 155 | # dictionary. |
Greg Ward | df0d335 | 1999-09-21 18:41:36 +0000 | [diff] [blame] | 156 | self.packages = None |
| 157 | self.package_dir = None |
| 158 | self.py_modules = None |
| 159 | self.ext_modules = None |
| 160 | self.ext_package = None |
| 161 | self.include_dirs = None |
| 162 | self.install_path = None |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 163 | |
| 164 | # And now initialize bookkeeping stuff that can't be supplied by |
Greg Ward | c997334 | 1999-06-08 02:02:00 +0000 | [diff] [blame] | 165 | # the caller at all. 'command_obj' maps command names to |
| 166 | # Command instances -- that's how we enforce that every command |
| 167 | # class is a singleton. |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 168 | self.command_obj = {} |
| 169 | |
Greg Ward | c997334 | 1999-06-08 02:02:00 +0000 | [diff] [blame] | 170 | # 'have_run' maps command names to boolean values; it keeps track |
| 171 | # of whether we have actually run a particular command, to make it |
| 172 | # cheap to "run" a command whenever we think we might need to -- if |
| 173 | # it's already been done, no need for expensive filesystem |
| 174 | # operations, we just check the 'have_run' dictionary and carry on. |
Greg Ward | 7f65c65 | 1999-08-14 23:47:21 +0000 | [diff] [blame] | 175 | # It's only safe to query 'have_run' for a command class that has |
| 176 | # been instantiated -- a false value will be inserted when the |
| 177 | # command object is created, and replaced with a true value when |
| 178 | # the command is succesfully run. Thus it's probably best to use |
| 179 | # '.get()' rather than a straight lookup. |
Greg Ward | c997334 | 1999-06-08 02:02:00 +0000 | [diff] [blame] | 180 | self.have_run = {} |
| 181 | |
Greg Ward | df0d335 | 1999-09-21 18:41:36 +0000 | [diff] [blame] | 182 | # Now we'll use the attrs dictionary (ultimately, keyword args from |
| 183 | # the client) to possibly override any or all of these distribution |
| 184 | # options. |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 185 | if attrs: |
| 186 | |
| 187 | # Pull out the set of command options and work on them |
| 188 | # specifically. Note that this order guarantees that aliased |
| 189 | # command options will override any supplied redundantly |
| 190 | # through the general options dictionary. |
| 191 | options = attrs.get ('options') |
| 192 | if options: |
| 193 | del attrs['options'] |
| 194 | for (command, cmd_options) in options.items(): |
| 195 | cmd_obj = self.find_command_obj (command) |
| 196 | for (key, val) in cmd_options.items(): |
| 197 | cmd_obj.set_option (key, val) |
| 198 | # loop over commands |
| 199 | # if any command options |
| 200 | |
Greg Ward | df0d335 | 1999-09-21 18:41:36 +0000 | [diff] [blame] | 201 | # Now work on the rest of the attributes. Any attribute that's |
| 202 | # not already defined is invalid! |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 203 | for (key,val) in attrs.items(): |
Greg Ward | df0d335 | 1999-09-21 18:41:36 +0000 | [diff] [blame] | 204 | if hasattr (self, key): |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 205 | setattr (self, key, val) |
| 206 | else: |
| 207 | raise DistutilsOptionError, \ |
| 208 | "invalid distribution option '%s'" % key |
| 209 | |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 210 | # __init__ () |
| 211 | |
| 212 | |
| 213 | def parse_command_line (self, args): |
| 214 | """Parse the client's command line: set any Distribution |
| 215 | attributes tied to command-line options, create all command |
| 216 | objects, and set their options from the command-line. 'args' |
| 217 | must be a list of command-line arguments, most likely |
| 218 | 'sys.argv[1:]' (see the 'setup()' function). This list is |
| 219 | first processed for "global options" -- options that set |
| 220 | attributes of the Distribution instance. Then, it is |
| 221 | alternately scanned for Distutils command and options for |
| 222 | that command. Each new command terminates the options for |
| 223 | the previous command. The allowed options for a command are |
| 224 | determined by the 'options' attribute of the command object |
| 225 | -- thus, we instantiate (and cache) every command object |
| 226 | here, in order to access its 'options' attribute. Any error |
| 227 | in that 'options' attribute raises DistutilsGetoptError; any |
| 228 | error on the command-line raises DistutilsArgError. If no |
| 229 | Distutils commands were found on the command line, raises |
| 230 | DistutilsArgError.""" |
| 231 | |
| 232 | # We have to parse the command line a bit at a time -- global |
| 233 | # options, then the first command, then its options, and so on -- |
| 234 | # because each command will be handled by a different class, and |
| 235 | # the options that are valid for a particular class aren't |
| 236 | # known until we instantiate the command class, which doesn't |
| 237 | # happen until we know what the command is. |
| 238 | |
| 239 | self.commands = [] |
| 240 | args = fancy_getopt (self.global_options, self, sys.argv[1:]) |
| 241 | |
| 242 | while args: |
| 243 | # Pull the current command from the head of the command line |
| 244 | command = args[0] |
| 245 | if not command_re.match (command): |
| 246 | raise SystemExit, "invalid command name '%s'" % command |
| 247 | self.commands.append (command) |
| 248 | |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 249 | # Make sure we have a command object to put the options into |
| 250 | # (this either pulls it out of a cache of command objects, |
| 251 | # or finds and instantiates the command class). |
| 252 | cmd_obj = self.find_command_obj (command) |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 253 | |
| 254 | # Require that the command class be derived from Command -- |
| 255 | # that way, we can be sure that we at least have the 'run' |
| 256 | # and 'get_option' methods. |
| 257 | if not isinstance (cmd_obj, Command): |
| 258 | raise DistutilsClassError, \ |
| 259 | "command class %s must subclass Command" % \ |
| 260 | cmd_obj.__class__ |
| 261 | |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 262 | # Also make sure that the command object provides a list of its |
| 263 | # known options |
| 264 | if not (hasattr (cmd_obj, 'options') and |
| 265 | type (cmd_obj.options) is ListType): |
| 266 | raise DistutilsClasserror, \ |
| 267 | ("command class %s must provide an 'options' attribute "+ |
| 268 | "(a list of tuples)") % \ |
| 269 | cmd_obj.__class__ |
| 270 | |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 271 | args = fancy_getopt (cmd_obj.options, cmd_obj, args[1:]) |
| 272 | self.command_obj[command] = cmd_obj |
Greg Ward | c997334 | 1999-06-08 02:02:00 +0000 | [diff] [blame] | 273 | self.have_run[command] = 0 |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 274 | |
| 275 | # while args |
| 276 | |
| 277 | # Oops, no commands found -- an end-user error |
| 278 | if not self.commands: |
| 279 | sys.stderr.write (usage + "\n") |
| 280 | raise DistutilsArgError, "no commands supplied" |
| 281 | |
| 282 | # parse_command_line() |
| 283 | |
| 284 | |
| 285 | # -- Command class/object methods ---------------------------------- |
| 286 | |
| 287 | # This is a method just so it can be overridden if desired; it doesn't |
| 288 | # actually use or change any attributes of the Distribution instance. |
| 289 | def find_command_class (self, command): |
| 290 | """Given a command, derives the names of the module and class |
| 291 | expected to implement the command: eg. 'foo_bar' becomes |
| 292 | 'distutils.command.foo_bar' (the module) and 'FooBar' (the |
| 293 | class within that module). Loads the module, extracts the |
| 294 | class from it, and returns the class object. |
| 295 | |
| 296 | Raises DistutilsModuleError with a semi-user-targeted error |
| 297 | message if the expected module could not be loaded, or the |
| 298 | expected class was not found in it.""" |
| 299 | |
| 300 | module_name = 'distutils.command.' + command |
| 301 | klass_name = string.join \ |
| 302 | (map (string.capitalize, string.split (command, '_')), '') |
| 303 | |
| 304 | try: |
| 305 | __import__ (module_name) |
| 306 | module = sys.modules[module_name] |
| 307 | except ImportError: |
| 308 | raise DistutilsModuleError, \ |
| 309 | "invalid command '%s' (no module named %s)" % \ |
| 310 | (command, module_name) |
| 311 | |
| 312 | try: |
| 313 | klass = vars(module)[klass_name] |
| 314 | except KeyError: |
| 315 | raise DistutilsModuleError, \ |
| 316 | "invalid command '%s' (no class '%s' in module '%s')" \ |
| 317 | % (command, klass_name, module_name) |
| 318 | |
| 319 | return klass |
| 320 | |
| 321 | # find_command_class () |
| 322 | |
| 323 | |
| 324 | def create_command_obj (self, command): |
| 325 | """Figure out the class that should implement a command, |
| 326 | instantiate it, cache and return the new "command object". |
| 327 | The "command class" is determined either by looking it up in |
| 328 | the 'cmdclass' attribute (this is the mechanism whereby |
| 329 | clients may override default Distutils commands or add their |
| 330 | own), or by calling the 'find_command_class()' method (if the |
| 331 | command name is not in 'cmdclass'.""" |
| 332 | |
| 333 | # Determine the command class -- either it's in the command_class |
| 334 | # dictionary, or we have to divine the module and class name |
| 335 | klass = self.cmdclass.get(command) |
| 336 | if not klass: |
| 337 | klass = self.find_command_class (command) |
| 338 | self.cmdclass[command] = klass |
| 339 | |
| 340 | # Found the class OK -- instantiate it |
| 341 | cmd_obj = klass (self) |
| 342 | return cmd_obj |
| 343 | |
| 344 | |
| 345 | def find_command_obj (self, command, create=1): |
| 346 | """Look up and return a command object in the cache maintained by |
| 347 | 'create_command_obj()'. If none found, the action taken |
| 348 | depends on 'create': if true (the default), create a new |
| 349 | command object by calling 'create_command_obj()' and return |
| 350 | it; otherwise, return None.""" |
| 351 | |
| 352 | cmd_obj = self.command_obj.get (command) |
| 353 | if not cmd_obj and create: |
| 354 | cmd_obj = self.create_command_obj (command) |
| 355 | self.command_obj[command] = cmd_obj |
| 356 | |
| 357 | return cmd_obj |
| 358 | |
| 359 | |
| 360 | # -- Methods that operate on the Distribution ---------------------- |
| 361 | |
| 362 | def announce (self, msg, level=1): |
| 363 | """Print 'msg' if 'level' is greater than or equal to the verbosity |
| 364 | level recorded in the 'verbose' attribute (which, currently, |
| 365 | can be only 0 or 1).""" |
| 366 | |
| 367 | if self.verbose >= level: |
| 368 | print msg |
| 369 | |
| 370 | |
| 371 | def run_commands (self): |
| 372 | """Run each command that was seen on the client command line. |
| 373 | Uses the list of commands found and cache of command objects |
| 374 | created by 'create_command_obj()'.""" |
| 375 | |
| 376 | for cmd in self.commands: |
| 377 | self.run_command (cmd) |
| 378 | |
| 379 | |
| 380 | def get_option (self, option): |
| 381 | """Return the value of a distribution option. Raise |
| 382 | DistutilsOptionError if 'option' is not known.""" |
| 383 | |
| 384 | try: |
| 385 | return getattr (self, opt) |
| 386 | except AttributeError: |
| 387 | raise DistutilsOptionError, \ |
| 388 | "unknown distribution option %s" % option |
| 389 | |
| 390 | |
| 391 | def get_options (self, *options): |
| 392 | """Return (as a tuple) the values of several distribution |
| 393 | options. Raise DistutilsOptionError if any element of |
| 394 | 'options' is not known.""" |
| 395 | |
| 396 | values = [] |
| 397 | try: |
| 398 | for opt in options: |
| 399 | values.append (getattr (self, opt)) |
| 400 | except AttributeError, name: |
| 401 | raise DistutilsOptionError, \ |
| 402 | "unknown distribution option %s" % name |
| 403 | |
| 404 | return tuple (values) |
| 405 | |
| 406 | |
| 407 | # -- Methods that operate on its Commands -------------------------- |
| 408 | |
| 409 | def run_command (self, command): |
Greg Ward | c997334 | 1999-06-08 02:02:00 +0000 | [diff] [blame] | 410 | |
| 411 | """Do whatever it takes to run a command (including nothing at all, |
| 412 | if the command has already been run). Specifically: if we have |
| 413 | already created and run the command named by 'command', return |
| 414 | silently without doing anything. If the command named by |
| 415 | 'command' doesn't even have a command object yet, create one. |
| 416 | Then invoke 'run()' on that command object (or an existing |
| 417 | one).""" |
| 418 | |
| 419 | # Already been here, done that? then return silently. |
| 420 | if self.have_run.get (command): |
| 421 | return |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 422 | |
| 423 | self.announce ("running " + command) |
| 424 | cmd_obj = self.find_command_obj (command) |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 425 | cmd_obj.ensure_ready () |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 426 | cmd_obj.run () |
Greg Ward | c997334 | 1999-06-08 02:02:00 +0000 | [diff] [blame] | 427 | self.have_run[command] = 1 |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 428 | |
| 429 | |
| 430 | def get_command_option (self, command, option): |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 431 | """Create a command object for 'command' if necessary, ensure that |
| 432 | its option values are all set to their final values, and return |
| 433 | the value of its 'option' option. Raise DistutilsOptionError if |
| 434 | 'option' is not known for that 'command'.""" |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 435 | |
| 436 | cmd_obj = self.find_command_obj (command) |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 437 | cmd_obj.ensure_ready () |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 438 | return cmd_obj.get_option (option) |
| 439 | try: |
| 440 | return getattr (cmd_obj, option) |
| 441 | except AttributeError: |
| 442 | raise DistutilsOptionError, \ |
| 443 | "command %s: no such option %s" % (command, option) |
| 444 | |
| 445 | |
| 446 | def get_command_options (self, command, *options): |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 447 | """Create a command object for 'command' if necessary, ensure that |
| 448 | its option values are all set to their final values, and return |
| 449 | a tuple containing the values of all the options listed in |
| 450 | 'options' for that command. Raise DistutilsOptionError if any |
| 451 | invalid option is supplied in 'options'.""" |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 452 | |
| 453 | cmd_obj = self.find_command_obj (command) |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 454 | cmd_obj.ensure_ready () |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 455 | values = [] |
| 456 | try: |
| 457 | for opt in options: |
| 458 | values.append (getattr (cmd_obj, option)) |
| 459 | except AttributeError, name: |
| 460 | raise DistutilsOptionError, \ |
| 461 | "command %s: no such option %s" % (command, name) |
| 462 | |
| 463 | return tuple (values) |
| 464 | |
| 465 | # end class Distribution |
| 466 | |
| 467 | |
| 468 | class Command: |
| 469 | """Abstract base class for defining command classes, the "worker bees" |
| 470 | of the Distutils. A useful analogy for command classes is to |
| 471 | think of them as subroutines with local variables called |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 472 | "options". The options are "declared" in 'set_default_options()' |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 473 | and "initialized" (given their real values) in |
| 474 | 'set_final_options()', both of which must be defined by every |
| 475 | command class. The distinction between the two is necessary |
| 476 | because option values might come from the outside world (command |
| 477 | line, option file, ...), and any options dependent on other |
| 478 | options must be computed *after* these outside influences have |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 479 | been processed -- hence 'set_final_options()'. The "body" of the |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 480 | subroutine, where it does all its work based on the values of its |
| 481 | options, is the 'run()' method, which must also be implemented by |
| 482 | every command class.""" |
| 483 | |
| 484 | # -- Creation/initialization methods ------------------------------- |
| 485 | |
| 486 | def __init__ (self, dist): |
| 487 | """Create and initialize a new Command object. Most importantly, |
| 488 | invokes the 'set_default_options()' method, which is the |
| 489 | real initializer and depends on the actual command being |
| 490 | instantiated.""" |
| 491 | |
| 492 | if not isinstance (dist, Distribution): |
| 493 | raise TypeError, "dist must be a Distribution instance" |
| 494 | if self.__class__ is Command: |
| 495 | raise RuntimeError, "Command is an abstract class" |
| 496 | |
| 497 | self.distribution = dist |
| 498 | self.set_default_options () |
| 499 | |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 500 | # 'ready' records whether or not 'set_final_options()' has been |
| 501 | # called. 'set_final_options()' itself should not pay attention to |
| 502 | # this flag: it is the business of 'ensure_ready()', which always |
| 503 | # calls 'set_final_options()', to respect/update it. |
| 504 | self.ready = 0 |
| 505 | |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 506 | # end __init__ () |
| 507 | |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 508 | |
| 509 | def ensure_ready (self): |
| 510 | if not self.ready: |
| 511 | self.set_final_options () |
| 512 | self.ready = 1 |
| 513 | |
| 514 | |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 515 | # Subclasses must define: |
| 516 | # set_default_options() |
| 517 | # provide default values for all options; may be overridden |
| 518 | # by Distutils client, by command-line options, or by options |
| 519 | # from option file |
| 520 | # set_final_options() |
| 521 | # decide on the final values for all options; this is called |
| 522 | # after all possible intervention from the outside world |
| 523 | # (command-line, option file, etc.) has been processed |
| 524 | # run() |
| 525 | # run the command: do whatever it is we're here to do, |
| 526 | # controlled by the command's various option values |
| 527 | |
| 528 | def set_default_options (self): |
| 529 | """Set default values for all the options that this command |
| 530 | supports. Note that these defaults may be overridden |
| 531 | by the command-line supplied by the user; thus, this is |
| 532 | not the place to code dependencies between options; generally, |
| 533 | 'set_default_options()' implementations are just a bunch |
| 534 | of "self.foo = None" assignments. |
| 535 | |
| 536 | This method must be implemented by all command classes.""" |
| 537 | |
| 538 | raise RuntimeError, \ |
| 539 | "abstract method -- subclass %s must override" % self.__class__ |
| 540 | |
| 541 | def set_final_options (self): |
| 542 | """Set final values for all the options that this command |
| 543 | supports. This is always called as late as possible, ie. |
| 544 | after any option assignments from the command-line or from |
| 545 | other commands have been done. Thus, this is the place to to |
| 546 | code option dependencies: if 'foo' depends on 'bar', then it |
| 547 | is safe to set 'foo' from 'bar' as long as 'foo' still has |
| 548 | the same value it was assigned in 'set_default_options()'. |
| 549 | |
| 550 | This method must be implemented by all command classes.""" |
| 551 | |
| 552 | raise RuntimeError, \ |
| 553 | "abstract method -- subclass %s must override" % self.__class__ |
| 554 | |
| 555 | def run (self): |
| 556 | """A command's raison d'etre: carry out the action it exists |
| 557 | to perform, controlled by the options initialized in |
| 558 | 'set_initial_options()', customized by the user and other |
| 559 | commands, and finalized in 'set_final_options()'. All |
| 560 | terminal output and filesystem interaction should be done by |
| 561 | 'run()'. |
| 562 | |
| 563 | This method must be implemented by all command classes.""" |
| 564 | |
| 565 | raise RuntimeError, \ |
| 566 | "abstract method -- subclass %s must override" % self.__class__ |
| 567 | |
| 568 | def announce (self, msg, level=1): |
| 569 | """If the Distribution instance to which this command belongs |
| 570 | has a verbosity level of greater than or equal to 'level' |
| 571 | print 'msg' to stdout.""" |
| 572 | if self.distribution.verbose >= level: |
| 573 | print msg |
| 574 | |
| 575 | |
| 576 | # -- Option query/set methods -------------------------------------- |
| 577 | |
| 578 | def get_option (self, option): |
| 579 | """Return the value of a single option for this command. Raise |
| 580 | DistutilsOptionError if 'option' is not known.""" |
| 581 | try: |
| 582 | return getattr (self, option) |
| 583 | except AttributeError: |
| 584 | raise DistutilsOptionError, \ |
| 585 | "command %s: no such option %s" % \ |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 586 | (self.get_command_name(), option) |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 587 | |
| 588 | |
| 589 | def get_options (self, *options): |
| 590 | """Return (as a tuple) the values of several options for this |
| 591 | command. Raise DistutilsOptionError if any of the options in |
| 592 | 'options' are not known.""" |
| 593 | |
| 594 | values = [] |
| 595 | try: |
| 596 | for opt in options: |
| 597 | values.append (getattr (self, opt)) |
| 598 | except AttributeError, name: |
| 599 | raise DistutilsOptionError, \ |
| 600 | "command %s: no such option %s" % \ |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 601 | (self.get_command_name(), name) |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 602 | |
| 603 | return tuple (values) |
| 604 | |
| 605 | |
| 606 | def set_option (self, option, value): |
| 607 | """Set the value of a single option for this command. Raise |
| 608 | DistutilsOptionError if 'option' is not known.""" |
| 609 | |
| 610 | if not hasattr (self, option): |
| 611 | raise DistutilsOptionError, \ |
Greg Ward | 1ae3246 | 1999-09-13 03:03:01 +0000 | [diff] [blame] | 612 | "command '%s': no such option '%s'" % \ |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 613 | (self.get_command_name(), option) |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 614 | if value is not None: |
| 615 | setattr (self, option, value) |
| 616 | |
| 617 | def set_options (self, **optval): |
| 618 | """Set the values of several options for this command. Raise |
| 619 | DistutilsOptionError if any of the options specified as |
| 620 | keyword arguments are not known.""" |
| 621 | |
| 622 | for k in optval.keys(): |
| 623 | if optval[k] is not None: |
| 624 | self.set_option (k, optval[k]) |
| 625 | |
| 626 | |
| 627 | # -- Convenience methods for commands ------------------------------ |
| 628 | |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 629 | def get_command_name (self): |
| 630 | if hasattr (self, 'command_name'): |
| 631 | return self.command_name |
| 632 | else: |
| 633 | class_name = self.__class__.__name__ |
| 634 | |
| 635 | # The re.split here returs empty strings delimited by the |
| 636 | # words we're actually interested in -- e.g. "FooBarBaz" |
| 637 | # splits to ['', 'Foo', '', 'Bar', '', 'Baz', '']. Hence |
| 638 | # the 'filter' to strip out the empties. |
| 639 | words = filter (None, re.split (r'([A-Z][a-z]+)', class_name)) |
Greg Ward | df0d335 | 1999-09-21 18:41:36 +0000 | [diff] [blame] | 640 | self.command_name = string.join (map (string.lower, words), "_") |
| 641 | return self.command_name |
Greg Ward | 42926dd | 1999-09-08 02:41:09 +0000 | [diff] [blame] | 642 | |
| 643 | |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 644 | def set_undefined_options (self, src_cmd, *option_pairs): |
| 645 | """Set the values of any "undefined" options from corresponding |
| 646 | option values in some other command object. "Undefined" here |
| 647 | means "is None", which is the convention used to indicate |
| 648 | that an option has not been changed between |
| 649 | 'set_initial_values()' and 'set_final_values()'. Usually |
| 650 | called from 'set_final_values()' for options that depend on |
| 651 | some other command rather than another option of the same |
| 652 | command. 'src_cmd' is the other command from which option |
| 653 | values will be taken (a command object will be created for it |
| 654 | if necessary); the remaining arguments are |
| 655 | '(src_option,dst_option)' tuples which mean "take the value |
| 656 | of 'src_option' in the 'src_cmd' command object, and copy it |
| 657 | to 'dst_option' in the current command object".""" |
| 658 | |
| 659 | # Option_pairs: list of (src_option, dst_option) tuples |
| 660 | |
| 661 | src_cmd_obj = self.distribution.find_command_obj (src_cmd) |
| 662 | src_cmd_obj.set_final_options () |
| 663 | try: |
| 664 | for (src_option, dst_option) in option_pairs: |
| 665 | if getattr (self, dst_option) is None: |
| 666 | self.set_option (dst_option, |
| 667 | src_cmd_obj.get_option (src_option)) |
| 668 | except AttributeError, name: |
| 669 | # duh, which command? |
| 670 | raise DistutilsOptionError, "unknown option %s" % name |
| 671 | |
| 672 | |
| 673 | def set_peer_option (self, command, option, value): |
| 674 | """Attempt to simulate a command-line override of some option |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 675 | value in another command. Finds the command object for |
| 676 | 'command', sets its 'option' to 'value', and unconditionally |
| 677 | calls 'set_final_options()' on it: this means that some command |
| 678 | objects may have 'set_final_options()' invoked more than once. |
| 679 | Even so, this is not entirely reliable: the other command may |
| 680 | already be initialized to its satisfaction, in which case the |
| 681 | second 'set_final_options()' invocation will have little or no |
| 682 | effect.""" |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 683 | |
| 684 | cmd_obj = self.distribution.find_command_obj (command) |
| 685 | cmd_obj.set_option (option, value) |
| 686 | cmd_obj.set_final_options () |
| 687 | |
| 688 | |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 689 | def find_peer (self, command, create=1): |
| 690 | """Wrapper around Distribution's 'find_command_obj()' method: |
| 691 | find (create if necessary and 'create' is true) the command |
| 692 | object for 'command'..""" |
| 693 | |
| 694 | return self.distribution.find_command_obj (command, create) |
| 695 | |
| 696 | |
Greg Ward | 1ae3246 | 1999-09-13 03:03:01 +0000 | [diff] [blame] | 697 | def get_peer_option (self, command, option): |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 698 | """Find or create the command object for 'command', and return |
| 699 | its 'option' option.""" |
| 700 | |
Greg Ward | 1ae3246 | 1999-09-13 03:03:01 +0000 | [diff] [blame] | 701 | cmd_obj = self.distribution.find_command_obj (command) |
| 702 | return cmd_obj.get_option (option) |
| 703 | |
| 704 | |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 705 | def run_peer (self, command): |
| 706 | """Run some other command: uses the 'run_command()' method of |
| 707 | Distribution, which creates the command object if necessary |
| 708 | and then invokes its 'run()' method.""" |
| 709 | |
| 710 | self.distribution.run_command (command) |
| 711 | |
Greg Ward | 06ca948 | 1999-04-04 02:58:07 +0000 | [diff] [blame] | 712 | |
| 713 | # -- External world manipulation ----------------------------------- |
| 714 | |
Greg Ward | df0d335 | 1999-09-21 18:41:36 +0000 | [diff] [blame] | 715 | def warn (self, msg): |
| 716 | sys.stderr.write ("warning: %s: %s\n" % |
| 717 | (self.get_command_name(), msg)) |
| 718 | |
| 719 | |
Greg Ward | 06ca948 | 1999-04-04 02:58:07 +0000 | [diff] [blame] | 720 | def execute (self, func, args, msg=None, level=1): |
| 721 | """Perform some action that affects the outside world (eg. |
| 722 | by writing to the filesystem). Such actions are special because |
| 723 | they should be disabled by the "dry run" flag (carried around by |
| 724 | the Command's Distribution), and should announce themselves if |
| 725 | the current verbosity level is high enough. This method takes |
| 726 | care of all that bureaucracy for you; all you have to do is |
| 727 | supply the funtion to call and an argument tuple for it (to |
| 728 | embody the "external action" being performed), a message to |
| 729 | print if the verbosity level is high enough, and an optional |
| 730 | verbosity threshold.""" |
| 731 | |
| 732 | |
| 733 | # Generate a message if we weren't passed one |
| 734 | if msg is None: |
| 735 | msg = "%s %s" % (func.__name__, `args`) |
| 736 | if msg[-2:] == ',)': # correct for singleton tuple |
| 737 | msg = msg[0:-2] + ')' |
| 738 | |
| 739 | # Print it if verbosity level is high enough |
| 740 | self.announce (msg, level) |
| 741 | |
| 742 | # And do it, as long as we're not in dry-run mode |
| 743 | if not self.distribution.dry_run: |
| 744 | apply (func, args) |
| 745 | |
| 746 | # execute() |
| 747 | |
| 748 | |
| 749 | def mkpath (self, name, mode=0777): |
| 750 | util.mkpath (name, mode, |
| 751 | self.distribution.verbose, self.distribution.dry_run) |
| 752 | |
| 753 | |
| 754 | def copy_file (self, infile, outfile, |
| 755 | preserve_mode=1, preserve_times=1, update=1, level=1): |
| 756 | """Copy a file respecting verbose and dry-run flags.""" |
| 757 | |
Greg Ward | 884df45 | 1999-05-02 21:42:05 +0000 | [diff] [blame] | 758 | return util.copy_file (infile, outfile, |
| 759 | preserve_mode, preserve_times, |
| 760 | update, self.distribution.verbose >= level, |
| 761 | self.distribution.dry_run) |
Greg Ward | 06ca948 | 1999-04-04 02:58:07 +0000 | [diff] [blame] | 762 | |
| 763 | |
| 764 | def copy_tree (self, infile, outfile, |
| 765 | preserve_mode=1, preserve_times=1, preserve_symlinks=0, |
| 766 | update=1, level=1): |
| 767 | """Copy an entire directory tree respecting verbose and dry-run |
| 768 | flags.""" |
| 769 | |
Greg Ward | 884df45 | 1999-05-02 21:42:05 +0000 | [diff] [blame] | 770 | return util.copy_tree (infile, outfile, |
| 771 | preserve_mode,preserve_times,preserve_symlinks, |
| 772 | update, self.distribution.verbose >= level, |
| 773 | self.distribution.dry_run) |
Greg Ward | 06ca948 | 1999-04-04 02:58:07 +0000 | [diff] [blame] | 774 | |
| 775 | |
Greg Ward | 1ae3246 | 1999-09-13 03:03:01 +0000 | [diff] [blame] | 776 | def move_file (self, src, dst, level=1): |
| 777 | """Move a file respecting verbose and dry-run flags.""" |
| 778 | return util.move_file (src, dst, |
| 779 | self.distribution.verbose >= level, |
| 780 | self.distribution.dry_run) |
| 781 | |
| 782 | |
Greg Ward | 3868eb9 | 1999-09-29 12:12:19 +0000 | [diff] [blame^] | 783 | def spawn (self, cmd, search_path=1, level=1): |
| 784 | from distutils.spawn import spawn |
| 785 | spawn (cmd, search_path, |
| 786 | self.distribution.verbose >= level, |
| 787 | self.distribution.dry_run) |
| 788 | |
| 789 | |
Greg Ward | 06ca948 | 1999-04-04 02:58:07 +0000 | [diff] [blame] | 790 | def make_file (self, infiles, outfile, func, args, |
| 791 | exec_msg=None, skip_msg=None, level=1): |
| 792 | |
| 793 | """Special case of 'execute()' for operations that process one or |
| 794 | more input files and generate one output file. Works just like |
| 795 | 'execute()', except the operation is skipped and a different |
| 796 | message printed if 'outfile' already exists and is newer than |
| 797 | all files listed in 'infiles'.""" |
| 798 | |
| 799 | |
| 800 | if exec_msg is None: |
| 801 | exec_msg = "generating %s from %s" % \ |
| 802 | (outfile, string.join (infiles, ', ')) |
| 803 | if skip_msg is None: |
| 804 | skip_msg = "skipping %s (inputs unchanged)" % outfile |
| 805 | |
| 806 | |
| 807 | # Allow 'infiles' to be a single string |
| 808 | if type (infiles) is StringType: |
| 809 | infiles = (infiles,) |
| 810 | elif type (infiles) not in (ListType, TupleType): |
| 811 | raise TypeError, \ |
| 812 | "'infiles' must be a string, or a list or tuple of strings" |
| 813 | |
| 814 | # XXX this stuff should probably be moved off to a function |
| 815 | # in 'distutils.util' |
| 816 | from stat import * |
| 817 | |
| 818 | if os.path.exists (outfile): |
| 819 | out_mtime = os.stat (outfile)[ST_MTIME] |
| 820 | |
| 821 | # Loop over all infiles. If any infile is newer than outfile, |
| 822 | # then we'll have to regenerate outfile |
| 823 | for f in infiles: |
| 824 | in_mtime = os.stat (f)[ST_MTIME] |
| 825 | if in_mtime > out_mtime: |
| 826 | runit = 1 |
| 827 | break |
| 828 | else: |
| 829 | runit = 0 |
| 830 | |
| 831 | else: |
| 832 | runit = 1 |
| 833 | |
| 834 | # If we determined that 'outfile' must be regenerated, then |
| 835 | # perform the action that presumably regenerates it |
| 836 | if runit: |
| 837 | self.execute (func, args, exec_msg, level) |
| 838 | |
| 839 | # Otherwise, print the "skip" message |
| 840 | else: |
| 841 | self.announce (skip_msg, level) |
| 842 | |
| 843 | # make_file () |
| 844 | |
| 845 | |
| 846 | # def make_files (self, infiles, outfiles, func, args, |
| 847 | # exec_msg=None, skip_msg=None, level=1): |
| 848 | |
| 849 | # """Special case of 'execute()' for operations that process one or |
| 850 | # more input files and generate one or more output files. Works |
| 851 | # just like 'execute()', except the operation is skipped and a |
| 852 | # different message printed if all files listed in 'outfiles' |
| 853 | # already exist and are newer than all files listed in |
| 854 | # 'infiles'.""" |
| 855 | |
| 856 | # pass |
| 857 | |
| 858 | |
| 859 | |
Greg Ward | 2689e3d | 1999-03-22 14:52:19 +0000 | [diff] [blame] | 860 | # end class Command |