blob: 76a76919cd4c097784bc467d5b97f0c7f866d966 [file] [log] [blame]
Greg Wardfe6462c2000-04-04 01:40:52 +00001"""distutils.cmd
2
3Provides the Command class, the base class for the command classes
4in the distutils.command package."""
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
12from types import *
13from distutils.errors import *
14from distutils import util
15
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
20 think of them as subroutines with local variables called
21 "options". The options are "declared" in 'initialize_options()'
22 and "defined" (given their final values, aka "finalized") in
23 'finalize_options()', both of which must be defined by every
24 command class. The distinction between the two is necessary
25 because option values might come from the outside world (command
26 line, option file, ...), and any options dependent on other
27 options must be computed *after* these outside influences have
28 been processed -- hence 'finalize_options()'. The "body" of the
29 subroutine, where it does all its work based on the values of its
30 options, is the 'run()' method, which must also be implemented by
31 every command class."""
32
33 # -- Creation/initialization methods -------------------------------
34
35 def __init__ (self, dist):
36 """Create and initialize a new Command object. Most importantly,
37 invokes the 'initialize_options()' method, which is the
38 real initializer and depends on the actual command being
39 instantiated."""
40
41 # late import because of mutual dependence between these classes
42 from distutils.dist import Distribution
43
44 if not isinstance (dist, Distribution):
45 raise TypeError, "dist must be a Distribution instance"
46 if self.__class__ is Command:
47 raise RuntimeError, "Command is an abstract class"
48
49 self.distribution = dist
50 self.initialize_options ()
51
52 # Per-command versions of the global flags, so that the user can
53 # customize Distutils' behaviour command-by-command and let some
54 # commands fallback on the Distribution's behaviour. None means
55 # "not defined, check self.distribution's copy", while 0 or 1 mean
56 # false and true (duh). Note that this means figuring out the real
57 # value of each flag is a touch complicatd -- hence "self.verbose"
58 # (etc.) will be handled by __getattr__, below.
59 self._verbose = None
60 self._dry_run = None
Greg Wardfe6462c2000-04-04 01:40:52 +000061
62 # The 'help' flag is just used for command-line parsing, so
63 # none of that complicated bureaucracy is needed.
64 self.help = 0
65
66 # 'ready' records whether or not 'finalize_options()' has been
67 # called. 'finalize_options()' itself should not pay attention to
68 # this flag: it is the business of 'ensure_ready()', which always
69 # calls 'finalize_options()', to respect/update it.
70 self.ready = 0
71
72 # __init__ ()
73
74
75 def __getattr__ (self, attr):
Greg Ward68a07572000-04-10 00:18:16 +000076 if attr in ('verbose', 'dry_run'):
Greg Wardfe6462c2000-04-04 01:40:52 +000077 myval = getattr (self, "_" + attr)
78 if myval is None:
79 return getattr (self.distribution, attr)
80 else:
81 return myval
82 else:
83 raise AttributeError, attr
84
85
86 def ensure_ready (self):
87 if not self.ready:
88 self.finalize_options ()
89 self.ready = 1
90
91
92 # Subclasses must define:
93 # initialize_options()
94 # provide default values for all options; may be overridden
95 # by Distutils client, by command-line options, or by options
96 # from option file
97 # finalize_options()
98 # decide on the final values for all options; this is called
99 # after all possible intervention from the outside world
100 # (command-line, option file, etc.) has been processed
101 # run()
102 # run the command: do whatever it is we're here to do,
103 # controlled by the command's various option values
104
105 def initialize_options (self):
106 """Set default values for all the options that this command
107 supports. Note that these defaults may be overridden
108 by the command-line supplied by the user; thus, this is
109 not the place to code dependencies between options; generally,
110 'initialize_options()' implementations are just a bunch
111 of "self.foo = None" assignments.
112
113 This method must be implemented by all command classes."""
114
115 raise RuntimeError, \
116 "abstract method -- subclass %s must override" % self.__class__
117
118 def finalize_options (self):
119 """Set final values for all the options that this command
120 supports. This is always called as late as possible, ie.
121 after any option assignments from the command-line or from
122 other commands have been done. Thus, this is the place to to
123 code option dependencies: if 'foo' depends on 'bar', then it
124 is safe to set 'foo' from 'bar' as long as 'foo' still has
125 the same value it was assigned in 'initialize_options()'.
126
127 This method must be implemented by all command classes."""
128
129 raise RuntimeError, \
130 "abstract method -- subclass %s must override" % self.__class__
131
132 def run (self):
133 """A command's raison d'etre: carry out the action it exists
134 to perform, controlled by the options initialized in
135 'initialize_options()', customized by the user and other
136 commands, and finalized in 'finalize_options()'. All
137 terminal output and filesystem interaction should be done by
138 'run()'.
139
140 This method must be implemented by all command classes."""
141
142 raise RuntimeError, \
143 "abstract method -- subclass %s must override" % self.__class__
144
145 def announce (self, msg, level=1):
146 """If the Distribution instance to which this command belongs
147 has a verbosity level of greater than or equal to 'level'
148 print 'msg' to stdout."""
149
150 if self.verbose >= level:
151 print msg
152
153
154 # -- Option query/set methods --------------------------------------
155
156 def get_option (self, option):
157 """Return the value of a single option for this command. Raise
158 DistutilsOptionError if 'option' is not known."""
159 try:
160 return getattr (self, option)
161 except AttributeError:
162 raise DistutilsOptionError, \
163 "command %s: no such option %s" % \
164 (self.get_command_name(), option)
165
166
167 def get_options (self, *options):
168 """Return (as a tuple) the values of several options for this
169 command. Raise DistutilsOptionError if any of the options in
170 'options' are not known."""
171
172 values = []
173 try:
174 for opt in options:
175 values.append (getattr (self, opt))
176 except AttributeError, name:
177 raise DistutilsOptionError, \
178 "command %s: no such option %s" % \
179 (self.get_command_name(), name)
180
181 return tuple (values)
182
183
184 def set_option (self, option, value):
185 """Set the value of a single option for this command. Raise
186 DistutilsOptionError if 'option' is not known."""
187
188 if not hasattr (self, option):
189 raise DistutilsOptionError, \
190 "command '%s': no such option '%s'" % \
191 (self.get_command_name(), option)
192 if value is not None:
193 setattr (self, option, value)
194
195 def set_options (self, **optval):
196 """Set the values of several options for this command. Raise
197 DistutilsOptionError if any of the options specified as
198 keyword arguments are not known."""
199
200 for k in optval.keys():
201 if optval[k] is not None:
202 self.set_option (k, optval[k])
203
204
205 # -- Convenience methods for commands ------------------------------
206
207 def get_command_name (self):
208 if hasattr (self, 'command_name'):
209 return self.command_name
210 else:
211 return self.__class__.__name__
212
213
214 def set_undefined_options (self, src_cmd, *option_pairs):
215 """Set the values of any "undefined" options from corresponding
216 option values in some other command object. "Undefined" here
217 means "is None", which is the convention used to indicate
218 that an option has not been changed between
219 'set_initial_values()' and 'set_final_values()'. Usually
220 called from 'set_final_values()' for options that depend on
221 some other command rather than another option of the same
222 command. 'src_cmd' is the other command from which option
223 values will be taken (a command object will be created for it
224 if necessary); the remaining arguments are
225 '(src_option,dst_option)' tuples which mean "take the value
226 of 'src_option' in the 'src_cmd' command object, and copy it
227 to 'dst_option' in the current command object"."""
228
229 # Option_pairs: list of (src_option, dst_option) tuples
230
231 src_cmd_obj = self.distribution.find_command_obj (src_cmd)
232 src_cmd_obj.ensure_ready ()
233 try:
234 for (src_option, dst_option) in option_pairs:
235 if getattr (self, dst_option) is None:
236 self.set_option (dst_option,
237 src_cmd_obj.get_option (src_option))
238 except AttributeError, name:
239 # duh, which command?
240 raise DistutilsOptionError, "unknown option %s" % name
241
242
243 def find_peer (self, command, create=1):
244 """Wrapper around Distribution's 'find_command_obj()' method:
245 find (create if necessary and 'create' is true) the command
246 object for 'command'.."""
247
248 cmd_obj = self.distribution.find_command_obj (command, create)
249 cmd_obj.ensure_ready ()
250 return cmd_obj
251
252
253 def get_peer_option (self, command, option):
254 """Find or create the command object for 'command', and return
255 its 'option' option."""
256
257 cmd_obj = self.find_peer (command)
258 return cmd_obj.get_option (option)
259
260
261 def run_peer (self, command):
262 """Run some other command: uses the 'run_command()' method of
263 Distribution, which creates the command object if necessary
264 and then invokes its 'run()' method."""
265
266 self.distribution.run_command (command)
267
268
269 # -- External world manipulation -----------------------------------
270
271 def warn (self, msg):
272 sys.stderr.write ("warning: %s: %s\n" %
273 (self.get_command_name(), msg))
274
275
276 def execute (self, func, args, msg=None, level=1):
277 """Perform some action that affects the outside world (eg.
278 by writing to the filesystem). Such actions are special because
279 they should be disabled by the "dry run" flag, and should
280 announce themselves if the current verbosity level is high
281 enough. This method takes care of all that bureaucracy for you;
282 all you have to do is supply the funtion to call and an argument
283 tuple for it (to embody the "external action" being performed),
284 a message to print if the verbosity level is high enough, and an
285 optional verbosity threshold."""
286
287 # Generate a message if we weren't passed one
288 if msg is None:
289 msg = "%s %s" % (func.__name__, `args`)
290 if msg[-2:] == ',)': # correct for singleton tuple
291 msg = msg[0:-2] + ')'
292
293 # Print it if verbosity level is high enough
294 self.announce (msg, level)
295
296 # And do it, as long as we're not in dry-run mode
297 if not self.dry_run:
298 apply (func, args)
299
300 # execute()
301
302
303 def mkpath (self, name, mode=0777):
304 util.mkpath (name, mode,
305 self.verbose, self.dry_run)
306
307
308 def copy_file (self, infile, outfile,
309 preserve_mode=1, preserve_times=1, link=None, level=1):
Greg Ward68a07572000-04-10 00:18:16 +0000310 """Copy a file respecting verbose, dry-run and force flags (this
311 should only be used by commands that define 'self.force'!)."""
Greg Wardfe6462c2000-04-04 01:40:52 +0000312
313 return util.copy_file (infile, outfile,
314 preserve_mode, preserve_times,
315 not self.force,
316 link,
317 self.verbose >= level,
318 self.dry_run)
319
320
321 def copy_tree (self, infile, outfile,
322 preserve_mode=1, preserve_times=1, preserve_symlinks=0,
323 level=1):
324 """Copy an entire directory tree respecting verbose, dry-run,
Greg Ward68a07572000-04-10 00:18:16 +0000325 and force flags (again, should only be used by commands
326 that define 'self.force')."""
Greg Wardfe6462c2000-04-04 01:40:52 +0000327
328 return util.copy_tree (infile, outfile,
329 preserve_mode,preserve_times,preserve_symlinks,
330 not self.force,
331 self.verbose >= level,
332 self.dry_run)
333
334
335 def move_file (self, src, dst, level=1):
336 """Move a file respecting verbose and dry-run flags."""
337 return util.move_file (src, dst,
338 self.verbose >= level,
339 self.dry_run)
340
341
342 def spawn (self, cmd, search_path=1, level=1):
343 from distutils.spawn import spawn
344 spawn (cmd, search_path,
345 self.verbose >= level,
346 self.dry_run)
347
348
349 def make_archive (self, base_name, format,
350 root_dir=None, base_dir=None):
351 util.make_archive (base_name, format, root_dir, base_dir,
352 self.verbose, self.dry_run)
353
354
355 def make_file (self, infiles, outfile, func, args,
Greg Ward68a07572000-04-10 00:18:16 +0000356 exec_msg=None, skip_msg=None, level=1):
Greg Wardfe6462c2000-04-04 01:40:52 +0000357
358 """Special case of 'execute()' for operations that process one or
Greg Ward68a07572000-04-10 00:18:16 +0000359 more input files and generate one output file. Works just like
360 'execute()', except the operation is skipped and a different
361 message printed if 'outfile' already exists and is newer than all
362 files listed in 'infiles'. If the command defined 'self.force',
363 and it is true, then the command is unconditionally run -- does no
364 timestamp checks."""
Greg Wardfe6462c2000-04-04 01:40:52 +0000365
366
367 if exec_msg is None:
368 exec_msg = "generating %s from %s" % \
369 (outfile, string.join (infiles, ', '))
370 if skip_msg is None:
371 skip_msg = "skipping %s (inputs unchanged)" % outfile
372
373
374 # Allow 'infiles' to be a single string
375 if type (infiles) is StringType:
376 infiles = (infiles,)
377 elif type (infiles) not in (ListType, TupleType):
378 raise TypeError, \
379 "'infiles' must be a string, or a list or tuple of strings"
380
381 # If 'outfile' must be regenerated (either because it doesn't
382 # exist, is out-of-date, or the 'force' flag is true) then
383 # perform the action that presumably regenerates it
Greg Ward68a07572000-04-10 00:18:16 +0000384 if ((hasattr(self,'force') and self.force) or
385 util.newer_group (infiles, outfile)):
Greg Wardfe6462c2000-04-04 01:40:52 +0000386 self.execute (func, args, exec_msg, level)
387
388 # Otherwise, print the "skip" message
389 else:
390 self.announce (skip_msg, level)
391
392 # make_file ()
393
394# class Command
Greg Wardb3612332000-04-09 03:48:37 +0000395
396
397if __name__ == "__main__":
398 print "ok"