cmd.py 18.9 KB
Newer Older
1 2 3
"""distutils.cmd

Provides the Command class, the base class for the command classes
4 5
in the distutils.command package.
"""
6 7 8 9 10 11

# created 2000/04/03, Greg Ward
# (extricated from core.py; actually dates back to the beginning)

__revision__ = "$Id$"

12
import sys, os, string, re
13 14
from types import *
from distutils.errors import *
15
from distutils import util, dir_util, file_util, archive_util, dep_util
16 17 18 19


class Command:
    """Abstract base class for defining command classes, the "worker bees"
20 21 22 23 24 25 26 27 28 29 30 31 32
    of the Distutils.  A useful analogy for command classes is to think of
    them as subroutines with local variables called "options".  The options
    are "declared" in 'initialize_options()' and "defined" (given their
    final values, aka "finalized") in 'finalize_options()', both of which
    must be defined by every command class.  The distinction between the
    two is necessary because option values might come from the outside
    world (command line, config file, ...), and any options dependent on
    other options must be computed *after* these outside influences have
    been processed -- hence 'finalize_options()'.  The "body" of the
    subroutine, where it does all its work based on the values of its
    options, is the 'run()' method, which must also be implemented by every
    command class.
    """
33

34 35 36 37 38 39 40 41 42 43
    # 'sub_commands' formalizes the notion of a "family" of commands,
    # eg. "install" as the parent with sub-commands "install_lib",
    # "install_headers", etc.  The parent of a family of commands
    # defines 'sub_commands' as a class attribute; it's a list of
    #    (command_name : string, predicate : unbound_method | string | None)
    # tuples, where 'predicate' is a method of the parent command that
    # determines whether the corresponding command is applicable in the
    # current situation.  (Eg. we "install_headers" is only applicable if
    # we have any C header files to install.)  If 'predicate' is None,
    # that command is always applicable.
Fred Drake's avatar
Fred Drake committed
44
    #
45 46 47 48 49 50
    # 'sub_commands' is usually defined at the *end* of a class, because
    # predicates can be unbound methods, so they must already have been
    # defined.  The canonical example is the "install" command.
    sub_commands = []


51 52 53 54
    # -- Creation/initialization methods -------------------------------

    def __init__ (self, dist):
        """Create and initialize a new Command object.  Most importantly,
55 56 57 58
        invokes the 'initialize_options()' method, which is the real
        initializer and depends on the actual command being
        instantiated.
        """
59 60 61
        # late import because of mutual dependence between these classes
        from distutils.dist import Distribution

62
        if not isinstance(dist, Distribution):
63 64 65 66 67
            raise TypeError, "dist must be a Distribution instance"
        if self.__class__ is Command:
            raise RuntimeError, "Command is an abstract class"

        self.distribution = dist
68
        self.initialize_options()
69 70 71 72 73 74

        # Per-command versions of the global flags, so that the user can
        # customize Distutils' behaviour command-by-command and let some
        # commands fallback on the Distribution's behaviour.  None means
        # "not defined, check self.distribution's copy", while 0 or 1 mean
        # false and true (duh).  Note that this means figuring out the real
75
        # value of each flag is a touch complicated -- hence "self.verbose"
76 77 78 79
        # (etc.) will be handled by __getattr__, below.
        self._verbose = None
        self._dry_run = None

80 81 82 83 84 85
        # Some commands define a 'self.force' option to ignore file
        # timestamps, but methods defined *here* assume that
        # 'self.force' exists for all commands.  So define it here
        # just to be safe.
        self.force = None

86 87 88 89
        # The 'help' flag is just used for command-line parsing, so
        # none of that complicated bureaucracy is needed.
        self.help = 0

90
        # 'finalized' records whether or not 'finalize_options()' has been
91
        # called.  'finalize_options()' itself should not pay attention to
92 93 94
        # this flag: it is the business of 'ensure_finalized()', which
        # always calls 'finalize_options()', to respect/update it.
        self.finalized = 0
95 96 97 98 99

    # __init__ ()


    def __getattr__ (self, attr):
100
        if attr in ('verbose', 'dry_run'):
101
            myval = getattr(self, "_" + attr)
102
            if myval is None:
103
                return getattr(self.distribution, attr)
104 105 106 107 108 109
            else:
                return myval
        else:
            raise AttributeError, attr


110 111
    def ensure_finalized (self):
        if not self.finalized:
112
            self.finalize_options()
113
        self.finalized = 1
Fred Drake's avatar
Fred Drake committed
114

115 116 117

    # Subclasses must define:
    #   initialize_options()
