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 plus the varlist. This is what gets MD5 checksummed to decide
35 if a target 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 get_presig()
61 Fetches the "contents" of a subclass for signature calculation.
62 The varlist is added to this to produce the Action's contents.
63
64 strfunction()
65 Returns a substituted string representation of the Action.
66 This is used by the _ActionAction.show() command to display the
67 command/function that will be executed to generate the target(s).
68
69 There is a related independent ActionCaller class that looks like a
70 regular Action, and which serves as a wrapper for arbitrary functions
71 that we want to let the user specify the arguments to now, but actually
72 execute later (when an out-of-date check determines that it's needed to
73 be executed, for example). Objects of this class are returned by an
74 ActionFactory class that provides a __call__() method as a convenient
75 way for wrapping up the functions.
76
77 """
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 __revision__ = "src/engine/SCons/Action.py 5023 2010/06/14 22:05:46 scons"
101
102 import SCons.compat
103
104 import dis
105 import os
106
107 import pickle
108 import re
109 import sys
110 import subprocess
111
112 from SCons.Debug import logInstanceCreation
113 import SCons.Errors
114 import SCons.Executor
115 import SCons.Util
116 import SCons.Subst
117
118
119 is_String = SCons.Util.is_String
120 is_List = SCons.Util.is_List
121
124
125 print_actions = 1
126 execute_actions = 1
127 print_actions_presub = 0
128
130 try:
131 return n.rfile()
132 except AttributeError:
133 return n
134
137
138 try:
139 SET_LINENO = dis.SET_LINENO
140 HAVE_ARGUMENT = dis.HAVE_ARGUMENT
141 except AttributeError:
142 remove_set_lineno_codes = lambda x: x
143 else:
159
160 strip_quotes = re.compile('^[\'"](.*)[\'"]$')
161
162
164 """Return the signature contents of a callable Python object.
165 """
166 try:
167
168 return _function_contents(obj.im_func)
169
170 except AttributeError:
171 try:
172
173 return _function_contents(obj.__call__.im_func)
174
175 except AttributeError:
176 try:
177
178 return _code_contents(obj)
179
180 except AttributeError:
181
182 return _function_contents(obj)
183
184
186 """Return the signature contents of any Python object.
187
188 We have to handle the case where object contains a code object
189 since it can be pickled directly.
190 """
191 try:
192
193 return _function_contents(obj.im_func)
194
195 except AttributeError:
196 try:
197
198 return _function_contents(obj.__call__.im_func)
199
200 except AttributeError:
201 try:
202
203 return _code_contents(obj)
204
205 except AttributeError:
206 try:
207
208 return _function_contents(obj)
209
210 except AttributeError:
211
212 try:
213 return pickle.dumps(obj)
214 except (pickle.PicklingError, TypeError):
215
216
217
218
219
220 return str(obj)
221
222
223 -def _code_contents(code):
224 """Return the signature contents of a code object.
225
226 By providing direct access to the code object of the
227 function, Python makes this extremely easy. Hooray!
228
229 Unfortunately, older versions of Python include line
230 number indications in the compiled byte code. Boo!
231 So we remove the line number byte codes to prevent
232 recompilations from moving a Python function.
233 """
234
235 contents = []
236
237
238
239 contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames)))
240 try:
241 contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)))
242 except AttributeError:
243
244 contents.append(",0,0")
245
246
247
248
249
250
251
252
253
254 contents.append(',(' + ','.join(map(_object_contents,code.co_consts[1:])) + ')')
255
256
257
258
259
260 contents.append(',(' + ','.join(map(_object_contents,code.co_names)) + ')')
261
262
263
264 contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')')
265
266 return ''.join(contents)
267
268
270 """Return the signature contents of a function."""
271
272 contents = [_code_contents(func.func_code)]
273
274
275 if func.func_defaults:
276 contents.append(',(' + ','.join(map(_object_contents,func.func_defaults)) + ')')
277 else:
278 contents.append(',()')
279
280
281 try:
282 closure = func.func_closure or []
283 except AttributeError:
284
285 closure = []
286
287
288 try:
289 xxx = [_object_contents(x.cell_contents) for x in closure]
290 except AttributeError:
291 xxx = []
292 contents.append(',(' + ','.join(xxx) + ')')
293
294 return ''.join(contents)
295
296
298
299
300
301 a1 = Action(act1)
302 a2 = Action(act2)
303 if a1 is None or a2 is None:
304 raise TypeError("Cannot append %s to %s" % (type(act1), type(act2)))
305 if isinstance(a1, ListAction):
306 if isinstance(a2, ListAction):
307 return ListAction(a1.list + a2.list)
308 else:
309 return ListAction(a1.list + [ a2 ])
310 else:
311 if isinstance(a2, ListAction):
312 return ListAction([ a1 ] + a2.list)
313 else:
314 return ListAction([ a1, a2 ])
315
317 """This converts any arguments after the action argument into
318 their equivalent keywords and adds them to the kw argument.
319 """
320 v = kw.get('varlist', ())
321
322 if is_String(v): v = (v,)
323 kw['varlist'] = tuple(v)
324 if args:
325
326 cmdstrfunc = args[0]
327 if cmdstrfunc is None or is_String(cmdstrfunc):
328 kw['cmdstr'] = cmdstrfunc
329 elif callable(cmdstrfunc):
330 kw['strfunction'] = cmdstrfunc
331 else:
332 raise SCons.Errors.UserError(
333 'Invalid command display variable type. '
334 'You must either pass a string or a callback which '
335 'accepts (target, source, env) as parameters.')
336 if len(args) > 1:
337 kw['varlist'] = args[1:] + kw['varlist']
338 if kw.get('strfunction', _null) is not _null \
339 and kw.get('cmdstr', _null) is not _null:
340 raise SCons.Errors.UserError(
341 'Cannot have both strfunction and cmdstr args to Action()')
342
344 """This is the actual "implementation" for the
345 Action factory method, below. This handles the
346 fact that passing lists to Action() itself has
347 different semantics than passing lists as elements
348 of lists.
349
350 The former will create a ListAction, the latter
351 will create a CommandAction by converting the inner
352 list elements to strings."""
353
354 if isinstance(act, ActionBase):
355 return act
356
357 if is_List(act):
358 return CommandAction(act, **kw)
359
360 if callable(act):
361 try:
362 gen = kw['generator']
363 del kw['generator']
364 except KeyError:
365 gen = 0
366 if gen:
367 action_type = CommandGeneratorAction
368 else:
369 action_type = FunctionAction
370 return action_type(act, kw)
371
372 if is_String(act):
373 var=SCons.Util.get_environment_var(act)
374 if var:
375
376
377
378
379
380
381 return LazyAction(var, kw)
382 commands = str(act).split('\n')
383 if len(commands) == 1:
384 return CommandAction(commands[0], **kw)
385
386
387 return _do_create_list_action(commands, kw)
388 return None
389
391 """A factory for list actions. Convert the input list into Actions
392 and then wrap them in a ListAction."""
393 acts = []
394 for a in act:
395 aa = _do_create_action(a, kw)
396 if aa is not None: acts.append(aa)
397 if not acts:
398 return ListAction([])
399 elif len(acts) == 1:
400 return acts[0]
401 else:
402 return ListAction(acts)
403
405 """A factory for action objects."""
406
407 _do_create_keywords(args, kw)
408 if is_List(act):
409 return _do_create_list_action(act, kw)
410 return _do_create_action(act, kw)
411
413 """Base class for all types of action objects that can be held by
414 other objects (Builders, Executors, etc.) This provides the
415 common methods for manipulating and combining those actions."""
416
418 return cmp(self.__dict__, other)
419
422
423 batch_key = no_batch_key
424
427
428 - def get_contents(self, target, source, env):
429 result = [ self.get_presig(target, source, env) ]
430
431
432
433 vl = self.get_varlist(target, source, env)
434 if is_String(vl): vl = (vl,)
435 for v in vl:
436 result.append(env.subst('${'+v+'}'))
437 return ''.join(result)
438
440 return _actionAppend(self, other)
441
443 return _actionAppend(other, self)
444
446
447
448
449
450
451
452 self.presub_env = env
453 lines = str(self).split('\n')
454 self.presub_env = None
455 return lines
456
457 - def get_varlist(self, target, source, env, executor=None):
459
461 """
462 Returns the type of targets ($TARGETS, $CHANGED_TARGETS) used
463 by this action.
464 """
465 return self.targets
466
468 """Base class for actions that create output objects."""
469 - def __init__(self, cmdstr=_null, strfunction=_null, varlist=(),
470 presub=_null, chdir=None, exitstatfunc=None,
471 batch_key=None, targets='$TARGETS',
472 **kw):
473 self.cmdstr = cmdstr
474 if strfunction is not _null:
475 if strfunction is None:
476 self.cmdstr = None
477 else:
478 self.strfunction = strfunction
479 self.varlist = varlist
480 self.presub = presub
481 self.chdir = chdir
482 if not exitstatfunc:
483 exitstatfunc = default_exitstatfunc
484 self.exitstatfunc = exitstatfunc
485
486 self.targets = targets
487
488 if batch_key:
489 if not callable(batch_key):
490
491
492
493
494 def default_batch_key(self, env, target, source):
495 return (id(self), id(env))
496 batch_key = default_batch_key
497 SCons.Util.AddMethod(self, batch_key, 'batch_key')
498
500 sys.stdout.write(s + u"\n")
501
509 if not is_List(target):
510 target = [target]
511 if not is_List(source):
512 source = [source]
513
514 if presub is _null:
515 presub = self.presub
516 if presub is _null:
517 presub = print_actions_presub
518 if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
519 if show is _null: show = print_actions
520 if execute is _null: execute = execute_actions
521 if chdir is _null: chdir = self.chdir
522 save_cwd = None
523 if chdir:
524 save_cwd = os.getcwd()
525 try:
526 chdir = str(chdir.abspath)
527 except AttributeError:
528 if not is_String(chdir):
529 if executor:
530 chdir = str(executor.batches[0].targets[0].dir)
531 else:
532 chdir = str(target[0].dir)
533 if presub:
534 if executor:
535 target = executor.get_all_targets()
536 source = executor.get_all_sources()
537 t = ' and '.join(map(str, target))
538 l = '\n '.join(self.presub_lines(env))
539 out = u"Building %s with action:\n %s\n" % (t, l)
540 sys.stdout.write(out)
541 cmd = None
542 if show and self.strfunction:
543 if executor:
544 target = executor.get_all_targets()
545 source = executor.get_all_sources()
546 try:
547 cmd = self.strfunction(target, source, env, executor)
548 except TypeError:
549 cmd = self.strfunction(target, source, env)
550 if cmd:
551 if chdir:
552 cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd
553 try:
554 get = env.get
555 except AttributeError:
556 print_func = self.print_cmd_line
557 else:
558 print_func = get('PRINT_CMD_LINE_FUNC')
559 if not print_func:
560 print_func = self.print_cmd_line
561 print_func(cmd, target, source, env)
562 stat = 0
563 if execute:
564 if chdir:
565 os.chdir(chdir)
566 try:
567 stat = self.execute(target, source, env, executor=executor)
568 if isinstance(stat, SCons.Errors.BuildError):
569 s = exitstatfunc(stat.status)
570 if s:
571 stat.status = s
572 else:
573 stat = s
574 else:
575 stat = exitstatfunc(stat)
576 finally:
577 if save_cwd:
578 os.chdir(save_cwd)
579 if cmd and save_cwd:
580 print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
581
582 return stat
583
584
586 """Takes a list of command line arguments and returns a pretty
587 representation for printing."""
588 cl = []
589 for arg in map(str, cmd_list):
590 if ' ' in arg or '\t' in arg:
591 arg = '"' + arg + '"'
592 cl.append(arg)
593 return ' '.join(cl)
594
595
596
597
598
599
600 default_ENV = None
615
616
617
618
619
620 -def _subproc(scons_env, cmd, error = 'ignore', **kw):
621 """Do common setup for a subprocess.Popen() call"""
622
623 io = kw.get('stdin')
624 if is_String(io) and io == 'devnull':
625 kw['stdin'] = open(os.devnull)
626 io = kw.get('stdout')
627 if is_String(io) and io == 'devnull':
628 kw['stdout'] = open(os.devnull, 'w')
629 io = kw.get('stderr')
630 if is_String(io) and io == 'devnull':
631 kw['stderr'] = open(os.devnull, 'w')
632
633
634 ENV = kw.get('env', None)
635 if ENV is None: ENV = get_default_ENV(scons_env)
636
637
638 new_env = {}
639 for key, value in ENV.items():
640 if is_List(value):
641
642
643
644 value = SCons.Util.flatten_sequence(value)
645 new_env[key] = os.pathsep.join(map(str, value))
646 else:
647
648
649
650
651
652
653 new_env[key] = str(value)
654 kw['env'] = new_env
655
656 try:
657
658 return subprocess.Popen(cmd, **kw)
659 except EnvironmentError, e:
660 if error == 'raise': raise
661
662 class dummyPopen(object):
663 def __init__(self, e): self.exception = e
664 def communicate(self): return ('','')
665 def wait(self): return -self.exception.errno
666 stdin = None
667 class f(object):
668 def read(self): return ''
669 def readline(self): return ''
670 stdout = stderr = f()
671 return dummyPopen(e)
672
674 """Class for command-execution actions."""
676
677
678
679
680
681
682
683
684
685 if __debug__: logInstanceCreation(self, 'Action.CommandAction')
686
687 _ActionAction.__init__(self, **kw)
688 if is_List(cmd):
689 if list(filter(is_List, cmd)):
690 raise TypeError("CommandAction should be given only " \
691 "a single command")
692 self.cmd_list = cmd
693
695 if is_List(self.cmd_list):
696 return ' '.join(map(str, self.cmd_list))
697 return str(self.cmd_list)
698
699 - def process(self, target, source, env, executor=None):
700 if executor:
701 result = env.subst_list(self.cmd_list, 0, executor=executor)
702 else:
703 result = env.subst_list(self.cmd_list, 0, target, source)
704 silent = None
705 ignore = None
706 while True:
707 try: c = result[0][0][0]
708 except IndexError: c = None
709 if c == '@': silent = 1
710 elif c == '-': ignore = 1
711 else: break
712 result[0][0] = result[0][0][1:]
713 try:
714 if not result[0][0]:
715 result[0] = result[0][1:]
716 except IndexError:
717 pass
718 return result, ignore, silent
719
720 - def strfunction(self, target, source, env, executor=None):
721 if self.cmdstr is None:
722 return None
723 if self.cmdstr is not _null:
724 from SCons.Subst import SUBST_RAW
725 if executor:
726 c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
727 else:
728 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
729 if c:
730 return c
731 cmd_list, ignore, silent = self.process(target, source, env, executor)
732 if silent:
733 return ''
734 return _string_from_cmd_list(cmd_list[0])
735
736 - def execute(self, target, source, env, executor=None):
737 """Execute a command action.
738
739 This will handle lists of commands as well as individual commands,
740 because construction variable substitution may turn a single
741 "command" into a list. This means that this class can actually
742 handle lists of commands, even though that's not how we use it
743 externally.
744 """
745 escape_list = SCons.Subst.escape_list
746 flatten_sequence = SCons.Util.flatten_sequence
747
748 try:
749 shell = env['SHELL']
750 except KeyError:
751 raise SCons.Errors.UserError('Missing SHELL construction variable.')
752
753 try:
754 spawn = env['SPAWN']
755 except KeyError:
756 raise SCons.Errors.UserError('Missing SPAWN construction variable.')
757 else:
758 if is_String(spawn):
759 spawn = env.subst(spawn, raw=1, conv=lambda x: x)
760
761 escape = env.get('ESCAPE', lambda x: x)
762
763 ENV = get_default_ENV(env)
764
765
766 for key, value in ENV.items():
767 if not is_String(value):
768 if is_List(value):
769
770
771
772 value = flatten_sequence(value)
773 ENV[key] = os.pathsep.join(map(str, value))
774 else:
775
776
777
778
779 ENV[key] = str(value)
780
781 if executor:
782 target = executor.get_all_targets()
783 source = executor.get_all_sources()
784 cmd_list, ignore, silent = self.process(target, list(map(rfile, source)), env, executor)
785
786
787 for cmd_line in filter(len, cmd_list):
788
789 cmd_line = escape_list(cmd_line, escape)
790 result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
791 if not ignore and result:
792 msg = "Error %s" % result
793 return SCons.Errors.BuildError(errstr=msg,
794 status=result,
795 action=self,
796 command=cmd_line)
797 return 0
798
799 - def get_presig(self, target, source, env, executor=None):
800 """Return the signature contents of this action's command line.
801
802 This strips $(-$) and everything in between the string,
803 since those parts don't affect signatures.
804 """
805 from SCons.Subst import SUBST_SIG
806 cmd = self.cmd_list
807 if is_List(cmd):
808 cmd = ' '.join(map(str, cmd))
809 else:
810 cmd = str(cmd)
811 if executor:
812 return env.subst_target_source(cmd, SUBST_SIG, executor=executor)
813 else:
814 return env.subst_target_source(cmd, SUBST_SIG, target, source)
815
817 icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
818 if is_String(icd) and icd[:1] == '$':
819 icd = env.subst(icd)
820 if not icd or icd in ('0', 'None'):
821 return []
822 from SCons.Subst import SUBST_SIG
823 if executor:
824 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executor)
825 else:
826 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
827 res = []
828 for cmd_line in cmd_list:
829 if cmd_line:
830 d = str(cmd_line[0])
831 m = strip_quotes.match(d)
832 if m:
833 d = m.group(1)
834 d = env.WhereIs(d)
835 if d:
836 res.append(env.fs.File(d))
837 return res
838
840 """Class for command-generator actions."""
842 if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction')
843 self.generator = generator
844 self.gen_kw = kw
845 self.varlist = kw.get('varlist', ())
846 self.targets = kw.get('targets', '$TARGETS')
847
848 - def _generate(self, target, source, env, for_signature, executor=None):
849
850
851 if not is_List(target):
852 target = [target]
853
854 if executor:
855 target = executor.get_all_targets()
856 source = executor.get_all_sources()
857 ret = self.generator(target=target,
858 source=source,
859 env=env,
860 for_signature=for_signature)
861 gen_cmd = Action(ret, **self.gen_kw)
862 if not gen_cmd:
863 raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
864 return gen_cmd
865
867 try:
868 env = self.presub_env
869 except AttributeError:
870 env = None
871 if env is None:
872 env = SCons.Defaults.DefaultEnvironment()
873 act = self._generate([], [], env, 1)
874 return str(act)
875
878
879 - def genstring(self, target, source, env, executor=None):
880 return self._generate(target, source, env, 1, executor).genstring(target, source, env)
881
884 act = self._generate(target, source, env, 0, executor)
885 if act is None:
886 raise UserError("While building `%s': "
887 "Cannot deduce file extension from source files: %s"
888 % (repr(list(map(str, target))), repr(list(map(str, source)))))
889 return act(target, source, env, exitstatfunc, presub,
890 show, execute, chdir, executor)
891
892 - def get_presig(self, target, source, env, executor=None):
893 """Return the signature contents of this action's command line.
894
895 This strips $(-$) and everything in between the string,
896 since those parts don't affect signatures.
897 """
898 return self._generate(target, source, env, 1, executor).get_presig(target, source, env)
899
902
903 - def get_varlist(self, target, source, env, executor=None):
904 return self._generate(target, source, env, 1, executor).get_varlist(target, source, env, executor)
905
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928 -class LazyAction(CommandGeneratorAction, CommandAction):
929
936
942
944 if env:
945 c = env.get(self.var, '')
946 else:
947 c = ''
948 gen_cmd = Action(c, **self.gen_kw)
949 if not gen_cmd:
950 raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
951 return gen_cmd
952
953 - def _generate(self, target, source, env, for_signature, executor=None):
955
956 - def __call__(self, target, source, env, *args, **kw):
959
963
964 - def get_varlist(self, target, source, env, executor=None):
967
968
970 """Class for Python function actions."""
971
973 if __debug__: logInstanceCreation(self, 'Action.FunctionAction')
974
975 self.execfunction = execfunction
976 try:
977 self.funccontents = _callable_contents(execfunction)
978 except AttributeError:
979 try:
980
981 self.gc = execfunction.get_contents
982 except AttributeError:
983
984 self.funccontents = _object_contents(execfunction)
985
986 _ActionAction.__init__(self, **kw)
987
989 try:
990 return self.execfunction.__name__
991 except AttributeError:
992 try:
993 return self.execfunction.__class__.__name__
994 except AttributeError:
995 return "unknown_python_function"
996
997 - def strfunction(self, target, source, env, executor=None):
1017 return '[' + ", ".join(map(quote, a)) + ']'
1018 try:
1019 strfunc = self.execfunction.strfunction
1020 except AttributeError:
1021 pass
1022 else:
1023 if strfunc is None:
1024 return None
1025 if callable(strfunc):
1026 return strfunc(target, source, env)
1027 name = self.function_name()
1028 tstr = array(target)
1029 sstr = array(source)
1030 return "%s(%s, %s)" % (name, tstr, sstr)
1031
1033 name = self.function_name()
1034 if name == 'ActionCaller':
1035 return str(self.execfunction)
1036 return "%s(target, source, env)" % name
1037
1038 - def execute(self, target, source, env, executor=None):
1039 exc_info = (None,None,None)
1040 try:
1041 if executor:
1042 target = executor.get_all_targets()
1043 source = executor.get_all_sources()
1044 rsources = list(map(rfile, source))
1045 try:
1046 result = self.execfunction(target=target, source=rsources, env=env)
1047 except KeyboardInterrupt, e:
1048 raise
1049 except SystemExit, e:
1050 raise
1051 except Exception, e:
1052 result = e
1053 exc_info = sys.exc_info()
1054
1055 if result:
1056 result = SCons.Errors.convert_to_BuildError(result, exc_info)
1057 result.node=target
1058 result.action=self
1059 try:
1060 result.command=self.strfunction(target, source, env, executor)
1061 except TypeError:
1062 result.command=self.strfunction(target, source, env)
1063
1064
1065
1066
1067
1068
1069
1070 if (exc_info[1] and
1071 not isinstance(exc_info[1],EnvironmentError)):
1072 raise result
1073
1074 return result
1075 finally:
1076
1077
1078
1079 del exc_info
1080
1081
1083 """Return the signature contents of this callable action."""
1084 try:
1085 return self.gc(target, source, env)
1086 except AttributeError:
1087 return self.funccontents
1088
1091
1093 """Class for lists of other actions."""
1100 self.list = list(map(list_of_actions, actionlist))
1101
1102
1103 self.varlist = ()
1104 self.targets = '$TARGETS'
1105
1107 return '\n'.join([a.genstring(target, source, env) for a in self.list])
1108
1110 return '\n'.join(map(str, self.list))
1111
1115
1117 """Return the signature contents of this action list.
1118
1119 Simple concatenation of the signatures of the elements.
1120 """
1121 return "".join([x.get_contents(target, source, env) for x in self.list])
1122
1134
1140
1141 - def get_varlist(self, target, source, env, executor=None):
1147
1149 """A class for delaying calling an Action function with specific
1150 (positional and keyword) arguments until the Action is actually
1151 executed.
1152
1153 This class looks to the rest of the world like a normal Action object,
1154 but what it's really doing is hanging on to the arguments until we
1155 have a target, source and env to use for the expansion.
1156 """
1158 self.parent = parent
1159 self.args = args
1160 self.kw = kw
1161
1162 - def get_contents(self, target, source, env):
1163 actfunc = self.parent.actfunc
1164 try:
1165
1166 contents = str(actfunc.func_code.co_code)
1167 except AttributeError:
1168
1169 try:
1170 contents = str(actfunc.__call__.im_func.func_code.co_code)
1171 except AttributeError:
1172
1173
1174 contents = str(actfunc)
1175 contents = remove_set_lineno_codes(contents)
1176 return contents
1177
1178 - def subst(self, s, target, source, env):
1179
1180
1181 if is_List(s):
1182 result = []
1183 for elem in s:
1184 result.append(self.subst(elem, target, source, env))
1185 return self.parent.convert(result)
1186
1187
1188
1189
1190 if s == '$__env__':
1191 return env
1192 elif is_String(s):
1193 return env.subst(s, 1, target, source)
1194 return self.parent.convert(s)
1195
1197 return [self.subst(x, target, source, env) for x in self.args]
1198
1199 - def subst_kw(self, target, source, env):
1200 kw = {}
1201 for key in self.kw.keys():
1202 kw[key] = self.subst(self.kw[key], target, source, env)
1203 return kw
1204
1205 - def __call__(self, target, source, env, executor=None):
1206 args = self.subst_args(target, source, env)
1207 kw = self.subst_kw(target, source, env)
1208 return self.parent.actfunc(*args, **kw)
1209
1211 args = self.subst_args(target, source, env)
1212 kw = self.subst_kw(target, source, env)
1213 return self.parent.strfunc(*args, **kw)
1214
1216 return self.parent.strfunc(*self.args, **self.kw)
1217
1219 """A factory class that will wrap up an arbitrary function
1220 as an SCons-executable Action object.
1221
1222 The real heavy lifting here is done by the ActionCaller class.
1223 We just collect the (positional and keyword) arguments that we're
1224 called with and give them to the ActionCaller object we create,
1225 so it can hang onto them until it needs them.
1226 """
1227 - def __init__(self, actfunc, strfunc, convert=lambda x: x):
1228 self.actfunc = actfunc
1229 self.strfunc = strfunc
1230 self.convert = convert
1231
1236
1237
1238
1239
1240
1241
1242