Officially support target_factory and source_factory when creating a Builder.
[scons.git] / src / engine / SCons / Action.py
1 """SCons.Action
2
3 This encapsulates information about executing any sort of action that
4 can build one or more target Nodes (typically files) from one or more
5 source Nodes (also typically files) given a specific Environment.
6
7 The base class here is ActionBase.  The base class supplies just a few
8 OO utility methods and some generic methods for displaying information
9 about an Action in response to the various commands that control printing.
10
11 The heavy lifting is handled by subclasses for the different types of
12 actions we might execute:
13
14     CommandAction
15     CommandGeneratorAction
16     FunctionAction
17     ListAction
18
19 The subclasses supply the following public interface methods used by
20 other modules:
21
22     __call__()
23         THE public interface, "calling" an Action object executes the
24         command or Python function.  This also takes care of printing
25         a pre-substitution command for debugging purposes.
26
27     get_contents()
28         Fetches the "contents" of an Action for signature calculation.
29         This is what the Sig/*.py subsystem uses to decide if a target
30         needs to be rebuilt because its action changed.
31
32     genstring()
33         Returns a string representation of the Action *without* command
34         substitution, but allows a CommandGeneratorAction to generate
35         the right action based on the specified target, source and env.
36         This is used by the Signature subsystem (through the Executor)
37         to compare the actions used to build a target last time and
38         this time.
39
40 Subclasses also supply the following methods for internal use within
41 this module:
42
43     __str__()
44         Returns a string representation of the Action *without* command
45         substitution.  This is used by the __call__() methods to display
46         the pre-substitution command whenever the --debug=presub option
47         is used.
48
49     strfunction()
50         Returns a substituted string representation of the Action.
51         This is used by the ActionBase.show() command to display the
52         command/function that will be executed to generate the target(s).
53
54     execute()
55         The internal method that really, truly, actually handles the
56         execution of a command or Python function.  This is used so
57         that the __call__() methods can take care of displaying any
58         pre-substitution representations, and *then* execute an action
59         without worrying about the specific Actions involved.
60
61 There is a related independent ActionCaller class that looks like a
62 regular Action, and which serves as a wrapper for arbitrary functions
63 that we want to let the user specify the arguments to now, but actually
64 execute later (when an out-of-date check determines that it's needed to
65 be executed, for example).  Objects of this class are returned by an
66 ActionFactory class that provides a __call__() method as a convenient
67 way for wrapping up the functions.
68
69 """
70
71 #
72 # __COPYRIGHT__
73 #
74 # Permission is hereby granted, free of charge, to any person obtaining
75 # a copy of this software and associated documentation files (the
76 # "Software"), to deal in the Software without restriction, including
77 # without limitation the rights to use, copy, modify, merge, publish,
78 # distribute, sublicense, and/or sell copies of the Software, and to
79 # permit persons to whom the Software is furnished to do so, subject to
80 # the following conditions:
81 #
82 # The above copyright notice and this permission notice shall be included
83 # in all copies or substantial portions of the Software.
84 #
85 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
86 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
87 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
88 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
89 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
90 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
91 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
92 #
93
94 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
95
96 import os
97 import os.path
98 import re
99 import string
100 import sys
101
102 from SCons.Debug import logInstanceCreation
103 import SCons.Errors
104 import SCons.Util
105
106 class _Null:
107     pass
108
109 _null = _Null
110
111 print_actions = 1
112 execute_actions = 1
113 print_actions_presub = 0
114
115 default_ENV = None
116
117 def rfile(n):
118     try:
119         return n.rfile()
120     except AttributeError:
121         return n
122
123 def _actionAppend(act1, act2):
124     # This function knows how to slap two actions together.
125     # Mainly, it handles ListActions by concatenating into
126     # a single ListAction.
127     a1 = Action(act1)
128     a2 = Action(act2)
129     if a1 is None or a2 is None:
130         raise TypeError, "Cannot append %s to %s" % (type(act1), type(act2))
131     if isinstance(a1, ListAction):
132         if isinstance(a2, ListAction):
133             return ListAction(a1.list + a2.list)
134         else:
135             return ListAction(a1.list + [ a2 ])
136     else:
137         if isinstance(a2, ListAction):
138             return ListAction([ a1 ] + a2.list)
139         else:
140             return ListAction([ a1, a2 ])
141
142 class CommandGenerator:
143     """
144     Wraps a command generator function so the Action() factory
145     function can tell a generator function from a function action.
146     """
147     def __init__(self, generator):
148         self.generator = generator
149
150     def __add__(self, other):
151         return _actionAppend(self, other)
152
153     def __radd__(self, other):
154         return _actionAppend(other, self)
155
156 def _do_create_action(act, *args, **kw):
157     """This is the actual "implementation" for the
158     Action factory method, below.  This handles the
159     fact that passing lists to Action() itself has
160     different semantics than passing lists as elements
161     of lists.
162
163     The former will create a ListAction, the latter
164     will create a CommandAction by converting the inner
165     list elements to strings."""
166
167     if isinstance(act, ActionBase):
168         return act
169     if SCons.Util.is_List(act):
170         return apply(CommandAction, (act,)+args, kw)
171     if isinstance(act, CommandGenerator):
172         return apply(CommandGeneratorAction, (act.generator,)+args, kw)
173     if callable(act):
174         return apply(FunctionAction, (act,)+args, kw)
175     if SCons.Util.is_String(act):
176         var=SCons.Util.get_environment_var(act)
177         if var:
178             # This looks like a string that is purely an Environment
179             # variable reference, like "$FOO" or "${FOO}".  We do
180             # something special here...we lazily evaluate the contents
181             # of that Environment variable, so a user could put something
182             # like a function or a CommandGenerator in that variable
183             # instead of a string.
184             lcg = LazyCmdGenerator(var)
185             return apply(CommandGeneratorAction, (lcg,)+args, kw)
186         commands = string.split(str(act), '\n')
187         if len(commands) == 1:
188             return apply(CommandAction, (commands[0],)+args, kw)
189         else:
190             listCmdActions = map(lambda x: CommandAction(x), commands)
191             return apply(ListAction, (listCmdActions,)+args, kw)
192     return None
193
194 def Action(act, strfunction=_null, varlist=[], presub=_null):
195     """A factory for action objects."""
196     if SCons.Util.is_List(act):
197         acts = map(lambda x, s=strfunction, v=varlist, ps=presub:
198                           _do_create_action(x, strfunction=s, varlist=v, presub=ps),
199                    act)
200         acts = filter(lambda x: not x is None, acts)
201         if len(acts) == 1:
202             return acts[0]
203         else:
204             return ListAction(acts, strfunction=strfunction, varlist=varlist, presub=presub)
205     else:
206         return _do_create_action(act, strfunction=strfunction, varlist=varlist, presub=presub)
207
208 class ActionBase:
209     """Base class for actions that create output objects."""
210     def __init__(self, strfunction=_null, presub=_null, **kw):
211         if not strfunction is _null:
212             self.strfunction = strfunction
213         if presub is _null:
214             self.presub = print_actions_presub
215         else:
216             self.presub = presub
217
218     def __cmp__(self, other):
219         return cmp(self.__dict__, other.__dict__)
220
221     def __call__(self, target, source, env,
222                                errfunc=None,
223                                presub=_null,
224                                show=_null,
225                                execute=_null):
226         if not SCons.Util.is_List(target):
227             target = [target]
228         if not SCons.Util.is_List(source):
229             source = [source]
230         if presub is _null:  presub = self.presub
231         if show is _null:  show = print_actions
232         if execute is _null:  execute = execute_actions
233         if presub:
234             t = string.join(map(str, target), 'and')
235             l = string.join(self.presub_lines(env), '\n  ')
236             out = "Building %s with action(s):\n  %s\n" % (t, l)
237             sys.stdout.write(out)
238         if show and self.strfunction:
239             s = self.strfunction(target, source, env)
240             if s:
241                 sys.stdout.write(s + '\n')
242         if execute:
243             stat = self.execute(target, source, env)
244             if stat and errfunc:
245                 errfunc(stat)
246             return stat
247         else:
248             return 0
249
250     def presub_lines(self, env):
251         # CommandGeneratorAction needs a real environment
252         # in order to return the proper string here, since
253         # it may call LazyCmdGenerator, which looks up a key
254         # in that env.  So we temporarily remember the env here,
255         # and CommandGeneratorAction will use this env
256         # when it calls its __generate method.
257         self.presub_env = env
258         lines = string.split(str(self), '\n')
259         self.presub_env = None      # don't need this any more
260         return lines
261
262     def genstring(self, target, source, env):
263         return str(self)
264
265     def get_actions(self):
266         return [self]
267
268     def __add__(self, other):
269         return _actionAppend(self, other)
270
271     def __radd__(self, other):
272         return _actionAppend(other, self)
273
274 def _string_from_cmd_list(cmd_list):
275     """Takes a list of command line arguments and returns a pretty
276     representation for printing."""
277     cl = []
278     for arg in map(str, cmd_list):
279         if ' ' in arg or '\t' in arg:
280             arg = '"' + arg + '"'
281         cl.append(arg)
282     return string.join(cl)
283
284 class CommandAction(ActionBase):
285     """Class for command-execution actions."""
286     def __init__(self, cmd, **kw):
287         # Cmd list can actually be a list or a single item...basically
288         # anything that we could pass in as the first arg to
289         # Environment.subst_list().
290         if __debug__: logInstanceCreation(self)
291         apply(ActionBase.__init__, (self,), kw)
292         self.cmd_list = cmd
293
294     def __str__(self):
295         return str(self.cmd_list)
296
297     def strfunction(self, target, source, env):
298         cmd_list = env.subst_list(self.cmd_list, 0, target, source)
299         return string.join(map(_string_from_cmd_list, cmd_list), "\n")
300
301     def execute(self, target, source, env):
302         """Execute a command action.
303
304         This will handle lists of commands as well as individual commands,
305         because construction variable substitution may turn a single
306         "command" into a list.  This means that this class can actually
307         handle lists of commands, even though that's not how we use it
308         externally.
309         """
310         import SCons.Util
311
312         escape = env.get('ESCAPE', lambda x: x)
313
314         if env.has_key('SHELL'):
315             shell = env['SHELL']
316         else:
317             raise SCons.Errors.UserError('Missing SHELL construction variable.')
318
319         # for SConf support (by now): check, if we want to pipe the command
320         # output to somewhere else
321         if env.has_key('PIPE_BUILD'):
322             pipe_build = 1
323             if env.has_key('PSPAWN'):
324                 pspawn = env['PSPAWN']
325             else:
326                 raise SCons.Errors.UserError('Missing PSPAWN construction variable.')
327             if env.has_key('PSTDOUT'):
328                 pstdout = env['PSTDOUT']
329             else:
330                 raise SCons.Errors.UserError('Missing PSTDOUT construction variable.')
331             if env.has_key('PSTDERR'):
332                 pstderr = env['PSTDERR']
333             else:
334                 raise SCons.Errors.UserError('Missing PSTDOUT construction variable.')
335         else:
336             pipe_build = 0
337             if env.has_key('SPAWN'):
338                 spawn = env['SPAWN']
339             else:
340                 raise SCons.Errors.UserError('Missing SPAWN construction variable.')
341
342         cmd_list = env.subst_list(self.cmd_list, 0, target, source)
343         for cmd_line in cmd_list:
344             if len(cmd_line):
345                 try:
346                     ENV = env['ENV']
347                 except KeyError:
348                     global default_ENV
349                     if not default_ENV:
350                         import SCons.Environment
351                         default_ENV = SCons.Environment.Environment()['ENV']
352                     ENV = default_ENV
353
354                 # ensure that the ENV values are all strings:
355                 for key, value in ENV.items():
356                     if SCons.Util.is_List(value):
357                         # If the value is a list, then we assume
358                         # it is a path list, because that's a pretty
359                         # common list like value to stick in an environment
360                         # variable:
361                         ENV[key] = string.join(map(str, value), os.pathsep)
362                     elif not SCons.Util.is_String(value):
363                         # If it isn't a string or a list, then
364                         # we just coerce it to a string, which
365                         # is proper way to handle Dir and File instances
366                         # and will produce something reasonable for
367                         # just about everything else:
368                         ENV[key] = str(value)
369
370                 # Escape the command line for the command
371                 # interpreter we are using
372                 cmd_line = SCons.Util.escape_list(cmd_line, escape)
373                 if pipe_build:
374                     ret = pspawn( shell, escape, cmd_line[0], cmd_line,
375                                   ENV, pstdout, pstderr )
376                 else:
377                     ret = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
378                 if ret:
379                     return ret
380         return 0
381
382     def get_contents(self, target, source, env, dict=None):
383         """Return the signature contents of this action's command line.
384
385         This strips $(-$) and everything in between the string,
386         since those parts don't affect signatures.
387         """
388         cmd = self.cmd_list
389         if SCons.Util.is_List(cmd):
390             cmd = string.join(map(str, cmd))
391         else:
392             cmd = str(cmd)
393         return env.subst_target_source(cmd, SCons.Util.SUBST_SIG, target, source, dict)
394
395 class CommandGeneratorAction(ActionBase):
396     """Class for command-generator actions."""
397     def __init__(self, generator, **kw):
398         if __debug__: logInstanceCreation(self)
399         apply(ActionBase.__init__, (self,), kw)
400         self.generator = generator
401
402     def __generate(self, target, source, env, for_signature):
403         # ensure that target is a list, to make it easier to write
404         # generator functions:
405         if not SCons.Util.is_List(target):
406             target = [target]
407
408         ret = self.generator(target=target, source=source, env=env, for_signature=for_signature)
409         gen_cmd = Action(ret)
410         if not gen_cmd:
411             raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
412         return gen_cmd
413
414     def strfunction(self, target, source, env):
415         if not SCons.Util.is_List(source):
416             source = [source]
417         rsources = map(rfile, source)
418         act = self.__generate(target, source, env, 0)
419         if act.strfunction:
420             return act.strfunction(target, rsources, env)
421         else:
422             return None
423
424     def __str__(self):
425         try:
426             env = self.presub_env or {}
427         except AttributeError:
428             env = {}
429         act = self.__generate([], [], env, 0)
430         return str(act)
431
432     def genstring(self, target, source, env):
433         return str(self.__generate(target, source, env, 0))
434
435     def execute(self, target, source, env):
436         rsources = map(rfile, source)
437         act = self.__generate(target, source, env, 0)
438         return act.execute(target, source, env)
439
440     def get_contents(self, target, source, env, dict=None):
441         """Return the signature contents of this action's command line.
442
443         This strips $(-$) and everything in between the string,
444         since those parts don't affect signatures.
445         """
446         return self.__generate(target, source, env, 1).get_contents(target, source, env, dict=None)
447
448 class LazyCmdGenerator:
449     """This is not really an Action, although it kind of looks like one.
450     This is really a simple callable class that acts as a command
451     generator.  It holds on to a key into an Environment dictionary,
452     then waits until execution time to see what type it is, then tries
453     to create an Action out of it."""
454     def __init__(self, var):
455         if __debug__: logInstanceCreation(self)
456         self.var = SCons.Util.to_String(var)
457
458     def strfunction(self, target, source, env):
459         try:
460             return env[self.var]
461         except KeyError:
462             # The variable reference substitutes to nothing.
463             return ''
464
465     def __str__(self):
466         return 'LazyCmdGenerator: %s'%str(self.var)
467
468     def __call__(self, target, source, env, for_signature):
469         try:
470             return env[self.var]
471         except KeyError:
472             # The variable reference substitutes to nothing.
473             return ''
474
475     def __cmp__(self, other):
476         return cmp(self.__dict__, other.__dict__)
477
478 class FunctionAction(ActionBase):
479     """Class for Python function actions."""
480
481     def __init__(self, execfunction, **kw):
482         if __debug__: logInstanceCreation(self)
483         self.execfunction = execfunction
484         apply(ActionBase.__init__, (self,), kw)
485         self.varlist = kw.get('varlist', [])
486
487     def function_name(self):
488         try:
489             return self.execfunction.__name__
490         except AttributeError:
491             try:
492                 return self.execfunction.__class__.__name__
493             except AttributeError:
494                 return "unknown_python_function"
495
496     def strfunction(self, target, source, env):
497         def quote(s):
498             return '"' + str(s) + '"'
499         def array(a, q=quote):
500             return '[' + string.join(map(lambda x, q=q: q(x), a), ", ") + ']'
501         name = self.function_name()
502         tstr = len(target) == 1 and quote(target[0]) or array(target)
503         sstr = len(source) == 1 and quote(source[0]) or array(source)
504         return "%s(%s, %s)" % (name, tstr, sstr)
505
506     def __str__(self):
507         return "%s(env, target, source)" % self.function_name()
508
509     def execute(self, target, source, env):
510         rsources = map(rfile, source)
511         return self.execfunction(target=target, source=rsources, env=env)
512
513     def get_contents(self, target, source, env, dict=None):
514         """Return the signature contents of this callable action.
515
516         By providing direct access to the code object of the
517         function, Python makes this extremely easy.  Hooray!
518         """
519         try:
520             # "self.execfunction" is a function.
521             contents = str(self.execfunction.func_code.co_code)
522         except AttributeError:
523             # "self.execfunction" is a callable object.
524             try:
525                 contents = str(self.execfunction.__call__.im_func.func_code.co_code)
526             except AttributeError:
527                 try:
528                     # See if execfunction will do the heavy lifting for us.
529                     gc = self.execfunction.get_contents
530                 except AttributeError:
531                     # This is weird, just do the best we can.
532                     contents = str(self.execfunction)
533                 else:
534                     contents = gc(target, source, env, dict)
535         return contents + env.subst(string.join(map(lambda v: '${'+v+'}',
536                                                      self.varlist)))
537
538 class ListAction(ActionBase):
539     """Class for lists of other actions."""
540     def __init__(self, list, **kw):
541         if __debug__: logInstanceCreation(self)
542         apply(ActionBase.__init__, (self,), kw)
543         self.list = map(lambda x: Action(x), list)
544
545     def get_actions(self):
546         return self.list
547
548     def __str__(self):
549         s = []
550         for l in self.list:
551             s.append(str(l))
552         return string.join(s, "\n")
553
554     def strfunction(self, target, source, env):
555         s = []
556         for l in self.list:
557             if l.strfunction:
558                 x = l.strfunction(target, source, env)
559                 if not SCons.Util.is_List(x):
560                     x = [x]
561                 s.extend(x)
562         return string.join(s, "\n")
563
564     def execute(self, target, source, env):
565         for l in self.list:
566             r = l.execute(target, source, env)
567             if r:
568                 return r
569         return 0
570
571     def get_contents(self, target, source, env, dict=None):
572         """Return the signature contents of this action list.
573
574         Simple concatenation of the signatures of the elements.
575         """
576         dict = SCons.Util.subst_dict(target, source)
577         return string.join(map(lambda x, t=target, s=source, e=env, d=dict:
578                                       x.get_contents(t, s, e, d),
579                                self.list),
580                            "")
581
582 class ActionCaller:
583     """A class for delaying calling an Action function with specific
584     (positional and keyword) arguments until the Action is actually
585     executed.
586
587     This class looks to the rest of the world like a normal Action object,
588     but what it's really doing is hanging on to the arguments until we
589     have a target, source and env to use for the expansion.
590     """
591     def __init__(self, parent, args, kw):
592         self.parent = parent
593         self.args = args
594         self.kw = kw
595     def get_contents(self, target, source, env, dict=None):
596         actfunc = self.parent.actfunc
597         try:
598             # "self.actfunc" is a function.
599             contents = str(actfunc.func_code.co_code)
600         except AttributeError:
601             # "self.actfunc" is a callable object.
602             try:
603                 contents = str(actfunc.__call__.im_func.func_code.co_code)
604             except AttributeError:
605                 # No __call__() method, so it might be a builtin
606                 # or something like that.  Do the best we can.
607                 contents = str(actfunc)
608         return contents
609     def subst_args(self, target, source, env):
610         return map(lambda x, e=env, t=target, s=source:
611                           e.subst(x, 0, t, s),
612                    self.args)
613     def subst_kw(self, target, source, env):
614         kw = {}
615         for key in self.kw.keys():
616             kw[key] = env.subst(self.kw[key], 0, target, source)
617         return kw
618     def __call__(self, target, source, env):
619         args = self.subst_args(target, source, env)
620         kw = self.subst_kw(target, source, env)
621         return apply(self.parent.actfunc, args, kw)
622     def strfunction(self, target, source, env):
623         args = self.subst_args(target, source, env)
624         kw = self.subst_kw(target, source, env)
625         return apply(self.parent.strfunc, args, kw)
626
627 class ActionFactory:
628     """A factory class that will wrap up an arbitrary function
629     as an SCons-executable Action object.
630
631     The real heavy lifting here is done by the ActionCaller class.
632     We just collect the (positional and keyword) arguments that we're
633     called with and give them to the ActionCaller object we create,
634     so it can hang onto them until it needs them.
635     """
636     def __init__(self, actfunc, strfunc):
637         self.actfunc = actfunc
638         self.strfunc = strfunc
639     def __call__(self, *args, **kw):
640         ac = ActionCaller(self, args, kw)
641         return Action(ac, strfunction=ac.strfunction)