118 119 120
    #     provide default values for all options; may be customized by
    #     setup script, by options from config file(s), or by command-line
    #     options
121 122 123 124 125 126 127 128 129 130
    #   finalize_options()
    #     decide on the final values for all options; this is called
    #     after all possible intervention from the outside world
    #     (command-line, option file, etc.) has been processed
    #   run()
    #     run the command: do whatever it is we're here to do,
    #     controlled by the command's various option values

    def initialize_options (self):
        """Set default values for all the options that this command
131 132 133 134 135
        supports.  Note that these defaults may be overridden by other
        commands, by the setup script, by config files, or by the
        command-line.  Thus, this is not the place to code dependencies
        between options; generally, 'initialize_options()' implementations
        are just a bunch of "self.foo = None" assignments.
Fred Drake's avatar
Fred Drake committed
136

137 138
        This method must be implemented by all command classes.
        """
139 140
        raise RuntimeError, \
              "abstract method -- subclass %s must override" % self.__class__
Fred Drake's avatar
Fred Drake committed
141

142
    def finalize_options (self):
143 144 145 146 147 148 149 150 151 152
        """Set final values for all the options that this command supports.
        This is always called as late as possible, ie.  after any option
        assignments from the command-line or from other commands have been
        done.  Thus, this is the place to to code option dependencies: if
        'foo' depends on 'bar', then it is safe to set 'foo' from 'bar' as
        long as 'foo' still has the same value it was assigned in
        'initialize_options()'.

        This method must be implemented by all command classes.
        """
153 154 155
        raise RuntimeError, \
              "abstract method -- subclass %s must override" % self.__class__

156 157 158 159 160 161 162 163

    def dump_options (self, header=None, indent=""):
        from distutils.fancy_getopt import longopt_xlate
        if header is None:
            header = "command options for '%s':" % self.get_command_name()
        print indent + header
        indent = indent + "  "
        for (option, _, _) in self.user_options:
164
            option = string.translate(option, longopt_xlate)
165 166 167 168 169 170
            if option[-1] == "=":
                option = option[:-1]
            value = getattr(self, option)
            print indent + "%s = %s" % (option, value)


171
    def run (self):
172 173 174 175 176 177
        """A command's raison d'etre: carry out the action it exists to
        perform, controlled by the options initialized in
        'initialize_options()', customized by other commands, the setup
        script, the command-line, and config files, and finalized in
        'finalize_options()'.  All terminal output and filesystem
        interaction should be done by 'run()'.
178

179 180
        This method must be implemented by all command classes.
        """
181 182 183 184 185

        raise RuntimeError, \
              "abstract method -- subclass %s must override" % self.__class__

    def announce (self, msg, level=1):
186 187 188
        """If the current verbosity level is of greater than or equal to
        'level' print 'msg' to stdout.
        """
189 190
        if self.verbose >= level:
            print msg
191
            sys.stdout.flush()
192

193 194 195 196 197 198 199
    def debug_print (self, msg):
        """Print 'msg' to stdout if the global DEBUG (taken from the
        DISTUTILS_DEBUG environment variable) flag is true.
        """
        from distutils.core import DEBUG
        if DEBUG:
            print msg
200
            sys.stdout.flush()
Fred Drake's avatar
Fred Drake committed
201

202

203

204 205
    # -- Option validation methods -------------------------------------
    # (these are very handy in writing the 'finalize_options()' method)
Fred Drake's avatar
Fred Drake committed
206
    #
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
    # NB. the general philosophy here is to ensure that a particular option
    # value meets certain type and value constraints.  If not, we try to
    # force it into conformance (eg. if we expect a list but have a string,
    # split the string on comma and/or whitespace).  If we can't force the
    # option into conformance, raise DistutilsOptionError.  Thus, command
    # classes need do nothing more than (eg.)
    #   self.ensure_string_list('foo')
    # and they can be guaranteed that thereafter, self.foo will be
    # a list of strings.

    def _ensure_stringlike (self, option, what, default=None):
        val = getattr(self, option)
        if val is None:
            setattr(self, option, default)
            return default
        elif type(val) is not StringType:
            raise DistutilsOptionError, \
                  "'%s' must be a %s (got `%s`)" % (option, what, val)
        return val

    def ensure_string (self, option, default=None):
        """Ensure that 'option' is a string; if not defined, set it to
        'default'.
        """
        self._ensure_stringlike(option, "string", default)

    def ensure_string_list (self, option):
        """Ensure that 'option' is a list of strings.  If 'option' is
        currently a string, we split it either on /,\s*/ or /\s+/, so
        "foo bar baz", "foo,bar,baz", and "foo,   bar baz" all become
        ["foo", "bar", "baz"].
        """
        val = getattr(self, option)
        if val is None:
            return
        elif type(val) is StringType:
            setattr(self, option, re.split(r',\s*|\s+', val))
        else:
            if type(val) is ListType:
                types = map(type, val)
                ok = (types == [StringType] * len(val))
            else:
                ok = 0

            if not ok:
                raise DistutilsOptionError, \
                      "'%s' must be a list of strings (got %s)" % \
                      (option, `val`)
