Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: scons-2.0.1/engine/SCons/Action.py

Issue 6711079: Added an unmodified copy of SCons to third_party. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/third_party/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « scons-2.0.1/RELEASE.txt ('k') | scons-2.0.1/engine/SCons/Builder.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The S Cons Foundation
80 #
81 # Permission is hereby granted, free of charge, to any person obtaining
82 # a copy of this software and associated documentation files (the
83 # "Software"), to deal in the Software without restriction, including
84 # without limitation the rights to use, copy, modify, merge, publish,
85 # distribute, sublicense, and/or sell copies of the Software, and to
86 # permit persons to whom the Software is furnished to do so, subject to
87 # the following conditions:
88 #
89 # The above copyright notice and this permission notice shall be included
90 # in all copies or substantial portions of the Software.
91 #
92 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
93 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
94 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
95 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
96 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
97 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
98 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
99
100 __revision__ = "src/engine/SCons/Action.py 5134 2010/08/16 23:02:40 bdeegan"
101
102 import SCons.compat
103
104 import dis
105 import os
106 # compat layer imports "cPickle" for us if it's available.
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 # we use these a lot, so try to optimize them
119 is_String = SCons.Util.is_String
120 is_List = SCons.Util.is_List
121
122 class _null(object):
123 pass
124
125 print_actions = 1
126 execute_actions = 1
127 print_actions_presub = 0
128
129 def rfile(n):
130 try:
131 return n.rfile()
132 except AttributeError:
133 return n
134
135 def default_exitstatfunc(s):
136 return s
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:
144 def remove_set_lineno_codes(code):
145 result = []
146 n = len(code)
147 i = 0
148 while i < n:
149 c = code[i]
150 op = ord(c)
151 if op >= HAVE_ARGUMENT:
152 if op != SET_LINENO:
153 result.append(code[i:i+3])
154 i = i+3
155 else:
156 result.append(c)
157 i = i+1
158 return ''.join(result)
159
160 strip_quotes = re.compile('^[\'"](.*)[\'"]$')
161
162
163 def _callable_contents(obj):
164 """Return the signature contents of a callable Python object.
165 """
166 try:
167 # Test if obj is a method.
168 return _function_contents(obj.im_func)
169
170 except AttributeError:
171 try:
172 # Test if obj is a callable object.
173 return _function_contents(obj.__call__.im_func)
174
175 except AttributeError:
176 try:
177 # Test if obj is a code object.
178 return _code_contents(obj)
179
180 except AttributeError:
181 # Test if obj is a function object.
182 return _function_contents(obj)
183
184
185 def _object_contents(obj):
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 # Test if obj is a method.
193 return _function_contents(obj.im_func)
194
195 except AttributeError:
196 try:
197 # Test if obj is a callable object.
198 return _function_contents(obj.__call__.im_func)
199
200 except AttributeError:
201 try:
202 # Test if obj is a code object.
203 return _code_contents(obj)
204
205 except AttributeError:
206 try:
207 # Test if obj is a function object.
208 return _function_contents(obj)
209
210 except AttributeError:
211 # Should be a pickable Python object.
212 try:
213 return pickle.dumps(obj)
214 except (pickle.PicklingError, TypeError):
215 # This is weird, but it seems that nested classes
216 # are unpickable. The Python docs say it should
217 # always be a PicklingError, but some Python
218 # versions seem to return TypeError. Just do
219 # the best we can.
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 # The code contents depends on the number of local variables
238 # but not their actual names.
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 # Older versions of Python do not support closures.
244 contents.append(",0,0")
245
246 # The code contents depends on any constants accessed by the
247 # function. Note that we have to call _object_contents on each
248 # constants because the code object of nested functions can
249 # show-up among the constants.
250 #
251 # Note that we also always ignore the first entry of co_consts
252 # which contains the function doc string. We assume that the
253 # function does not access its doc string.
254 contents.append(',(' + ','.join(map(_object_contents,code.co_consts[1:])) + ')')
255
256 # The code contents depends on the variable names used to
257 # accessed global variable, as changing the variable name changes
258 # the variable actually accessed and therefore changes the
259 # function result.
260 contents.append(',(' + ','.join(map(_object_contents,code.co_names)) + ')')
261
262
263 # The code contents depends on its actual code!!!
264 contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')')
265
266 return ''.join(contents)
267
268
269 def _function_contents(func):
270 """Return the signature contents of a function."""
271
272 contents = [_code_contents(func.func_code)]
273
274 # The function contents depends on the value of defaults arguments
275 if func.func_defaults:
276 contents.append(',(' + ','.join(map(_object_contents,func.func_defaults) ) + ')')
277 else:
278 contents.append(',()')
279
280 # The function contents depends on the closure captured cell values.
281 try:
282 closure = func.func_closure or []
283 except AttributeError:
284 # Older versions of Python do not support closures.
285 closure = []
286
287 #xxx = [_object_contents(x.cell_contents) for x in closure]
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
297 def _actionAppend(act1, act2):
298 # This function knows how to slap two actions together.
299 # Mainly, it handles ListActions by concatenating into
300 # a single ListAction.
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
316 def _do_create_keywords(args, kw):
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 # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O']
322 if is_String(v): v = (v,)
323 kw['varlist'] = tuple(v)
324 if args:
325 # turn positional args into equivalent keywords
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
343 def _do_create_action(act, kw):
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 # This looks like a string that is purely an Environment
376 # variable reference, like "$FOO" or "${FOO}". We do
377 # something special here...we lazily evaluate the contents
378 # of that Environment variable, so a user could put something
379 # like a function or a CommandGenerator in that variable
380 # instead of a string.
381 return LazyAction(var, kw)
382 commands = str(act).split('\n')
383 if len(commands) == 1:
384 return CommandAction(commands[0], **kw)
385 # The list of string commands may include a LazyAction, so we
386 # reprocess them via _do_create_list_action.
387 return _do_create_list_action(commands, kw)
388 return None
389
390 def _do_create_list_action(act, kw):
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
404 def Action(act, *args, **kw):
405 """A factory for action objects."""
406 # Really simple: the _do_create_* routines do the heavy lifting.
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
412 class ActionBase(object):
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
417 def __cmp__(self, other):
418 return cmp(self.__dict__, other)
419
420 def no_batch_key(self, env, target, source):
421 return None
422
423 batch_key = no_batch_key
424
425 def genstring(self, target, source, env):
426 return str(self)
427
428 def get_contents(self, target, source, env):
429 result = [ self.get_presig(target, source, env) ]
430 # This should never happen, as the Action() factory should wrap
431 # the varlist, but just in case an action is created directly,
432 # we duplicate this check here.
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
439 def __add__(self, other):
440 return _actionAppend(self, other)
441
442 def __radd__(self, other):
443 return _actionAppend(other, self)
444
445 def presub_lines(self, env):
446 # CommandGeneratorAction needs a real environment
447 # in order to return the proper string here, since
448 # it may call LazyAction, which looks up a key
449 # in that env. So we temporarily remember the env here,
450 # and CommandGeneratorAction will use this env
451 # when it calls its _generate method.
452 self.presub_env = env
453 lines = str(self).split('\n')
454 self.presub_env = None # don't need this any more
455 return lines
456
457 def get_varlist(self, target, source, env, executor=None):
458 return self.varlist
459
460 def get_targets(self, env, executor):
461 """
462 Returns the type of targets ($TARGETS, $CHANGED_TARGETS) used
463 by this action.
464 """
465 return self.targets
466
467 class _ActionAction(ActionBase):
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 # They have set batch_key, but not to their own
491 # callable. The default behavior here will batch
492 # *all* targets+sources using this action, separated
493 # for each construction environment.
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
499 def print_cmd_line(self, s, target, source, env):
500 sys.stdout.write(s + u"\n")
501
502 def __call__(self, target, source, env,
503 exitstatfunc=_null,
504 presub=_null,
505 show=_null,
506 execute=_null,
507 chdir=_null,
508 executor=None):
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
585 def _string_from_cmd_list(cmd_list):
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 # A fiddlin' little function that has an 'import SCons.Environment' which
596 # can't be moved to the top level without creating an import loop. Since
597 # this import creates a local variable named 'SCons', it blocks access to
598 # the global variable, so we move it here to prevent complaints about local
599 # variables being used uninitialized.
600 default_ENV = None
601 def get_default_ENV(env):
602 global default_ENV
603 try:
604 return env['ENV']
605 except KeyError:
606 if not default_ENV:
607 import SCons.Environment
608 # This is a hideously expensive way to get a default shell
609 # environment. What it really should do is run the platform
610 # setup to get the default ENV. Fortunately, it's incredibly
611 # rare for an Environment not to have a shell environment, so
612 # we're not going to worry about it overmuch.
613 default_ENV = SCons.Environment.Environment()['ENV']
614 return default_ENV
615
616 # This function is still in draft mode. We're going to need something like
617 # it in the long run as more and more places use subprocess, but I'm sure
618 # it'll have to be tweaked to get the full desired functionality.
619 # one special arg (so far?), 'error', to tell what to do with exceptions.
620 def _subproc(scons_env, cmd, error = 'ignore', **kw):
621 """Do common setup for a subprocess.Popen() call"""
622 # allow std{in,out,err} to be "'devnull'"
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 # Figure out what shell environment to use
634 ENV = kw.get('env', None)
635 if ENV is None: ENV = get_default_ENV(scons_env)
636
637 # Ensure that the ENV values are all strings:
638 new_env = {}
639 for key, value in ENV.items():
640 if is_List(value):
641 # If the value is a list, then we assume it is a path list,
642 # because that's a pretty common list-like value to stick
643 # in an environment variable:
644 value = SCons.Util.flatten_sequence(value)
645 new_env[key] = os.pathsep.join(map(str, value))
646 else:
647 # It's either a string or something else. If it's a string,
648 # we still want to call str() because it might be a *Unicode*
649 # string, which makes subprocess.Popen() gag. If it isn't a
650 # string or a list, then we just coerce it to a string, which
651 # is the proper way to handle Dir and File instances and will
652 # produce something reasonable for just about everything else:
653 new_env[key] = str(value)
654 kw['env'] = new_env
655
656 try:
657 #FUTURE return subprocess.Popen(cmd, **kw)
658 return subprocess.Popen(cmd, **kw)
659 except EnvironmentError, e:
660 if error == 'raise': raise
661 # return a dummy Popen instance that only returns error
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
673 class CommandAction(_ActionAction):
674 """Class for command-execution actions."""
675 def __init__(self, cmd, **kw):
676 # Cmd can actually be a list or a single item; if it's a
677 # single item it should be the command string to execute; if a
678 # list then it should be the words of the command string to
679 # execute. Only a single command should be executed by this
680 # object; lists of commands should be handled by embedding
681 # these objects in a ListAction object (which the Action()
682 # factory above does). cmd will be passed to
683 # Environment.subst_list() for substituting environment
684 # variables.
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
694 def __str__(self):
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 # Ensure that the ENV values are all strings:
766 for key, value in ENV.items():
767 if not is_String(value):
768 if is_List(value):
769 # If the value is a list, then we assume it is a
770 # path list, because that's a pretty common list-like
771 # value to stick in an environment variable:
772 value = flatten_sequence(value)
773 ENV[key] = os.pathsep.join(map(str, value))
774 else:
775 # If it isn't a string or a list, then we just coerce
776 # it to a string, which is the proper way to handle
777 # Dir and File instances and will produce something
778 # reasonable for just about everything else:
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 # Use len() to filter out any "command" that's zero-length.
787 for cmd_line in filter(len, cmd_list):
788 # Escape the command line for the interpreter we are using.
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
816 def get_implicit_deps(self, target, source, env, executor=None):
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=executo r)
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
839 class CommandGeneratorAction(ActionBase):
840 """Class for command-generator actions."""
841 def __init__(self, generator, kw):
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 # ensure that target is a list, to make it easier to write
850 # generator functions:
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
866 def __str__(self):
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
876 def batch_key(self, env, target, source):
877 return self._generate(target, source, env, 1).batch_key(env, target, sou rce)
878
879 def genstring(self, target, source, env, executor=None):
880 return self._generate(target, source, env, 1, executor).genstring(target , source, env)
881
882 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
883 show=_null, execute=_null, chdir=_null, executor=None):
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(targe t, source, env)
899
900 def get_implicit_deps(self, target, source, env, executor=None):
901 return self._generate(target, source, env, 1, executor).get_implicit_dep s(target, source, env)
902
903 def get_varlist(self, target, source, env, executor=None):
904 return self._generate(target, source, env, 1, executor).get_varlist(targ et, source, env, executor)
905
906 def get_targets(self, env, executor):
907 return self._generate(None, None, env, 1, executor).get_targets(env, exe cutor)
908
909
910
911 # A LazyAction is a kind of hybrid generator and command action for
912 # strings of the form "$VAR". These strings normally expand to other
913 # strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also
914 # want to be able to replace them with functions in the construction
915 # environment. Consequently, we want lazy evaluation and creation of
916 # an Action in the case of the function, but that's overkill in the more
917 # normal case of expansion to other strings.
918 #
919 # So we do this with a subclass that's both a generator *and*
920 # a command action. The overridden methods all do a quick check
921 # of the construction variable, and if it's a string we just call
922 # the corresponding CommandAction method to do the heavy lifting.
923 # If not, then we call the same-named CommandGeneratorAction method.
924 # The CommandGeneratorAction methods work by using the overridden
925 # _generate() method, that is, our own way of handling "generation" of
926 # an action based on what's in the construction variable.
927
928 class LazyAction(CommandGeneratorAction, CommandAction):
929
930 def __init__(self, var, kw):
931 if __debug__: logInstanceCreation(self, 'Action.LazyAction')
932 #FUTURE CommandAction.__init__(self, '${'+var+'}', **kw)
933 CommandAction.__init__(self, '${'+var+'}', **kw)
934 self.var = SCons.Util.to_String(var)
935 self.gen_kw = kw
936
937 def get_parent_class(self, env):
938 c = env.get(self.var)
939 if is_String(c) and not '\n' in c:
940 return CommandAction
941 return CommandGeneratorAction
942
943 def _generate_cache(self, env):
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):
954 return self._generate_cache(env)
955
956 def __call__(self, target, source, env, *args, **kw):
957 c = self.get_parent_class(env)
958 return c.__call__(self, target, source, env, *args, **kw)
959
960 def get_presig(self, target, source, env):
961 c = self.get_parent_class(env)
962 return c.get_presig(self, target, source, env)
963
964 def get_varlist(self, target, source, env, executor=None):
965 c = self.get_parent_class(env)
966 return c.get_varlist(self, target, source, env, executor)
967
968
969 class FunctionAction(_ActionAction):
970 """Class for Python function actions."""
971
972 def __init__(self, execfunction, kw):
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 # See if execfunction will do the heavy lifting for us.
981 self.gc = execfunction.get_contents
982 except AttributeError:
983 # This is weird, just do the best we can.
984 self.funccontents = _object_contents(execfunction)
985
986 _ActionAction.__init__(self, **kw)
987
988 def function_name(self):
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):
998 if self.cmdstr is None:
999 return None
1000 if self.cmdstr is not _null:
1001 from SCons.Subst import SUBST_RAW
1002 if executor:
1003 c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
1004 else:
1005 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
1006 if c:
1007 return c
1008 def array(a):
1009 def quote(s):
1010 try:
1011 str_for_display = s.str_for_display
1012 except AttributeError:
1013 s = repr(s)
1014 else:
1015 s = str_for_display()
1016 return s
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
1032 def __str__(self):
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=e nv)
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, executo r)
1061 except TypeError:
1062 result.command=self.strfunction(target, source, env)
1063
1064 # FIXME: This maintains backward compatibility with respect to
1065 # which type of exceptions were returned by raising an
1066 # exception and which ones were returned by value. It would
1067 # probably be best to always return them by value here, but
1068 # some codes do not check the return value of Actions and I do
1069 # not have the time to modify them at this point.
1070 if (exc_info[1] and
1071 not isinstance(exc_info[1],EnvironmentError)):
1072 raise result
1073
1074 return result
1075 finally:
1076 # Break the cycle between the traceback object and this
1077 # function stack frame. See the sys.exc_info() doc info for
1078 # more information about this issue.
1079 del exc_info
1080
1081
1082 def get_presig(self, target, source, env):
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
1089 def get_implicit_deps(self, target, source, env):
1090 return []
1091
1092 class ListAction(ActionBase):
1093 """Class for lists of other actions."""
1094 def __init__(self, actionlist):
1095 if __debug__: logInstanceCreation(self, 'Action.ListAction')
1096 def list_of_actions(x):
1097 if isinstance(x, ActionBase):
1098 return x
1099 return Action(x)
1100 self.list = list(map(list_of_actions, actionlist))
1101 # our children will have had any varlist
1102 # applied; we don't need to do it again
1103 self.varlist = ()
1104 self.targets = '$TARGETS'
1105
1106 def genstring(self, target, source, env):
1107 return '\n'.join([a.genstring(target, source, env) for a in self.list])
1108
1109 def __str__(self):
1110 return '\n'.join(map(str, self.list))
1111
1112 def presub_lines(self, env):
1113 return SCons.Util.flatten_sequence(
1114 [a.presub_lines(env) for a in self.list])
1115
1116 def get_presig(self, target, source, env):
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
1123 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
1124 show=_null, execute=_null, chdir=_null, executor=None):
1125 if executor:
1126 target = executor.get_all_targets()
1127 source = executor.get_all_sources()
1128 for act in self.list:
1129 stat = act(target, source, env, exitstatfunc, presub,
1130 show, execute, chdir, executor)
1131 if stat:
1132 return stat
1133 return 0
1134
1135 def get_implicit_deps(self, target, source, env):
1136 result = []
1137 for act in self.list:
1138 result.extend(act.get_implicit_deps(target, source, env))
1139 return result
1140
1141 def get_varlist(self, target, source, env, executor=None):
1142 result = SCons.Util.OrderedDict()
1143 for act in self.list:
1144 for var in act.get_varlist(target, source, env, executor):
1145 result[var] = True
1146 return list(result.keys())
1147
1148 class ActionCaller(object):
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 """
1157 def __init__(self, parent, args, kw):
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 # "self.actfunc" is a function.
1166 contents = str(actfunc.func_code.co_code)
1167 except AttributeError:
1168 # "self.actfunc" is a callable object.
1169 try:
1170 contents = str(actfunc.__call__.im_func.func_code.co_code)
1171 except AttributeError:
1172 # No __call__() method, so it might be a builtin
1173 # or something like that. Do the best we can.
1174 contents = str(actfunc)
1175 contents = remove_set_lineno_codes(contents)
1176 return contents
1177
1178 def subst(self, s, target, source, env):
1179 # If s is a list, recursively apply subst()
1180 # to every element in the list
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 # Special-case hack: Let a custom function wrapped in an
1188 # ActionCaller get at the environment through which the action
1189 # was called by using this hard-coded value as a special return.
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
1196 def subst_args(self, target, source, env):
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
1210 def strfunction(self, target, source, env):
1211 args = self.subst_args(target, source, env)
1212 kw = self.subst_kw(target, source, env)
1213 return self.parent.strfunc(*args, **kw)
1214
1215 def __str__(self):
1216 return self.parent.strfunc(*self.args, **self.kw)
1217
1218 class ActionFactory(object):
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
1232 def __call__(self, *args, **kw):
1233 ac = ActionCaller(self, args, kw)
1234 action = Action(ac, strfunction=ac.strfunction)
1235 return action
1236
1237 # Local Variables:
1238 # tab-width:4
1239 # indent-tabs-mode:nil
1240 # End:
1241 # vim: set expandtab tabstop=4 shiftwidth=4:
OLDNEW
« no previous file with comments | « scons-2.0.1/RELEASE.txt ('k') | scons-2.0.1/engine/SCons/Builder.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698