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 2014/09/27 12:51:43 garyo"
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 import SCons.Debug
113 from SCons.Debug import logInstanceCreation
114 import SCons.Errors
115 import SCons.Executor
116 import SCons.Util
117 import SCons.Subst
118
119
120 is_String = SCons.Util.is_String
121 is_List = SCons.Util.is_List
122
125
126 print_actions = 1
127 execute_actions = 1
128 print_actions_presub = 0
129
131 try:
132 return n.rfile()
133 except AttributeError:
134 return n
135
138
139 try:
140 SET_LINENO = dis.SET_LINENO
141 HAVE_ARGUMENT = dis.HAVE_ARGUMENT
142 except AttributeError:
143 remove_set_lineno_codes = lambda x: x
144 else:
160
161 strip_quotes = re.compile('^[\'"](.*)[\'"]$')
162
163
165 """Return the signature contents of a callable Python object.
166 """
167 try:
168
169 return _function_contents(obj.im_func)
170
171 except AttributeError:
172 try:
173
174 return _function_contents(obj.__call__.im_func)
175
176 except AttributeError:
177 try:
178
179 return _code_contents(obj)
180
181 except AttributeError:
182
183 return _function_contents(obj)
184
185
187 """Return the signature contents of any Python object.
188
189 We have to handle the case where object contains a code object
190 since it can be pickled directly.
191 """
192 try:
193
194 return _function_contents(obj.im_func)
195
196 except AttributeError:
197 try:
198
199 return _function_contents(obj.__call__.im_func)
200
201 except AttributeError:
202 try:
203
204 return _code_contents(obj)
205
206 except AttributeError:
207 try:
208
209 return _function_contents(obj)
210
211 except AttributeError:
212
213 try:
214 return pickle.dumps(obj)
215 except (pickle.PicklingError, TypeError):
216
217
218
219
220
221 return str(obj)
222
223
224 -def _code_contents(code):
225 """Return the signature contents of a code object.
226
227 By providing direct access to the code object of the
228 function, Python makes this extremely easy. Hooray!
229
230 Unfortunately, older versions of Python include line
231 number indications in the compiled byte code. Boo!
232 So we remove the line number byte codes to prevent
233 recompilations from moving a Python function.
234 """
235
236 contents = []
237
238
239
240 contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames)))
241 try:
242 contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)))
243 except AttributeError:
244
245 contents.append(",0,0")
246
247
248
249
250
251
252
253
254
255 contents.append(',(' + ','.join(map(_object_contents,code.co_consts[1:])) + ')')
256
257
258
259
260
261 contents.append(',(' + ','.join(map(_object_contents,code.co_names)) + ')')
262
263
264
265 contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')')
266
267 return ''.join(contents)
268
269
271 """Return the signature contents of a function."""
272
273 contents = [_code_contents(func.func_code)]
274
275
276 if func.func_defaults:
277 contents.append(',(' + ','.join(map(_object_contents,func.func_defaults)) + ')')
278 else:
279 contents.append(',()')
280
281
282 try:
283 closure = func.func_closure or []
284 except AttributeError:
285
286 closure = []
287
288
289 try:
290 xxx = [_object_contents(x.cell_contents) for x in closure]
291 except AttributeError:
292 xxx = []
293 contents.append(',(' + ','.join(xxx) + ')')
294
295 return ''.join(contents)
296
297
299
300
301
302 a1 = Action(act1)
303 a2 = Action(act2)
304 if a1 is None:
305 return a2
306 if a2 is None:
307 return a1
308 if isinstance(a1, ListAction):
309 if isinstance(a2, ListAction):
310 return ListAction(a1.list + a2.list)
311 else:
312 return ListAction(a1.list + [ a2 ])
313 else:
314 if isinstance(a2, ListAction):
315 return ListAction([ a1 ] + a2.list)
316 else:
317 return ListAction([ a1, a2 ])
318
320 """This converts any arguments after the action argument into
321 their equivalent keywords and adds them to the kw argument.
322 """
323 v = kw.get('varlist', ())
324
325 if is_String(v): v = (v,)
326 kw['varlist'] = tuple(v)
327 if args:
328
329 cmdstrfunc = args[0]
330 if cmdstrfunc is None or is_String(cmdstrfunc):
331 kw['cmdstr'] = cmdstrfunc
332 elif callable(cmdstrfunc):
333 kw['strfunction'] = cmdstrfunc
334 else:
335 raise SCons.Errors.UserError(
336 'Invalid command display variable type. '
337 'You must either pass a string or a callback which '
338 'accepts (target, source, env) as parameters.')
339 if len(args) > 1:
340 kw['varlist'] = tuple(SCons.Util.flatten(args[1:])) + kw['varlist']
341 if kw.get('strfunction', _null) is not _null \
342 and kw.get('cmdstr', _null) is not _null:
343 raise SCons.Errors.UserError(
344 'Cannot have both strfunction and cmdstr args to Action()')
345
347 """This is the actual "implementation" for the
348 Action factory method, below. This handles the
349 fact that passing lists to Action() itself has
350 different semantics than passing lists as elements
351 of lists.
352
353 The former will create a ListAction, the latter
354 will create a CommandAction by converting the inner
355 list elements to strings."""
356
357 if isinstance(act, ActionBase):
358 return act
359
360 if is_List(act):
361 return CommandAction(act, **kw)
362
363 if callable(act):
364 try:
365 gen = kw['generator']
366 del kw['generator']
367 except KeyError:
368 gen = 0
369 if gen:
370 action_type = CommandGeneratorAction
371 else:
372 action_type = FunctionAction
373 return action_type(act, kw)
374
375 if is_String(act):
376 var=SCons.Util.get_environment_var(act)
377 if var:
378
379
380
381
382
383
384 return LazyAction(var, kw)
385 commands = str(act).split('\n')
386 if len(commands) == 1:
387 return CommandAction(commands[0], **kw)
388
389
390 return _do_create_list_action(commands, kw)
391
392 if isinstance(act, int) or isinstance(act, float):
393 raise TypeError("Don't know how to create an Action from a number (%s)"%act)
394
395 return None
396
398 """A factory for list actions. Convert the input list into Actions
399 and then wrap them in a ListAction."""
400 acts = []
401 for a in act:
402 aa = _do_create_action(a, kw)
403 if aa is not None: acts.append(aa)
404 if not acts:
405 return ListAction([])
406 elif len(acts) == 1:
407 return acts[0]
408 else:
409 return ListAction(acts)
410
412 """A factory for action objects."""
413
414 _do_create_keywords(args, kw)
415 if is_List(act):
416 return _do_create_list_action(act, kw)
417 return _do_create_action(act, kw)
418
420 """Base class for all types of action objects that can be held by
421 other objects (Builders, Executors, etc.) This provides the
422 common methods for manipulating and combining those actions."""
423
425 return cmp(self.__dict__, other)
426
429
430 batch_key = no_batch_key
431
434
435 - def get_contents(self, target, source, env):
436 result = [ self.get_presig(target, source, env) ]
437
438
439
440 vl = self.get_varlist(target, source, env)
441 if is_String(vl): vl = (vl,)
442 for v in vl:
443
444 result.append(env.subst_target_source('${'+v+'}', SCons.Subst.SUBST_SIG, target, source))
445 return ''.join(result)
446
448 return _actionAppend(self, other)
449
451 return _actionAppend(other, self)
452
454
455
456
457
458
459
460 self.presub_env = env
461 lines = str(self).split('\n')
462 self.presub_env = None
463 return lines
464
465 - def get_varlist(self, target, source, env, executor=None):
467
469 """
470 Returns the type of targets ($TARGETS, $CHANGED_TARGETS) used
471 by this action.
472 """
473 return self.targets
474
476 """Base class for actions that create output objects."""
477 - def __init__(self, cmdstr=_null, strfunction=_null, varlist=(),
478 presub=_null, chdir=None, exitstatfunc=None,
479 batch_key=None, targets='$TARGETS',
480 **kw):
481 self.cmdstr = cmdstr
482 if strfunction is not _null:
483 if strfunction is None:
484 self.cmdstr = None
485 else:
486 self.strfunction = strfunction
487 self.varlist = varlist
488 self.presub = presub
489 self.chdir = chdir
490 if not exitstatfunc:
491 exitstatfunc = default_exitstatfunc
492 self.exitstatfunc = exitstatfunc
493
494 self.targets = targets
495
496 if batch_key:
497 if not callable(batch_key):
498
499
500
501
502 def default_batch_key(self, env, target, source):
503 return (id(self), id(env))
504 batch_key = default_batch_key
505 SCons.Util.AddMethod(self, batch_key, 'batch_key')
506
508
509
510
511
512
513
514
515
516 try:
517 sys.stdout.write(unicode(s + "\n"))
518 except UnicodeDecodeError:
519 sys.stdout.write(s + "\n")
520
528 if not is_List(target):
529 target = [target]
530 if not is_List(source):
531 source = [source]
532
533 if presub is _null:
534 presub = self.presub
535 if presub is _null:
536 presub = print_actions_presub
537 if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
538 if show is _null: show = print_actions
539 if execute is _null: execute = execute_actions
540 if chdir is _null: chdir = self.chdir
541 save_cwd = None
542 if chdir:
543 save_cwd = os.getcwd()
544 try:
545 chdir = str(chdir.abspath)
546 except AttributeError:
547 if not is_String(chdir):
548 if executor:
549 chdir = str(executor.batches[0].targets[0].dir)
550 else:
551 chdir = str(target[0].dir)
552 if presub:
553 if executor:
554 target = executor.get_all_targets()
555 source = executor.get_all_sources()
556 t = ' and '.join(map(str, target))
557 l = '\n '.join(self.presub_lines(env))
558 out = u"Building %s with action:\n %s\n" % (t, l)
559 sys.stdout.write(out)
560 cmd = None
561 if show and self.strfunction:
562 if executor:
563 target = executor.get_all_targets()
564 source = executor.get_all_sources()
565 try:
566 cmd = self.strfunction(target, source, env, executor)
567 except TypeError:
568 cmd = self.strfunction(target, source, env)
569 if cmd:
570 if chdir:
571 cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd
572 try:
573 get = env.get
574 except AttributeError:
575 print_func = self.print_cmd_line
576 else:
577 print_func = get('PRINT_CMD_LINE_FUNC')
578 if not print_func:
579 print_func = self.print_cmd_line
580 print_func(cmd, target, source, env)
581 stat = 0
582 if execute:
583 if chdir:
584 os.chdir(chdir)
585 try:
586 stat = self.execute(target, source, env, executor=executor)
587 if isinstance(stat, SCons.Errors.BuildError):
588 s = exitstatfunc(stat.status)
589 if s:
590 stat.status = s
591 else:
592 stat = s
593 else:
594 stat = exitstatfunc(stat)
595 finally:
596 if save_cwd:
597 os.chdir(save_cwd)
598 if cmd and save_cwd:
599 print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
600
601 return stat
602
603
605 """Takes a list of command line arguments and returns a pretty
606 representation for printing."""
607 cl = []
608 for arg in map(str, cmd_list):
609 if ' ' in arg or '\t' in arg:
610 arg = '"' + arg + '"'
611 cl.append(arg)
612 return ' '.join(cl)
613
614
615
616
617
618
619 default_ENV = None
634
635
636
637
638
639 -def _subproc(scons_env, cmd, error = 'ignore', **kw):
640 """Do common setup for a subprocess.Popen() call"""
641
642 io = kw.get('stdin')
643 if is_String(io) and io == 'devnull':
644 kw['stdin'] = open(os.devnull)
645 io = kw.get('stdout')
646 if is_String(io) and io == 'devnull':
647 kw['stdout'] = open(os.devnull, 'w')
648 io = kw.get('stderr')
649 if is_String(io) and io == 'devnull':
650 kw['stderr'] = open(os.devnull, 'w')
651
652
653 ENV = kw.get('env', None)
654 if ENV is None: ENV = get_default_ENV(scons_env)
655
656
657 new_env = {}
658 for key, value in ENV.items():
659 if is_List(value):
660
661
662
663 value = SCons.Util.flatten_sequence(value)
664 new_env[key] = os.pathsep.join(map(str, value))
665 else:
666
667
668
669
670
671
672 new_env[key] = str(value)
673 kw['env'] = new_env
674
675 try:
676 return subprocess.Popen(cmd, **kw)
677 except EnvironmentError, e:
678 if error == 'raise': raise
679
680 class dummyPopen(object):
681 def __init__(self, e): self.exception = e
682 def communicate(self,input=None): return ('','')
683 def wait(self): return -self.exception.errno
684 stdin = None
685 class f(object):
686 def read(self): return ''
687 def readline(self): return ''
688 def __iter__(self): return iter(())
689 stdout = stderr = f()
690 return dummyPopen(e)
691
693 """Class for command-execution actions."""
695
696
697
698
699
700
701
702
703
704 if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.CommandAction')
705
706 _ActionAction.__init__(self, **kw)
707 if is_List(cmd):
708 if list(filter(is_List, cmd)):
709 raise TypeError("CommandAction should be given only " \
710 "a single command")
711 self.cmd_list = cmd
712
714 if is_List(self.cmd_list):
715 return ' '.join(map(str, self.cmd_list))
716 return str(self.cmd_list)
717
718 - def process(self, target, source, env, executor=None):
719 if executor:
720 result = env.subst_list(self.cmd_list, 0, executor=executor)
721 else:
722 result = env.subst_list(self.cmd_list, 0, target, source)
723 silent = None
724 ignore = None
725 while True:
726 try: c = result[0][0][0]
727 except IndexError: c = None
728 if c == '@': silent = 1
729 elif c == '-': ignore = 1
730 else: break
731 result[0][0] = result[0][0][1:]
732 try:
733 if not result[0][0]:
734 result[0] = result[0][1:]
735 except IndexError:
736 pass
737 return result, ignore, silent
738
739 - def strfunction(self, target, source, env, executor=None):
740 if self.cmdstr is None:
741 return None
742 if self.cmdstr is not _null:
743 from SCons.Subst import SUBST_RAW
744 if executor:
745 c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
746 else:
747 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
748 if c:
749 return c
750 cmd_list, ignore, silent = self.process(target, source, env, executor)
751 if silent:
752 return ''
753 return _string_from_cmd_list(cmd_list[0])
754
755 - def execute(self, target, source, env, executor=None):
756 """Execute a command action.
757
758 This will handle lists of commands as well as individual commands,
759 because construction variable substitution may turn a single
760 "command" into a list. This means that this class can actually
761 handle lists of commands, even though that's not how we use it
762 externally.
763 """
764 escape_list = SCons.Subst.escape_list
765 flatten_sequence = SCons.Util.flatten_sequence
766
767 try:
768 shell = env['SHELL']
769 except KeyError:
770 raise SCons.Errors.UserError('Missing SHELL construction variable.')
771
772 try:
773 spawn = env['SPAWN']
774 except KeyError:
775 raise SCons.Errors.UserError('Missing SPAWN construction variable.')
776 else:
777 if is_String(spawn):
778 spawn = env.subst(spawn, raw=1, conv=lambda x: x)
779
780 escape = env.get('ESCAPE', lambda x: x)
781
782 ENV = get_default_ENV(env)
783
784
785 for key, value in ENV.items():
786 if not is_String(value):
787 if is_List(value):
788
789
790
791 value = flatten_sequence(value)
792 ENV[key] = os.pathsep.join(map(str, value))
793 else:
794
795
796
797
798 ENV[key] = str(value)
799
800 if executor:
801 target = executor.get_all_targets()
802 source = executor.get_all_sources()
803 cmd_list, ignore, silent = self.process(target, list(map(rfile, source)), env, executor)
804
805
806 for cmd_line in filter(len, cmd_list):
807
808 cmd_line = escape_list(cmd_line, escape)
809 result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
810 if not ignore and result:
811 msg = "Error %s" % result
812 return SCons.Errors.BuildError(errstr=msg,
813 status=result,
814 action=self,
815 command=cmd_line)
816 return 0
817
818 - def get_presig(self, target, source, env, executor=None):
819 """Return the signature contents of this action's command line.
820
821 This strips $(-$) and everything in between the string,
822 since those parts don't affect signatures.
823 """
824 from SCons.Subst import SUBST_SIG
825 cmd = self.cmd_list
826 if is_List(cmd):
827 cmd = ' '.join(map(str, cmd))
828 else:
829 cmd = str(cmd)
830 if executor:
831 return env.subst_target_source(cmd, SUBST_SIG, executor=executor)
832 else:
833 return env.subst_target_source(cmd, SUBST_SIG, target, source)
834
836 icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
837 if is_String(icd) and icd[:1] == '$':
838 icd = env.subst(icd)
839 if not icd or icd in ('0', 'None'):
840 return []
841 from SCons.Subst import SUBST_SIG
842 if executor:
843 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executor)
844 else:
845 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
846 res = []
847 for cmd_line in cmd_list:
848 if cmd_line:
849 d = str(cmd_line[0])
850 m = strip_quotes.match(d)
851 if m:
852 d = m.group(1)
853 d = env.WhereIs(d)
854 if d:
855 res.append(env.fs.File(d))
856 return res
857
859 """Class for command-generator actions."""
866
867 - def _generate(self, target, source, env, for_signature, executor=None):
868
869
870 if not is_List(target):
871 target = [target]
872
873 if executor:
874 target = executor.get_all_targets()
875 source = executor.get_all_sources()
876 ret = self.generator(target=target,
877 source=source,
878 env=env,
879 for_signature=for_signature)
880 gen_cmd = Action(ret, **self.gen_kw)
881 if not gen_cmd:
882 raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
883 return gen_cmd
884
886 try:
887 env = self.presub_env
888 except AttributeError:
889 env = None
890 if env is None:
891 env = SCons.Defaults.DefaultEnvironment()
892 act = self._generate([], [], env, 1)
893 return str(act)
894
897
898 - def genstring(self, target, source, env, executor=None):
899 return self._generate(target, source, env, 1, executor).genstring(target, source, env)
900
903 act = self._generate(target, source, env, 0, executor)
904 if act is None:
905 raise SCons.Errors.UserError("While building `%s': "
906 "Cannot deduce file extension from source files: %s"
907 % (repr(list(map(str, target))), repr(list(map(str, source)))))
908 return act(target, source, env, exitstatfunc, presub,
909 show, execute, chdir, executor)
910
911 - def get_presig(self, target, source, env, executor=None):
912 """Return the signature contents of this action's command line.
913
914 This strips $(-$) and everything in between the string,
915 since those parts don't affect signatures.
916 """
917 return self._generate(target, source, env, 1, executor).get_presig(target, source, env)
918
921
922 - def get_varlist(self, target, source, env, executor=None):
923 return self._generate(target, source, env, 1, executor).get_varlist(target, source, env, executor)
924
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947 -class LazyAction(CommandGeneratorAction, CommandAction):
948
955
961
963 if env:
964 c = env.get(self.var, '')
965 else:
966 c = ''
967 gen_cmd = Action(c, **self.gen_kw)
968 if not gen_cmd:
969 raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
970 return gen_cmd
971
972 - def _generate(self, target, source, env, for_signature, executor=None):
974
975 - def __call__(self, target, source, env, *args, **kw):
978
982
983 - def get_varlist(self, target, source, env, executor=None):
986
987
989 """Class for Python function actions."""
990
992 if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.FunctionAction')
993
994 self.execfunction = execfunction
995 try:
996 self.funccontents = _callable_contents(execfunction)
997 except AttributeError:
998 try:
999
1000 self.gc = execfunction.get_contents
1001 except AttributeError:
1002
1003 self.funccontents = _object_contents(execfunction)
1004
1005 _ActionAction.__init__(self, **kw)
1006
1008 try:
1009 return self.execfunction.__name__
1010 except AttributeError:
1011 try:
1012 return self.execfunction.__class__.__name__
1013 except AttributeError:
1014 return "unknown_python_function"
1015
1016 - def strfunction(self, target, source, env, executor=None):
1036 return '[' + ", ".join(map(quote, a)) + ']'
1037 try:
1038 strfunc = self.execfunction.strfunction
1039 except AttributeError:
1040 pass
1041 else:
1042 if strfunc is None:
1043 return None
1044 if callable(strfunc):
1045 return strfunc(target, source, env)
1046 name = self.function_name()
1047 tstr = array(target)
1048 sstr = array(source)
1049 return "%s(%s, %s)" % (name, tstr, sstr)
1050
1052 name = self.function_name()
1053 if name == 'ActionCaller':
1054 return str(self.execfunction)
1055 return "%s(target, source, env)" % name
1056
1057 - def execute(self, target, source, env, executor=None):
1058 exc_info = (None,None,None)
1059 try:
1060 if executor:
1061 target = executor.get_all_targets()
1062 source = executor.get_all_sources()
1063 rsources = list(map(rfile, source))
1064 try:
1065 result = self.execfunction(target=target, source=rsources, env=env)
1066 except KeyboardInterrupt, e:
1067 raise
1068 except SystemExit, e:
1069 raise
1070 except Exception, e:
1071 result = e
1072 exc_info = sys.exc_info()
1073
1074 if result:
1075 result = SCons.Errors.convert_to_BuildError(result, exc_info)
1076 result.node=target
1077 result.action=self
1078 try:
1079 result.command=self.strfunction(target, source, env, executor)
1080 except TypeError:
1081 result.command=self.strfunction(target, source, env)
1082
1083
1084
1085
1086
1087
1088
1089 if (exc_info[1] and
1090 not isinstance(exc_info[1],EnvironmentError)):
1091 raise result
1092
1093 return result
1094 finally:
1095
1096
1097
1098 del exc_info
1099
1100
1102 """Return the signature contents of this callable action."""
1103 try:
1104 return self.gc(target, source, env)
1105 except AttributeError:
1106 return self.funccontents
1107
1110
1112 """Class for lists of other actions."""
1119 self.list = list(map(list_of_actions, actionlist))
1120
1121
1122 self.varlist = ()
1123 self.targets = '$TARGETS'
1124
1126 return '\n'.join([a.genstring(target, source, env) for a in self.list])
1127
1129 return '\n'.join(map(str, self.list))
1130
1134
1136 """Return the signature contents of this action list.
1137
1138 Simple concatenation of the signatures of the elements.
1139 """
1140 return "".join([x.get_contents(target, source, env) for x in self.list])
1141
1153
1159
1160 - def get_varlist(self, target, source, env, executor=None):
1166
1168 """A class for delaying calling an Action function with specific
1169 (positional and keyword) arguments until the Action is actually
1170 executed.
1171
1172 This class looks to the rest of the world like a normal Action object,
1173 but what it's really doing is hanging on to the arguments until we
1174 have a target, source and env to use for the expansion.
1175 """
1177 self.parent = parent
1178 self.args = args
1179 self.kw = kw
1180
1181 - def get_contents(self, target, source, env):
1182 actfunc = self.parent.actfunc
1183 try:
1184
1185 contents = str(actfunc.func_code.co_code)
1186 except AttributeError:
1187
1188 try:
1189 contents = str(actfunc.__call__.im_func.func_code.co_code)
1190 except AttributeError:
1191
1192
1193 contents = str(actfunc)
1194 contents = remove_set_lineno_codes(contents)
1195 return contents
1196
1197 - def subst(self, s, target, source, env):
1198
1199
1200 if is_List(s):
1201 result = []
1202 for elem in s:
1203 result.append(self.subst(elem, target, source, env))
1204 return self.parent.convert(result)
1205
1206
1207
1208
1209 if s == '$__env__':
1210 return env
1211 elif is_String(s):
1212 return env.subst(s, 1, target, source)
1213 return self.parent.convert(s)
1214
1216 return [self.subst(x, target, source, env) for x in self.args]
1217
1218 - def subst_kw(self, target, source, env):
1219 kw = {}
1220 for key in self.kw.keys():
1221 kw[key] = self.subst(self.kw[key], target, source, env)
1222 return kw
1223
1224 - def __call__(self, target, source, env, executor=None):
1225 args = self.subst_args(target, source, env)
1226 kw = self.subst_kw(target, source, env)
1227 return self.parent.actfunc(*args, **kw)
1228
1230 args = self.subst_args(target, source, env)
1231 kw = self.subst_kw(target, source, env)
1232 return self.parent.strfunc(*args, **kw)
1233
1235 return self.parent.strfunc(*self.args, **self.kw)
1236
1238 """A factory class that will wrap up an arbitrary function
1239 as an SCons-executable Action object.
1240
1241 The real heavy lifting here is done by the ActionCaller class.
1242 We just collect the (positional and keyword) arguments that we're
1243 called with and give them to the ActionCaller object we create,
1244 so it can hang onto them until it needs them.
1245 """
1246 - def __init__(self, actfunc, strfunc, convert=lambda x: x):
1247 self.actfunc = actfunc
1248 self.strfunc = strfunc
1249 self.convert = convert
1250
1255
1256
1257
1258
1259
1260
1261