Fred Drake's avatar
Fred Drake committed
255

256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    def _ensure_tested_string (self, option, tester,
                               what, error_fmt, default=None):
        val = self._ensure_stringlike(option, what, default)
        if val is not None and not tester(val):
            raise DistutilsOptionError, \
                  ("error in '%s' option: " + error_fmt) % (option, val)

    def ensure_filename (self, option):
        """Ensure that 'option' is the name of an existing file."""
        self._ensure_tested_string(option, os.path.isfile,
                                   "filename",
                                   "'%s' does not exist or is not a file")

    def ensure_dirname (self, option):
        self._ensure_tested_string(option, os.path.isdir,
                                   "directory name",
                                   "'%s' does not exist or is not a directory")


275 276 277
    # -- Convenience methods for commands ------------------------------

    def get_command_name (self):
278
        if hasattr(self, 'command_name'):
279 280 281 282 283 284 285
            return self.command_name
        else:
            return self.__class__.__name__


    def set_undefined_options (self, src_cmd, *option_pairs):
        """Set the values of any "undefined" options from corresponding
286 287 288 289 290 291 292 293 294 295 296 297
        option values in some other command object.  "Undefined" here means
        "is None", which is the convention used to indicate that an option
        has not been changed between 'initialize_options()' and
        'finalize_options()'.  Usually called from 'finalize_options()' for
        options that depend on some other command rather than another
        option of the same command.  'src_cmd' is the other command from
        which option values will be taken (a command object will be created
        for it if necessary); the remaining arguments are
        '(src_option,dst_option)' tuples which mean "take the value of
        'src_option' in the 'src_cmd' command object, and copy it to
        'dst_option' in the current command object".
        """
298 299 300

        # Option_pairs: list of (src_option, dst_option) tuples

301 302
        src_cmd_obj = self.distribution.get_command_obj(src_cmd)
        src_cmd_obj.ensure_finalized()
303
        for (src_option, dst_option) in option_pairs:
304 305 306
            if getattr(self, dst_option) is None:
                setattr(self, dst_option,
                        getattr(src_cmd_obj, src_option))
307 308


309
    def get_finalized_command (self, command, create=1):
310 311 312 313 314
        """Wrapper around Distribution's 'get_command_obj()' method: find
        (create if necessary and 'create' is true) the command object for
        'command', call its 'ensure_finalized()' method, and return the
        finalized command object.
        """
315 316
        cmd_obj = self.distribution.get_command_obj(command, create)
        cmd_obj.ensure_finalized()
317 318
        return cmd_obj

319 320
    # XXX rename to 'get_reinitialized_command()'? (should do the
    # same in dist.py, if so)
321 322 323
    def reinitialize_command (self, command, reinit_subcommands=0):
        return self.distribution.reinitialize_command(
            command, reinit_subcommands)
324

325
    def run_command (self, command):
326
        """Run some other command: uses the 'run_command()' method of
327 328 329
        Distribution, which creates and finalizes the command object if
        necessary and then invokes its 'run()' method.
        """
330
        self.distribution.run_command(command)
331 332


333 334 335 336 337 338 339 340 341 342 343 344 345 346
    def get_sub_commands (self):
        """Determine the sub-commands that are relevant in the current
        distribution (ie., that need to be run).  This is based on the
        'sub_commands' class attribute: each tuple in that list may include
        a method that we call to determine if the subcommand needs to be
        run for the current distribution.  Return a list of command names.
        """
        commands = []
        for (cmd_name, method) in self.sub_commands:
            if method is None or method(self):
                commands.append(cmd_name)
        return commands


347 348 349
    # -- External world manipulation -----------------------------------

    def warn (self, msg):
350 351
        sys.stderr.write("warning: %s: %s\n" %
                         (self.get_command_name(), msg))
352 353 354


    def execute (self, func, args, msg=None, level=1):
355
        util.execute(func, args, msg, self.verbose >= level, self.dry_run)
356 357 358


    def mkpath (self, name, mode=0777):
359 360
        dir_util.mkpath(name, mode,
                        self.verbose, self.dry_run)
