PageRenderTime 369ms CodeModel.GetById 141ms app.highlight 110ms RepoModel.GetById 111ms app.codeStats 1ms

/Lib/distutils/cmd.py

http://unladen-swallow.googlecode.com/
Python | 478 lines | 450 code | 7 blank | 21 comment | 7 complexity | 18b858e183af696d04e2bc099e398fd5 MD5 | raw file
  1"""distutils.cmd
  2
  3Provides the Command class, the base class for the command classes
  4in the distutils.command package.
  5"""
  6
  7# This module should be kept compatible with Python 2.1.
  8
  9__revision__ = "$Id: cmd.py 37828 2004-11-10 22:23:15Z loewis $"
 10
 11import sys, os, string, re
 12from types import *
 13from distutils.errors import *
 14from distutils import util, dir_util, file_util, archive_util, dep_util
 15from distutils import log
 16
 17class Command:
 18    """Abstract base class for defining command classes, the "worker bees"
 19    of the Distutils.  A useful analogy for command classes is to think of
 20    them as subroutines with local variables called "options".  The options
 21    are "declared" in 'initialize_options()' and "defined" (given their
 22    final values, aka "finalized") in 'finalize_options()', both of which
 23    must be defined by every command class.  The distinction between the
 24    two is necessary because option values might come from the outside
 25    world (command line, config file, ...), and any options dependent on
 26    other options must be computed *after* these outside influences have
 27    been processed -- hence 'finalize_options()'.  The "body" of the
 28    subroutine, where it does all its work based on the values of its
 29    options, is the 'run()' method, which must also be implemented by every
 30    command class.
 31    """
 32
 33    # 'sub_commands' formalizes the notion of a "family" of commands,
 34    # eg. "install" as the parent with sub-commands "install_lib",
 35    # "install_headers", etc.  The parent of a family of commands
 36    # defines 'sub_commands' as a class attribute; it's a list of
 37    #    (command_name : string, predicate : unbound_method | string | None)
 38    # tuples, where 'predicate' is a method of the parent command that
 39    # determines whether the corresponding command is applicable in the
 40    # current situation.  (Eg. we "install_headers" is only applicable if
 41    # we have any C header files to install.)  If 'predicate' is None,
 42    # that command is always applicable.
 43    #
 44    # 'sub_commands' is usually defined at the *end* of a class, because
 45    # predicates can be unbound methods, so they must already have been
 46    # defined.  The canonical example is the "install" command.
 47    sub_commands = []
 48
 49
 50    # -- Creation/initialization methods -------------------------------
 51
 52    def __init__ (self, dist):
 53        """Create and initialize a new Command object.  Most importantly,
 54        invokes the 'initialize_options()' method, which is the real
 55        initializer and depends on the actual command being
 56        instantiated.
 57        """
 58        # late import because of mutual dependence between these classes
 59        from distutils.dist import Distribution
 60
 61        if not isinstance(dist, Distribution):
 62            raise TypeError, "dist must be a Distribution instance"
 63        if self.__class__ is Command:
 64            raise RuntimeError, "Command is an abstract class"
 65
 66        self.distribution = dist
 67        self.initialize_options()
 68
 69        # Per-command versions of the global flags, so that the user can
 70        # customize Distutils' behaviour command-by-command and let some
 71        # commands fall back on the Distribution's behaviour.  None means
 72        # "not defined, check self.distribution's copy", while 0 or 1 mean
 73        # false and true (duh).  Note that this means figuring out the real
 74        # value of each flag is a touch complicated -- hence "self._dry_run"
 75        # will be handled by __getattr__, below.
 76        # XXX This needs to be fixed.
 77        self._dry_run = None
 78
 79        # verbose is largely ignored, but needs to be set for
 80        # backwards compatibility (I think)?
 81        self.verbose = dist.verbose
 82
 83        # Some commands define a 'self.force' option to ignore file
 84        # timestamps, but methods defined *here* assume that
 85        # 'self.force' exists for all commands.  So define it here
 86        # just to be safe.
 87        self.force = None
 88
 89        # The 'help' flag is just used for command-line parsing, so
 90        # none of that complicated bureaucracy is needed.
 91        self.help = 0
 92
 93        # 'finalized' records whether or not 'finalize_options()' has been
 94        # called.  'finalize_options()' itself should not pay attention to
 95        # this flag: it is the business of 'ensure_finalized()', which
 96        # always calls 'finalize_options()', to respect/update it.
 97        self.finalized = 0
 98
 99    # __init__ ()
