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