blob: 85a7f4618272f8d09c23a98719158b4b7bab59e7 [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
Greg Ward8ff5a3f2000-06-02 00:44:53 +00004in the distutils.command package.
5"""
Greg Wardfe6462c2000-04-04 01:40:52 +00006
7# created 2000/04/03, Greg Ward
8# (extricated from core.py; actually dates back to the beginning)
9
10__revision__ = "$Id$"
11
Andrew M. Kuchlingac20f772001-03-22 03:48:31 +000012import sys, os, string, re
Greg Wardfe6462c2000-04-04 01:40:52 +000013from types import *
14from distutils.errors import *
Greg Ward29124ff2000-08-13 00:36:47 +000015from distutils import util, dir_util, file_util, archive_util, dep_util
Greg Wardfe6462c2000-04-04 01:40:52 +000016
17
18class Command:
19 """Abstract base class for defining command classes, the "worker bees"
Greg Ward8ff5a3f2000-06-02 00:44:53 +000020 of the Distutils. A useful analogy for command classes is to think of
21 them as subroutines with local variables called "options". The options
22 are "declared" in 'initialize_options()' and "defined" (given their
23 final values, aka "finalized") in 'finalize_options()', both of which
24 must be defined by every command class. The distinction between the
25 two is necessary because option values might come from the outside
26 world (command line, config file, ...), and any options dependent on
27 other 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 every
31 command class.
32 """
Greg Wardfe6462c2000-04-04 01:40:52 +000033
Greg Wardb3e0ad92000-09-16 15:09:17 +000034 # 'sub_commands' formalizes the notion of a "family" of commands,
35 # eg. "install" as the parent with sub-commands "install_lib",
36 # "install_headers", etc. The parent of a family of commands
37 # defines 'sub_commands' as a class attribute; it's a list of
38 # (command_name : string, predicate : unbound_method | string | None)
39 # tuples, where 'predicate' is a method of the parent command that
40 # determines whether the corresponding command is applicable in the
41 # current situation. (Eg. we "install_headers" is only applicable if
42 # we have any C header files to install.) If 'predicate' is None,
43 # that command is always applicable.
44 #
45 # 'sub_commands' is usually defined at the *end* of a class, because
46 # predicates can be unbound methods, so they must already have been
47 # defined. The canonical example is the "install" command.
48 sub_commands = []
49
50
Greg Wardfe6462c2000-04-04 01:40:52 +000051 # -- Creation/initialization methods -------------------------------
52
53 def __init__ (self, dist):
54 """Create and initialize a new Command object. Most importantly,
Greg Ward8ff5a3f2000-06-02 00:44:53 +000055 invokes the 'initialize_options()' method, which is the real
56 initializer and depends on the actual command being
57 instantiated.
58 """
Greg Wardfe6462c2000-04-04 01:40:52 +000059 # late import because of mutual dependence between these classes
60 from distutils.dist import Distribution
61
Greg Ward071ed762000-09-26 02:12:31 +000062 if not isinstance(dist, Distribution):
Greg Wardfe6462c2000-04-04 01:40:52 +000063 raise TypeError, "dist must be a Distribution instance"
64 if self.__class__ is Command:
65 raise RuntimeError, "Command is an abstract class"
66
67 self.distribution = dist
Greg Ward071ed762000-09-26 02:12:31 +000068 self.initialize_options()
Greg Wardfe6462c2000-04-04 01:40:52 +000069
70 # Per-command versions of the global flags, so that the user can
71 # customize Distutils' behaviour command-by-command and let some
72 # commands fallback on the Distribution's behaviour. None means
73 # "not defined, check self.distribution's copy", while 0 or 1 mean
74 # false and true (duh). Note that this means figuring out the real
Greg Ward612eb9f2000-07-27 02:13:20 +000075 # value of each flag is a touch complicated -- hence "self.verbose"
Greg Wardfe6462c2000-04-04 01:40:52 +000076 # (etc.) will be handled by __getattr__, below.
77 self._verbose = None
78 self._dry_run = None
Greg Wardfe6462c2000-04-04 01:40:52 +000079
Greg Wardd197a3a2000-04-10 13:11:51 +000080 # Some commands define a 'self.force' option to ignore file
81 # timestamps, but methods defined *here* assume that
82 # 'self.force' exists for all commands. So define it here
83 # just to be safe.
84 self.force = None
85
Greg Wardfe6462c2000-04-04 01:40:52 +000086 # The 'help' flag is just used for command-line parsing, so
87 # none of that complicated bureaucracy is needed.
88 self.help = 0
89
Greg Ward4fb29e52000-05-27 17:27:23 +000090 # 'finalized' records whether or not 'finalize_options()' has been
Greg Wardfe6462c2000-04-04 01:40:52 +000091 # called. 'finalize_options()' itself should not pay attention to
Greg Ward4fb29e52000-05-27 17:27:23 +000092 # this flag: it is the business of 'ensure_finalized()', which
93 # always calls 'finalize_options()', to respect/update it.
94 self.finalized = 0
Greg Wardfe6462c2000-04-04 01:40:52 +000095
96 # __init__ ()
97
98
99 def __getattr__ (self, attr):
Greg Ward68a07572000-04-10 00:18:16 +0000100 if attr in ('verbose', 'dry_run'):
Greg Ward071ed762000-09-26 02:12:31 +0000101 myval = getattr(self, "_" + attr)
Greg Wardfe6462c2000-04-04 01:40:52 +0000102 if myval is None:
Greg Ward071ed762000-09-26 02:12:31 +0000103 return getattr(self.distribution, attr)
Greg Wardfe6462c2000-04-04 01:40:52 +0000104 else:
105 return myval
106 else:
107 raise AttributeError, attr
108
109
Greg Ward4fb29e52000-05-27 17:27:23 +0000110 def ensure_finalized (self):
111 if not self.finalized:
Greg Ward071ed762000-09-26 02:12:31 +0000112 self.finalize_options()
Greg Ward4fb29e52000-05-27 17:27:23 +0000113 self.finalized = 1
Greg Wardfe6462c2000-04-04 01:40:52 +0000114
115
116 # Subclasses must define:
117 # initialize_options()
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000118 # provide default values for all options; may be customized by
119 # setup script, by options from config file(s), or by command-line
120 # options
Greg Wardfe6462c2000-04-04 01:40:52 +0000121 # finalize_options()
122 # decide on the final values for all options; this is called
123 # after all possible intervention from the outside world
124 # (command-line, option file, etc.) has been processed
125 # run()
126 # run the command: do whatever it is we're here to do,
127 # controlled by the command's various option values
128
129 def initialize_options (self):
130 """Set default values for all the options that this command
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000131 supports. Note that these defaults may be overridden by other
132 commands, by the setup script, by config files, or by the
133 command-line. Thus, this is not the place to code dependencies
134 between options; generally, 'initialize_options()' implementations
135 are just a bunch of "self.foo = None" assignments.
Greg Wardfe6462c2000-04-04 01:40:52 +0000136
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000137 This method must be implemented by all command classes.
138 """
Greg Wardfe6462c2000-04-04 01:40:52 +0000139 raise RuntimeError, \
140 "abstract method -- subclass %s must override" % self.__class__
141
142 def finalize_options (self):
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000143 """Set final values for all the options that this command supports.
144 This is always called as late as possible, ie. after any option
145 assignments from the command-line or from other commands have been
146 done. Thus, this is the place to to code option dependencies: if
147 'foo' depends on 'bar', then it is safe to set 'foo' from 'bar' as
148 long as 'foo' still has the same value it was assigned in
149 'initialize_options()'.
Greg Wardfe6462c2000-04-04 01:40:52 +0000150
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000151 This method must be implemented by all command classes.
152 """
Greg Wardfe6462c2000-04-04 01:40:52 +0000153 raise RuntimeError, \
154 "abstract method -- subclass %s must override" % self.__class__
155
Greg Wardadda1562000-05-28 23:54:00 +0000156
157 def dump_options (self, header=None, indent=""):
158 from distutils.fancy_getopt import longopt_xlate
159 if header is None:
160 header = "command options for '%s':" % self.get_command_name()
161 print indent + header
162 indent = indent + " "
163 for (option, _, _) in self.user_options:
Andrew M. Kuchlingac20f772001-03-22 03:48:31 +0000164 option = string.translate(option, longopt_xlate)
Greg Wardadda1562000-05-28 23:54:00 +0000165 if option[-1] == "=":
166 option = option[:-1]
167 value = getattr(self, option)
168 print indent + "%s = %s" % (option, value)
169
170
Greg Wardfe6462c2000-04-04 01:40:52 +0000171 def run (self):
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000172 """A command's raison d'etre: carry out the action it exists to
173 perform, controlled by the options initialized in
174 'initialize_options()', customized by other commands, the setup
175 script, the command-line, and config files, and finalized in
176 'finalize_options()'. All terminal output and filesystem
177 interaction should be done by 'run()'.
Greg Wardfe6462c2000-04-04 01:40:52 +0000178
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000179 This method must be implemented by all command classes.
180 """
Greg Wardfe6462c2000-04-04 01:40:52 +0000181
182 raise RuntimeError, \
183 "abstract method -- subclass %s must override" % self.__class__
184
185 def announce (self, msg, level=1):
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000186 """If the current verbosity level is of greater than or equal to
187 'level' print 'msg' to stdout.
188 """
Greg Wardfe6462c2000-04-04 01:40:52 +0000189 if self.verbose >= level:
190 print msg
Neil Schemenauer69374e42001-08-29 23:57:22 +0000191 sys.stdout.flush()
Greg Wardfe6462c2000-04-04 01:40:52 +0000192
Greg Wardebec02a2000-06-08 00:02:36 +0000193 def debug_print (self, msg):
194 """Print 'msg' to stdout if the global DEBUG (taken from the
195 DISTUTILS_DEBUG environment variable) flag is true.
196 """
197 from distutils.core import DEBUG
198 if DEBUG:
199 print msg
Neil Schemenauer69374e42001-08-29 23:57:22 +0000200 sys.stdout.flush()
Greg Wardebec02a2000-06-08 00:02:36 +0000201
202
Greg Wardfe6462c2000-04-04 01:40:52 +0000203
Greg Ward31413a72000-06-04 14:21:28 +0000204 # -- Option validation methods -------------------------------------
205 # (these are very handy in writing the 'finalize_options()' method)
206 #
207 # NB. the general philosophy here is to ensure that a particular option
208 # value meets certain type and value constraints. If not, we try to
209 # force it into conformance (eg. if we expect a list but have a string,
210 # split the string on comma and/or whitespace). If we can't force the
211 # option into conformance, raise DistutilsOptionError. Thus, command
212 # classes need do nothing more than (eg.)
213 # self.ensure_string_list('foo')
214 # and they can be guaranteed that thereafter, self.foo will be
215 # a list of strings.
216
217 def _ensure_stringlike (self, option, what, default=None):
218 val = getattr(self, option)
219 if val is None:
220 setattr(self, option, default)
221 return default
222 elif type(val) is not StringType:
223 raise DistutilsOptionError, \
224 "'%s' must be a %s (got `%s`)" % (option, what, val)
225 return val
226
227 def ensure_string (self, option, default=None):
228 """Ensure that 'option' is a string; if not defined, set it to
229 'default'.
230 """
231 self._ensure_stringlike(option, "string", default)
232
233 def ensure_string_list (self, option):
234 """Ensure that 'option' is a list of strings. If 'option' is
235 currently a string, we split it either on /,\s*/ or /\s+/, so
236 "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become
237 ["foo", "bar", "baz"].
238 """
239 val = getattr(self, option)
240 if val is None:
241 return
242 elif type(val) is StringType:
243 setattr(self, option, re.split(r',\s*|\s+', val))
244 else:
245 if type(val) is ListType:
246 types = map(type, val)
247 ok = (types == [StringType] * len(val))
248 else:
249 ok = 0
250
251 if not ok:
252 raise DistutilsOptionError, \
253 "'%s' must be a list of strings (got %s)" % \
254 (option, `val`)
255
256 def _ensure_tested_string (self, option, tester,
257 what, error_fmt, default=None):
258 val = self._ensure_stringlike(option, what, default)
259 if val is not None and not tester(val):
260 raise DistutilsOptionError, \
261 ("error in '%s' option: " + error_fmt) % (option, val)
262
263 def ensure_filename (self, option):
264 """Ensure that 'option' is the name of an existing file."""
265 self._ensure_tested_string(option, os.path.isfile,
266 "filename",
267 "'%s' does not exist or is not a file")
268
269 def ensure_dirname (self, option):
270 self._ensure_tested_string(option, os.path.isdir,
271 "directory name",
272 "'%s' does not exist or is not a directory")
273
274
Greg Wardfe6462c2000-04-04 01:40:52 +0000275 # -- Convenience methods for commands ------------------------------
276
277 def get_command_name (self):
Greg Ward071ed762000-09-26 02:12:31 +0000278 if hasattr(self, 'command_name'):
Greg Wardfe6462c2000-04-04 01:40:52 +0000279 return self.command_name
280 else:
281 return self.__class__.__name__
282
283
284 def set_undefined_options (self, src_cmd, *option_pairs):
285 """Set the values of any "undefined" options from corresponding
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000286 option values in some other command object. "Undefined" here means
287 "is None", which is the convention used to indicate that an option
288 has not been changed between 'initialize_options()' and
289 'finalize_options()'. Usually called from 'finalize_options()' for
290 options that depend on some other command rather than another
291 option of the same command. 'src_cmd' is the other command from
292 which option values will be taken (a command object will be created
293 for it if necessary); the remaining arguments are
294 '(src_option,dst_option)' tuples which mean "take the value of
295 'src_option' in the 'src_cmd' command object, and copy it to
296 'dst_option' in the current command object".
297 """
Greg Wardfe6462c2000-04-04 01:40:52 +0000298
299 # Option_pairs: list of (src_option, dst_option) tuples
300
Greg Ward071ed762000-09-26 02:12:31 +0000301 src_cmd_obj = self.distribution.get_command_obj(src_cmd)
302 src_cmd_obj.ensure_finalized()
Greg Ward02a1a2b2000-04-15 22:15:07 +0000303 for (src_option, dst_option) in option_pairs:
Greg Ward071ed762000-09-26 02:12:31 +0000304 if getattr(self, dst_option) is None:
305 setattr(self, dst_option,
306 getattr(src_cmd_obj, src_option))
Greg Wardfe6462c2000-04-04 01:40:52 +0000307
308
Greg Ward4fb29e52000-05-27 17:27:23 +0000309 def get_finalized_command (self, command, create=1):
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000310 """Wrapper around Distribution's 'get_command_obj()' method: find
311 (create if necessary and 'create' is true) the command object for
312 'command', call its 'ensure_finalized()' method, and return the
313 finalized command object.
314 """
Greg Ward071ed762000-09-26 02:12:31 +0000315 cmd_obj = self.distribution.get_command_obj(command, create)
316 cmd_obj.ensure_finalized()
Greg Wardfe6462c2000-04-04 01:40:52 +0000317 return cmd_obj
318
Greg Ward308acf02000-06-01 01:08:52 +0000319 # XXX rename to 'get_reinitialized_command()'? (should do the
320 # same in dist.py, if so)
Greg Wardecce1452000-09-16 15:25:55 +0000321 def reinitialize_command (self, command, reinit_subcommands=0):
322 return self.distribution.reinitialize_command(
323 command, reinit_subcommands)
Greg Wardfe6462c2000-04-04 01:40:52 +0000324
Greg Ward4fb29e52000-05-27 17:27:23 +0000325 def run_command (self, command):
Greg Wardfe6462c2000-04-04 01:40:52 +0000326 """Run some other command: uses the 'run_command()' method of
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000327 Distribution, which creates and finalizes the command object if
328 necessary and then invokes its 'run()' method.
329 """
Greg Ward071ed762000-09-26 02:12:31 +0000330 self.distribution.run_command(command)
Greg Wardfe6462c2000-04-04 01:40:52 +0000331
332
Greg Wardb3e0ad92000-09-16 15:09:17 +0000333 def get_sub_commands (self):
334 """Determine the sub-commands that are relevant in the current
335 distribution (ie., that need to be run). This is based on the
336 'sub_commands' class attribute: each tuple in that list may include
337 a method that we call to determine if the subcommand needs to be
338 run for the current distribution. Return a list of command names.
339 """
340 commands = []
341 for (cmd_name, method) in self.sub_commands:
342 if method is None or method(self):
343 commands.append(cmd_name)
344 return commands
345
346
Greg Wardfe6462c2000-04-04 01:40:52 +0000347 # -- External world manipulation -----------------------------------
348
349 def warn (self, msg):
Greg Ward071ed762000-09-26 02:12:31 +0000350 sys.stderr.write("warning: %s: %s\n" %
351 (self.get_command_name(), msg))
Greg Wardfe6462c2000-04-04 01:40:52 +0000352
353
354 def execute (self, func, args, msg=None, level=1):
Greg Wardd7faa812000-08-02 01:37:53 +0000355 util.execute(func, args, msg, self.verbose >= level, self.dry_run)
Greg Wardfe6462c2000-04-04 01:40:52 +0000356
357
358 def mkpath (self, name, mode=0777):
Greg Ward29124ff2000-08-13 00:36:47 +0000359 dir_util.mkpath(name, mode,
360 self.verbose, self.dry_run)
Greg Wardfe6462c2000-04-04 01:40:52 +0000361
362
363 def copy_file (self, infile, outfile,
364 preserve_mode=1, preserve_times=1, link=None, level=1):
Greg Warde9613ae2000-04-10 01:30:44 +0000365 """Copy a file respecting verbose, dry-run and force flags. (The
366 former two default to whatever is in the Distribution object, and
367 the latter defaults to false for commands that don't define it.)"""
Greg Wardfe6462c2000-04-04 01:40:52 +0000368
Greg Ward29124ff2000-08-13 00:36:47 +0000369 return file_util.copy_file(
370 infile, outfile,
371 preserve_mode, preserve_times,
372 not self.force,
373 link,
374 self.verbose >= level,
375 self.dry_run)
Greg Wardfe6462c2000-04-04 01:40:52 +0000376
377
378 def copy_tree (self, infile, outfile,
379 preserve_mode=1, preserve_times=1, preserve_symlinks=0,
380 level=1):
381 """Copy an entire directory tree respecting verbose, dry-run,
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000382 and force flags.
383 """
Greg Ward29124ff2000-08-13 00:36:47 +0000384 return dir_util.copy_tree(
385 infile, outfile,
386 preserve_mode,preserve_times,preserve_symlinks,
387 not self.force,
388 self.verbose >= level,
389 self.dry_run)
Greg Wardfe6462c2000-04-04 01:40:52 +0000390
391
392 def move_file (self, src, dst, level=1):
393 """Move a file respecting verbose and dry-run flags."""
Greg Ward071ed762000-09-26 02:12:31 +0000394 return file_util.move_file(src, dst,
395 self.verbose >= level,
396 self.dry_run)
Greg Wardfe6462c2000-04-04 01:40:52 +0000397
398
399 def spawn (self, cmd, search_path=1, level=1):
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000400 """Spawn an external command respecting verbose and dry-run flags."""
Greg Wardfe6462c2000-04-04 01:40:52 +0000401 from distutils.spawn import spawn
Greg Ward071ed762000-09-26 02:12:31 +0000402 spawn(cmd, search_path,
403 self.verbose >= level,
404 self.dry_run)
Greg Wardfe6462c2000-04-04 01:40:52 +0000405
406
407 def make_archive (self, base_name, format,
408 root_dir=None, base_dir=None):
Greg Ward29124ff2000-08-13 00:36:47 +0000409 return archive_util.make_archive(
410 base_name, format, root_dir, base_dir,
411 self.verbose, self.dry_run)
Greg Wardfe6462c2000-04-04 01:40:52 +0000412
413
414 def make_file (self, infiles, outfile, func, args,
Greg Ward68a07572000-04-10 00:18:16 +0000415 exec_msg=None, skip_msg=None, level=1):
Greg Wardfe6462c2000-04-04 01:40:52 +0000416 """Special case of 'execute()' for operations that process one or
Greg Ward68a07572000-04-10 00:18:16 +0000417 more input files and generate one output file. Works just like
418 'execute()', except the operation is skipped and a different
419 message printed if 'outfile' already exists and is newer than all
420 files listed in 'infiles'. If the command defined 'self.force',
421 and it is true, then the command is unconditionally run -- does no
Greg Ward8ff5a3f2000-06-02 00:44:53 +0000422 timestamp checks.
423 """
Greg Wardfe6462c2000-04-04 01:40:52 +0000424 if exec_msg is None:
425 exec_msg = "generating %s from %s" % \
Andrew M. Kuchlingac20f772001-03-22 03:48:31 +0000426 (outfile, string.join(infiles, ', '))
Greg Wardfe6462c2000-04-04 01:40:52 +0000427 if skip_msg is None:
428 skip_msg = "skipping %s (inputs unchanged)" % outfile
429
430
431 # Allow 'infiles' to be a single string
Greg Ward071ed762000-09-26 02:12:31 +0000432 if type(infiles) is StringType:
Greg Wardfe6462c2000-04-04 01:40:52 +0000433 infiles = (infiles,)
Greg Ward071ed762000-09-26 02:12:31 +0000434 elif type(infiles) not in (ListType, TupleType):
Greg Wardfe6462c2000-04-04 01:40:52 +0000435 raise TypeError, \
436 "'infiles' must be a string, or a list or tuple of strings"
437
438 # If 'outfile' must be regenerated (either because it doesn't
439 # exist, is out-of-date, or the 'force' flag is true) then
440 # perform the action that presumably regenerates it
Greg Ward29124ff2000-08-13 00:36:47 +0000441 if self.force or dep_util.newer_group (infiles, outfile):
Greg Ward071ed762000-09-26 02:12:31 +0000442 self.execute(func, args, exec_msg, level)
Greg Wardfe6462c2000-04-04 01:40:52 +0000443
444 # Otherwise, print the "skip" message
445 else:
Greg Ward071ed762000-09-26 02:12:31 +0000446 self.announce(skip_msg, level)
Greg Wardfe6462c2000-04-04 01:40:52 +0000447
448 # make_file ()
449
450# class Command
Greg Wardb3612332000-04-09 03:48:37 +0000451
452
Greg Ward029e3022000-05-25 01:26:23 +0000453# XXX 'install_misc' class not currently used -- it was the base class for
454# both 'install_scripts' and 'install_data', but they outgrew it. It might
455# still be useful for 'install_headers', though, so I'm keeping it around
456# for the time being.
457
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000458class install_misc (Command):
459 """Common base class for installing some files in a subdirectory.
460 Currently used by install_data and install_scripts.
461 """
462
463 user_options = [('install-dir=', 'd', "directory to install the files to")]
464
465 def initialize_options (self):
466 self.install_dir = None
Gregory P. Smith21b9e912000-05-13 03:10:30 +0000467 self.outfiles = []
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000468
Gregory P. Smithce2b6b82000-05-12 01:31:37 +0000469 def _install_dir_from (self, dirname):
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000470 self.set_undefined_options('install', (dirname, 'install_dir'))
471
Gregory P. Smithce2b6b82000-05-12 01:31:37 +0000472 def _copy_files (self, filelist):
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000473 self.outfiles = []
474 if not filelist:
475 return
476 self.mkpath(self.install_dir)
477 for f in filelist:
Gregory P. Smithce2b6b82000-05-12 01:31:37 +0000478 self.copy_file(f, self.install_dir)
479 self.outfiles.append(os.path.join(self.install_dir, f))
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000480
Gregory P. Smithce2b6b82000-05-12 01:31:37 +0000481 def get_outputs (self):
482 return self.outfiles
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000483
484
Greg Wardb3612332000-04-09 03:48:37 +0000485if __name__ == "__main__":
486 print "ok"