blob: c544b86440576f814d27c06bb6bbfa82f7a80f2f [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
Gregory P. Smithce2b6b82000-05-12 01:31:37 +000011import sys, os, string
Greg Wardfe6462c2000-04-04 01:40:52 +000012from 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
Greg Wardd197a3a2000-04-10 13:11:51 +000062 # Some commands define a 'self.force' option to ignore file
63 # timestamps, but methods defined *here* assume that
64 # 'self.force' exists for all commands. So define it here
65 # just to be safe.
66 self.force = None
67
Greg Wardfe6462c2000-04-04 01:40:52 +000068 # The 'help' flag is just used for command-line parsing, so
69 # none of that complicated bureaucracy is needed.
70 self.help = 0
71
72 # 'ready' records whether or not 'finalize_options()' has been
73 # called. 'finalize_options()' itself should not pay attention to
74 # this flag: it is the business of 'ensure_ready()', which always
75 # calls 'finalize_options()', to respect/update it.
76 self.ready = 0
77
78 # __init__ ()
79
80
81 def __getattr__ (self, attr):
Greg Ward68a07572000-04-10 00:18:16 +000082 if attr in ('verbose', 'dry_run'):
Greg Wardfe6462c2000-04-04 01:40:52 +000083 myval = getattr (self, "_" + attr)
84 if myval is None:
85 return getattr (self.distribution, attr)
86 else:
87 return myval
88 else:
89 raise AttributeError, attr
90
91
92 def ensure_ready (self):
93 if not self.ready:
94 self.finalize_options ()
95 self.ready = 1
96
97
98 # Subclasses must define:
99 # initialize_options()
100 # provide default values for all options; may be overridden
101 # by Distutils client, by command-line options, or by options
102 # from option file
103 # finalize_options()
104 # decide on the final values for all options; this is called
105 # after all possible intervention from the outside world
106 # (command-line, option file, etc.) has been processed
107 # run()
108 # run the command: do whatever it is we're here to do,
109 # controlled by the command's various option values
110
111 def initialize_options (self):
112 """Set default values for all the options that this command
113 supports. Note that these defaults may be overridden
114 by the command-line supplied by the user; thus, this is
115 not the place to code dependencies between options; generally,
116 'initialize_options()' implementations are just a bunch
117 of "self.foo = None" assignments.
118
119 This method must be implemented by all command classes."""
120
121 raise RuntimeError, \
122 "abstract method -- subclass %s must override" % self.__class__
123
124 def finalize_options (self):
125 """Set final values for all the options that this command
126 supports. This is always called as late as possible, ie.
127 after any option assignments from the command-line or from
128 other commands have been done. Thus, this is the place to to
129 code option dependencies: if 'foo' depends on 'bar', then it
130 is safe to set 'foo' from 'bar' as long as 'foo' still has
131 the same value it was assigned in 'initialize_options()'.
132
133 This method must be implemented by all command classes."""
134
135 raise RuntimeError, \
136 "abstract method -- subclass %s must override" % self.__class__
137
138 def run (self):
139 """A command's raison d'etre: carry out the action it exists
140 to perform, controlled by the options initialized in
141 'initialize_options()', customized by the user and other
142 commands, and finalized in 'finalize_options()'. All
143 terminal output and filesystem interaction should be done by
144 'run()'.
145
146 This method must be implemented by all command classes."""
147
148 raise RuntimeError, \
149 "abstract method -- subclass %s must override" % self.__class__
150
151 def announce (self, msg, level=1):
152 """If the Distribution instance to which this command belongs
153 has a verbosity level of greater than or equal to 'level'
154 print 'msg' to stdout."""
155
156 if self.verbose >= level:
157 print msg
158
159
Greg Wardfe6462c2000-04-04 01:40:52 +0000160 # -- Convenience methods for commands ------------------------------
161
162 def get_command_name (self):
163 if hasattr (self, 'command_name'):
164 return self.command_name
165 else:
166 return self.__class__.__name__
167
168
169 def set_undefined_options (self, src_cmd, *option_pairs):
170 """Set the values of any "undefined" options from corresponding
171 option values in some other command object. "Undefined" here
172 means "is None", which is the convention used to indicate
173 that an option has not been changed between
174 'set_initial_values()' and 'set_final_values()'. Usually
175 called from 'set_final_values()' for options that depend on
176 some other command rather than another option of the same
177 command. 'src_cmd' is the other command from which option
178 values will be taken (a command object will be created for it
179 if necessary); the remaining arguments are
180 '(src_option,dst_option)' tuples which mean "take the value
181 of 'src_option' in the 'src_cmd' command object, and copy it
182 to 'dst_option' in the current command object"."""
183
184 # Option_pairs: list of (src_option, dst_option) tuples
185
186 src_cmd_obj = self.distribution.find_command_obj (src_cmd)
187 src_cmd_obj.ensure_ready ()
Greg Ward02a1a2b2000-04-15 22:15:07 +0000188 for (src_option, dst_option) in option_pairs:
189 if getattr (self, dst_option) is None:
Greg Wardf4f8e642000-05-07 15:29:15 +0000190 setattr (self, dst_option,
191 getattr (src_cmd_obj, src_option))
Greg Wardfe6462c2000-04-04 01:40:52 +0000192
193
194 def find_peer (self, command, create=1):
195 """Wrapper around Distribution's 'find_command_obj()' method:
196 find (create if necessary and 'create' is true) the command
197 object for 'command'.."""
198
199 cmd_obj = self.distribution.find_command_obj (command, create)
200 cmd_obj.ensure_ready ()
201 return cmd_obj
202
203
204 def get_peer_option (self, command, option):
205 """Find or create the command object for 'command', and return
206 its 'option' option."""
207
208 cmd_obj = self.find_peer (command)
Greg Wardf4f8e642000-05-07 15:29:15 +0000209 return getattr(cmd_obj, option)
Greg Wardfe6462c2000-04-04 01:40:52 +0000210
211
212 def run_peer (self, command):
213 """Run some other command: uses the 'run_command()' method of
214 Distribution, which creates the command object if necessary
215 and then invokes its 'run()' method."""
216
217 self.distribution.run_command (command)
218
219
220 # -- External world manipulation -----------------------------------
221
222 def warn (self, msg):
223 sys.stderr.write ("warning: %s: %s\n" %
224 (self.get_command_name(), msg))
225
226
227 def execute (self, func, args, msg=None, level=1):
228 """Perform some action that affects the outside world (eg.
229 by writing to the filesystem). Such actions are special because
230 they should be disabled by the "dry run" flag, and should
231 announce themselves if the current verbosity level is high
232 enough. This method takes care of all that bureaucracy for you;
233 all you have to do is supply the funtion to call and an argument
234 tuple for it (to embody the "external action" being performed),
235 a message to print if the verbosity level is high enough, and an
236 optional verbosity threshold."""
237
238 # Generate a message if we weren't passed one
239 if msg is None:
240 msg = "%s %s" % (func.__name__, `args`)
241 if msg[-2:] == ',)': # correct for singleton tuple
242 msg = msg[0:-2] + ')'
243
244 # Print it if verbosity level is high enough
245 self.announce (msg, level)
246
247 # And do it, as long as we're not in dry-run mode
248 if not self.dry_run:
249 apply (func, args)
250
251 # execute()
252
253
254 def mkpath (self, name, mode=0777):
255 util.mkpath (name, mode,
256 self.verbose, self.dry_run)
257
258
259 def copy_file (self, infile, outfile,
260 preserve_mode=1, preserve_times=1, link=None, level=1):
Greg Warde9613ae2000-04-10 01:30:44 +0000261 """Copy a file respecting verbose, dry-run and force flags. (The
262 former two default to whatever is in the Distribution object, and
263 the latter defaults to false for commands that don't define it.)"""
Greg Wardfe6462c2000-04-04 01:40:52 +0000264
265 return util.copy_file (infile, outfile,
266 preserve_mode, preserve_times,
267 not self.force,
268 link,
269 self.verbose >= level,
270 self.dry_run)
271
272
273 def copy_tree (self, infile, outfile,
274 preserve_mode=1, preserve_times=1, preserve_symlinks=0,
275 level=1):
276 """Copy an entire directory tree respecting verbose, dry-run,
Greg Warde9613ae2000-04-10 01:30:44 +0000277 and force flags."""
Greg Wardfe6462c2000-04-04 01:40:52 +0000278
279 return util.copy_tree (infile, outfile,
280 preserve_mode,preserve_times,preserve_symlinks,
281 not self.force,
282 self.verbose >= level,
283 self.dry_run)
284
285
286 def move_file (self, src, dst, level=1):
287 """Move a file respecting verbose and dry-run flags."""
288 return util.move_file (src, dst,
289 self.verbose >= level,
290 self.dry_run)
291
292
293 def spawn (self, cmd, search_path=1, level=1):
294 from distutils.spawn import spawn
295 spawn (cmd, search_path,
296 self.verbose >= level,
297 self.dry_run)
298
299
300 def make_archive (self, base_name, format,
301 root_dir=None, base_dir=None):
302 util.make_archive (base_name, format, root_dir, base_dir,
303 self.verbose, self.dry_run)
304
305
306 def make_file (self, infiles, outfile, func, args,
Greg Ward68a07572000-04-10 00:18:16 +0000307 exec_msg=None, skip_msg=None, level=1):
Greg Wardfe6462c2000-04-04 01:40:52 +0000308
309 """Special case of 'execute()' for operations that process one or
Greg Ward68a07572000-04-10 00:18:16 +0000310 more input files and generate one output file. Works just like
311 'execute()', except the operation is skipped and a different
312 message printed if 'outfile' already exists and is newer than all
313 files listed in 'infiles'. If the command defined 'self.force',
314 and it is true, then the command is unconditionally run -- does no
315 timestamp checks."""
Greg Wardfe6462c2000-04-04 01:40:52 +0000316
317
318 if exec_msg is None:
319 exec_msg = "generating %s from %s" % \
320 (outfile, string.join (infiles, ', '))
321 if skip_msg is None:
322 skip_msg = "skipping %s (inputs unchanged)" % outfile
323
324
325 # Allow 'infiles' to be a single string
326 if type (infiles) is StringType:
327 infiles = (infiles,)
328 elif type (infiles) not in (ListType, TupleType):
329 raise TypeError, \
330 "'infiles' must be a string, or a list or tuple of strings"
331
332 # If 'outfile' must be regenerated (either because it doesn't
333 # exist, is out-of-date, or the 'force' flag is true) then
334 # perform the action that presumably regenerates it
Greg Warde9613ae2000-04-10 01:30:44 +0000335 if self.force or util.newer_group (infiles, outfile):
Greg Wardfe6462c2000-04-04 01:40:52 +0000336 self.execute (func, args, exec_msg, level)
337
338 # Otherwise, print the "skip" message
339 else:
340 self.announce (skip_msg, level)
341
342 # make_file ()
343
344# class Command
Greg Wardb3612332000-04-09 03:48:37 +0000345
346
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000347class install_misc (Command):
348 """Common base class for installing some files in a subdirectory.
349 Currently used by install_data and install_scripts.
350 """
351
352 user_options = [('install-dir=', 'd', "directory to install the files to")]
353
354 def initialize_options (self):
355 self.install_dir = None
Gregory P. Smith21b9e912000-05-13 03:10:30 +0000356 self.outfiles = []
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000357
Gregory P. Smithce2b6b82000-05-12 01:31:37 +0000358 def _install_dir_from (self, dirname):
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000359 self.set_undefined_options('install', (dirname, 'install_dir'))
360
Gregory P. Smithce2b6b82000-05-12 01:31:37 +0000361 def _copy_files (self, filelist):
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000362 self.outfiles = []
363 if not filelist:
364 return
365 self.mkpath(self.install_dir)
366 for f in filelist:
Gregory P. Smithce2b6b82000-05-12 01:31:37 +0000367 self.copy_file(f, self.install_dir)
368 self.outfiles.append(os.path.join(self.install_dir, f))
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000369
Gregory P. Smithce2b6b82000-05-12 01:31:37 +0000370 def get_outputs (self):
371 return self.outfiles
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000372
373
Greg Wardb3612332000-04-09 03:48:37 +0000374if __name__ == "__main__":
375 print "ok"