100
101
102    # XXX A more explicit way to customize dry_run would be better.
103
104    def __getattr__ (self, attr):
105        if attr == 'dry_run':
106            myval = getattr(self, "_" + attr)
107            if myval is None:
108                return getattr(self.distribution, attr)
109            else:
110                return myval
111        else:
112            raise AttributeError, attr
113
114
115    def ensure_finalized (self):
116        if not self.finalized:
117            self.finalize_options()
118        self.finalized = 1
119
120
121    # Subclasses must define:
122    #   initialize_options()
123    #     provide default values for all options; may be customized by
124    #     setup script, by options from config file(s), or by command-line
125    #     options
126    #   finalize_options()
127    #     decide on the final values for all options; this is called
128    #     after all possible intervention from the outside world
129    #     (command-line, option file, etc.) has been processed
130    #   run()
131    #     run the command: do whatever it is we're here to do,
132    #     controlled by the command's various option values
133
134    def initialize_options (self):
135        """Set default values for all the options that this command
136        supports.  Note that these defaults may be overridden by other
137        commands, by the setup script, by config files, or by the
138        command-line.  Thus, this is not the place to code dependencies
139        between options; generally, 'initialize_options()' implementations
140        are just a bunch of "self.foo = None" assignments.
141
142        This method must be implemented by all command classes.
143        """
144        raise RuntimeError, \
145              "abstract method -- subclass %s must override" % self.__class__
146
147    def finalize_options (self):
148        """Set final values for all the options that this command supports.
149        This is always called as late as possible, ie.  after any option
150        assignments from the command-line or from other commands have been
151        done.  Thus, this is the place to code option dependencies: if
152        'foo' depends on 'bar', then it is safe to set 'foo' from 'bar' as
153        long as 'foo' still has the same value it was assigned in
154        'initialize_options()'.
155
156        This method must be implemented by all command classes.
157        """
158        raise RuntimeError, \
159              "abstract method -- subclass %s must override" % self.__class__
160
161
162    def dump_options (self, header=None, indent=""):
163        from distutils.fancy_getopt import longopt_xlate
164        if header is None:
165            header = "command options for '%s':" % self.get_command_name()
166        print indent + header
167        indent = indent + "  "
168        for (option, _, _) in self.user_options:
169            option = string.translate(option, longopt_xlate)
170            if option[-1] == "=":
171                option = option[:-1]
172            value = getattr(self, option)
173            print indent + "%s = %s" % (option, value)
174
175
176    def run (self):
177        """A command's raison d'etre: carry out the action it exists to
178        perform, controlled by the options initialized in
179        'initialize_options()', customized by other commands, the setup
180        script, the command-line, and config files, and finalized in
181        'finalize_options()'.  All terminal output and filesystem
182        interaction should be done by 'run()'.
183
184        This method must be implemented by all command classes.
185        """
186
187        raise RuntimeError, \
188              "abstract method -- subclass %s must override" % self.__class__
189
190    def announce (self, msg, level=1):
191        """If the current verbosity level is of greater than or equal to
192        'level' print 'msg' to stdout.
193        """
194        log.log(level, msg)
195
196    def debug_print (self, msg):
197        """Print 'msg' to stdout if the global DEBUG (taken from the
198        DISTUTILS_DEBUG environment variable) flag is true.
199        """
200        from distutils.debug import DEBUG
201        if DEBUG:
202            print msg
203            sys.stdout.flush()
204
205
206
207    # -- Option validation methods -------------------------------------
208    # (these are very handy in writing the 'finalize_options()' method)
209    #
210    # NB. the general philosophy here is to ensure that a particular option
211    # value meets certain type and value constraints.  If not, we try to
212    # force it into conformance (eg. if we expect a list but have a string,
213    # split the string on comma and/or whitespace).  If we can't force the
214    # option into conformance, raise DistutilsOptionError.  Thus, command
215    # classes need do nothing more than (eg.)
216    #   self.ensure_string_list('foo')
217    # and they can be guaranteed that thereafter, self.foo will be
218    # a list of strings.
219
220    def _ensure_stringlike (self, option, what, default=None):
221        val = getattr(self, option)
222        if val is None:
223            setattr(self, option, default)
224            return default
225        elif type(val) is not StringType:
226            raise DistutilsOptionError, \
227                  "'%s' must be a %s (got `%s`)" % (option, what, val)
228        return val
229
230    def ensure_string (self, option, default=None):
231        """Ensure that 'option' is a string; if not defined, set it to
232        'default'.
233        """
234        self._ensure_stringlike(option, "string", default)
235
236    def ensure_string_list (self, option):
237        """Ensure that 'option' is a list of strings.  If 'option' is
238        currently a string, we split it either on /,\s*/ or /\s+/, so
239        "foo bar baz", "foo,bar,baz", and "foo,   bar baz" all become
240        ["foo", "bar", "baz"].
241        """
242        val = getattr(self, option)
243        if val is None:
244            return
245        elif type(val) is StringType:
246            setattr(self, option, re.split(r',\s*|\s+', val))
247        else:
248            if type(val) is ListType:
249                types = map(type, val)
250                ok = (types == [StringType] * len(val))
251            else:
252                ok = 0
253
254            if not ok:
255                raise DistutilsOptionError, \
256                      "'%s' must be a list of strings (got %r)" % \
257                      (option, val)
258
259    def _ensure_tested_string (self, option, tester,
260                               what, error_fmt, default=None):
261        val = self._ensure_stringlike(option, what, default)
262        if val is not None and not tester(val):
263            raise DistutilsOptionError, \
264                  ("error in '%s' option: " + error_fmt) % (option, val)
265
266    def ensure_filename (self, option):
267        """Ensure that 'option' is the name of an existing file."""
268        self._ensure_tested_string(option, os.path.isfile,
269                                   "filename",
270                                   "'%s' does not exist or is not a file")
271
272    def ensure_dirname (self, option):
273        self._ensure_tested_string(option, os.path.isdir,
274                                   "directory name",
275                                   "'%s' does not exist or is not a directory")
276
277
278    # -- Convenience methods for commands ------------------------------
279
280    def get_command_name (self):
281        if hasattr(self, 'command_name'):
282            return self.command_name
283        else:
284            return self.__class__.__name__
285
286
287    def set_undefined_options (self, src_cmd, *option_pairs):
288        """Set the values of any "undefined" options from corresponding
289        option values in some other command object.  "Undefined" here means
290        "is None", which is the convention used to indicate that an option
291        has not been changed between 'initialize_options()' and
292        'finalize_options()'.  Usually called from 'finalize_options()' for
293        options that depend on some other command rather than another
294        option of the same command.  'src_cmd' is the other command from
295        which option values will be taken (a command object will be created
296        for it if necessary); the remaining arguments are
297        '(src_option,dst_option)' tuples which mean "take the value of
298        'src_option' in the 'src_cmd' command object, and copy it to
299        'dst_option' in the current command object".
300        """
301
302        # Option_pairs: list of (src_option, dst_option) tuples
303
304        src_cmd_obj = self.distribution.get_command_obj(src_cmd)
305        src_cmd_obj.ensure_finalized()
306        for (src_option, dst_option) in option_pairs:
307            if getattr(self, dst_option) is None:
308                setattr(self, dst_option,
309                        getattr(src_cmd_obj, src_option))
310
311
312    def get_finalized_command (self, command, create=1):
313        """Wrapper around Distribution's 'get_command_obj()' method: find
314        (create if necessary and 'create' is true) the command object for
315        'command', call its 'ensure_finalized()' method, and return the
316        finalized command object.
317        """
318        cmd_obj = self.distribution.get_command_obj(command, create)
319        cmd_obj.ensure_finalized()
320        return cmd_obj
321
322    # XXX rename to 'get_reinitialized_command()'? (should do the
323    # same in dist.py, if so)
324    def reinitialize_command (self, command, reinit_subcommands=0):
325        return self.distribution.reinitialize_command(
326            command, reinit_subcommands)
327
328    def run_command (self, command):
329        """Run some other command: uses the 'run_command()' method of
330        Distribution, which creates and finalizes the command object if
331        necessary and then invokes its 'run()' method.
332        """
333        self.distribution.run_command(command)
334
335
336    def get_sub_commands (self):
337        """Determine the sub-commands that are relevant in the current
338        distribution (ie., that need to be run).  This is based on the
339        'sub_commands' class attribute: each tuple in that list may include
340        a method that we call to determine if the subcommand needs to be
341        run for the current distribution.  Return a list of command names.
342        """
343        commands = []
344        for (cmd_name, method) in self.sub_commands:
345            if method is None or method(self):
346                commands.append(cmd_name)
347        return commands
348
349
350    # -- External world manipulation -----------------------------------
351
352    def warn (self, msg):
353        sys.stderr.write("warning: %s: %s\n" %
354                         (self.get_command_name(), msg))
355
356
357    def execute (self, func, args, msg=None, level=1):
358        util.execute(func, args, msg, dry_run=self.dry_run)
359
360
361    def mkpath (self, name, mode=0777):
362        dir_util.mkpath(name, mode, dry_run=self.dry_run)
363
364
365    def copy_file (self, infile, outfile,
366                   preserve_mode=1, preserve_times=1, link=None, level=1):
367        """Copy a file respecting verbose, dry-run and force flags.  (The
368        former two default to whatever is in the Distribution object, and
369        the latter defaults to false for commands that don't define it.)"""
370
371        return file_util.copy_file(
372            infile, outfile,
373            preserve_mode, preserve_times,
374            not self.force,
375            link,
376            dry_run=self.dry_run)
377
378
379    def copy_tree (self, infile, outfile,
380                   preserve_mode=1, preserve_times=1, preserve_symlinks=0,
381                   level=1):
382        """Copy an entire directory tree respecting verbose, dry-run,
383        and force flags.
384        """
385        return dir_util.copy_tree(
386            infile, outfile,
387            preserve_mode,preserve_times,preserve_symlinks,
388            not self.force,
389            dry_run=self.dry_run)
390
391    def move_file (self, src, dst, level=1):
392        """Move a file respectin dry-run flag."""
393        return file_util.move_file(src, dst, dry_run = self.dry_run)
394
395    def spawn (self, cmd, search_path=1, level=1):
396        """Spawn an external command respecting dry-run flag."""
397        from distutils.spawn import spawn
398        spawn(cmd, search_path, dry_run= self.dry_run)
399
400    def make_archive (self, base_name, format,
401                      root_dir=None, base_dir=None):
402        return archive_util.make_archive(
403            base_name, format, root_dir, base_dir, dry_run=self.dry_run)
404
405
406    def make_file (self, infiles, outfile, func, args,
407                   exec_msg=None, skip_msg=None, level=1):
408        """Special case of 'execute()' for operations that process one or
409        more input files and generate one output file.  Works just like
410        'execute()', except the operation is skipped and a different
411        message printed if 'outfile' already exists and is newer than all
412        files listed in 'infiles'.  If the command defined 'self.force',
413        and it is true, then the command is unconditionally run -- does no
414        timestamp checks.
415        """
416        if exec_msg is None:
417            exec_msg = "generating %s from %s" % \
418                       (outfile, string.join(infiles, ', '))
419        if skip_msg is None:
420            skip_msg = "skipping %s (inputs unchanged)" % outfile
421
422
423        # Allow 'infiles' to be a single string
424        if type(infiles) is StringType:
425            infiles = (infiles,)
426        elif type(infiles) not in (ListType, TupleType):
427            raise TypeError, \
428                  "'infiles' must be a string, or a list or tuple of strings"
429
430        # If 'outfile' must be regenerated (either because it doesn't
431        # exist, is out-of-date, or the 'force' flag is true) then
432        # perform the action that presumably regenerates it
433        if self.force or dep_util.newer_group (infiles, outfile):
434            self.execute(func, args, exec_msg, level)
435
436        # Otherwise, print the "skip" message
437        else:
438            log.debug(skip_msg)
439
440    # make_file ()
441
442# class Command
443
444
445# XXX 'install_misc' class not currently used -- it was the base class for
446# both 'install_scripts' and 'install_data', but they outgrew it.  It might
447# still be useful for 'install_headers', though, so I'm keeping it around
448# for the time being.
449
450class install_misc (Command):
451    """Common base class for installing some files in a subdirectory.
452    Currently used by install_data and install_scripts.
453    """
454
455    user_options = [('install-dir=', 'd', "directory to install the files to")]
456
457    def initialize_options (self):
458        self.install_dir = None
459        self.outfiles = []
460
461    def _install_dir_from (self, dirname):
462        self.set_undefined_options('install', (dirname, 'install_dir'))
463
464    def _copy_files (self, filelist):
465        self.outfiles = []
466        if not filelist:
467            return
468        self.mkpath(self.install_dir)
469        for f in filelist:
470            self.copy_file(f, self.install_dir)
471            self.outfiles.append(os.path.join(self.install_dir, f))
472
473    def get_outputs (self):
474        return self.outfiles
475
476
477if __name__ == "__main__":
478    print "ok"