361 362 363 364


    def copy_file (self, infile, outfile,
                   preserve_mode=1, preserve_times=1, link=None, level=1):
365 366 367
        """Copy a file respecting verbose, dry-run and force flags.  (The
        former two default to whatever is in the Distribution object, and
        the latter defaults to false for commands that don't define it.)"""
368

369 370 371 372 373 374 375
        return file_util.copy_file(
            infile, outfile,
            preserve_mode, preserve_times,
            not self.force,
            link,
            self.verbose >= level,
            self.dry_run)
376 377 378 379 380 381


    def copy_tree (self, infile, outfile,
                   preserve_mode=1, preserve_times=1, preserve_symlinks=0,
                   level=1):
        """Copy an entire directory tree respecting verbose, dry-run,
382 383
        and force flags.
        """
384
        return dir_util.copy_tree(
Fred Drake's avatar
Fred Drake committed
385
            infile, outfile,
386 387 388 389
            preserve_mode,preserve_times,preserve_symlinks,
            not self.force,
            self.verbose >= level,
            self.dry_run)
390 391 392 393


    def move_file (self, src, dst, level=1):
        """Move a file respecting verbose and dry-run flags."""
394 395 396
        return file_util.move_file(src, dst,
                                   self.verbose >= level,
                                   self.dry_run)
397 398 399


    def spawn (self, cmd, search_path=1, level=1):
400
        """Spawn an external command respecting verbose and dry-run flags."""
401
        from distutils.spawn import spawn
402 403 404
        spawn(cmd, search_path,
              self.verbose >= level,
              self.dry_run)
405 406 407 408


    def make_archive (self, base_name, format,
                      root_dir=None, base_dir=None):
409 410 411
        return archive_util.make_archive(
            base_name, format, root_dir, base_dir,
            self.verbose, self.dry_run)
412 413 414


    def make_file (self, infiles, outfile, func, args,
415
                   exec_msg=None, skip_msg=None, level=1):
416
        """Special case of 'execute()' for operations that process one or
417 418 419 420 421
        more input files and generate one output file.  Works just like
        'execute()', except the operation is skipped and a different
        message printed if 'outfile' already exists and is newer than all
        files listed in 'infiles'.  If the command defined 'self.force',
        and it is true, then the command is unconditionally run -- does no
422 423
        timestamp checks.
        """
424 425
        if exec_msg is None:
            exec_msg = "generating %s from %s" % \
426
                       (outfile, string.join(infiles, ', '))
427 428
        if skip_msg is None:
            skip_msg = "skipping %s (inputs unchanged)" % outfile
Fred Drake's avatar
Fred Drake committed
429

430 431

        # Allow 'infiles' to be a single string
432
        if type(infiles) is StringType:
433
            infiles = (infiles,)
434
        elif type(infiles) not in (ListType, TupleType):
435 436 437 438 439 440
            raise TypeError, \
                  "'infiles' must be a string, or a list or tuple of strings"

        # If 'outfile' must be regenerated (either because it doesn't
        # exist, is out-of-date, or the 'force' flag is true) then
        # perform the action that presumably regenerates it
441
        if self.force or dep_util.newer_group (infiles, outfile):
442
            self.execute(func, args, exec_msg, level)
443 444 445

        # Otherwise, print the "skip" message
        else:
446
            self.announce(skip_msg, level)
447 448 449 450

    # make_file ()

# class Command
451 452


453 454 455 456 457
# XXX 'install_misc' class not currently used -- it was the base class for
# both 'install_scripts' and 'install_data', but they outgrew it.  It might
# still be useful for 'install_headers', though, so I'm keeping it around
# for the time being.

458 459 460 461
class install_misc (Command):
    """Common base class for installing some files in a subdirectory.
    Currently used by install_data and install_scripts.
    """
Fred Drake's avatar
Fred Drake committed
462

463 464 465 466
    user_options = [('install-dir=', 'd', "directory to install the files to")]

    def initialize_options (self):
        self.install_dir = None
467
        self.outfiles = []
468

469
    def _install_dir_from (self, dirname):
470 471
        self.set_undefined_options('install', (dirname, 'install_dir'))

472
    def _copy_files (self, filelist):
473 474 475 476 477
        self.outfiles = []
        if not filelist:
            return
        self.mkpath(self.install_dir)
        for f in filelist:
478 479
            self.copy_file(f, self.install_dir)
            self.outfiles.append(os.path.join(self.install_dir, f))
480

481 482
    def get_outputs (self):
        return self.outfiles
483 484


485 486
if __name__ == "__main__":
    print "ok"