~ubuntu-branches/ubuntu/trusty/blender/trusty-proposed

« back to all changes in this revision

Viewing changes to scons/scons-local/SCons/Script/Interactive.py

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2013-08-14 10:43:49 UTC
  • mfrom: (14.2.19 sid)
  • Revision ID: package-import@ubuntu.com-20130814104349-t1d5mtwkphp12dyj
Tags: 2.68a-3
* Upload to unstable
* debian/: python3.3 Depends simplified
  - debian/control: python3.3 Depends dropped
    for blender-data package
  - 0001-blender_thumbnailer.patch refreshed
* debian/control: libavcodec b-dep versioning dropped

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 The SCons Foundation
 
3
#
 
4
# Permission is hereby granted, free of charge, to any person obtaining
 
5
# a copy of this software and associated documentation files (the
 
6
# "Software"), to deal in the Software without restriction, including
 
7
# without limitation the rights to use, copy, modify, merge, publish,
 
8
# distribute, sublicense, and/or sell copies of the Software, and to
 
9
# permit persons to whom the Software is furnished to do so, subject to
 
10
# the following conditions:
 
11
#
 
12
# The above copyright notice and this permission notice shall be included
 
13
# in all copies or substantial portions of the Software.
 
14
#
 
15
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
 
16
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 
17
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
18
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
19
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
20
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
21
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
22
 
 
23
__revision__ = "src/engine/SCons/Script/Interactive.py  2013/03/03 09:48:35 garyo"
 
24
 
 
25
__doc__ = """
 
26
SCons interactive mode
 
27
"""
 
28
 
 
29
# TODO:
 
30
#
 
31
# This has the potential to grow into something with a really big life
 
32
# of its own, which might or might not be a good thing.  Nevertheless,
 
33
# here are some enhancements that will probably be requested some day
 
34
# and are worth keeping in mind (assuming this takes off):
 
35
 
36
# - A command to re-read / re-load the SConscript files.  This may
 
37
#   involve allowing people to specify command-line options (e.g. -f,
 
38
#   -I, --no-site-dir) that affect how the SConscript files are read.
 
39
#
 
40
# - Additional command-line options on the "build" command.
 
41
#
 
42
#   Of the supported options that seemed to make sense (after a quick
 
43
#   pass through the list), the ones that seemed likely enough to be
 
44
#   used are listed in the man page and have explicit test scripts.
 
45
#
 
46
#   These had code changed in Script/Main.py to support them, but didn't
 
47
#   seem likely to be used regularly, so had no test scripts added:
 
48
#
 
49
#       build --diskcheck=*
 
50
#       build --implicit-cache=*
 
51
#       build --implicit-deps-changed=*
 
52
#       build --implicit-deps-unchanged=*
 
53
#
 
54
#   These look like they should "just work" with no changes to the
 
55
#   existing code, but like those above, look unlikely to be used and
 
56
#   therefore had no test scripts added:
 
57
#
 
58
#       build --random
 
59
#
 
60
#   These I'm not sure about.  They might be useful for individual
 
61
#   "build" commands, and may even work, but they seem unlikely enough
 
62
#   that we'll wait until they're requested before spending any time on
 
63
#   writing test scripts for them, or investigating whether they work.
 
64
#
 
65
#       build -q [???  is there a useful analog to the exit status?]
 
66
#       build --duplicate=
 
67
#       build --profile=
 
68
#       build --max-drift=
 
69
#       build --warn=*
 
70
#       build --Y
 
71
#
 
72
# - Most of the SCons command-line options that the "build" command
 
73
#   supports should be settable as default options that apply to all
 
74
#   subsequent "build" commands.  Maybe a "set {option}" command that
 
75
#   maps to "SetOption('{option}')".
 
76
#
 
77
# - Need something in the 'help' command that prints the -h output.
 
78
#
 
79
# - A command to run the configure subsystem separately (must see how
 
80
#   this interacts with the new automake model).
 
81
#
 
82
# - Command-line completion of target names; maybe even of SCons options?
 
83
#   Completion is something that's supported by the Python cmd module,
 
84
#   so this should be doable without too much trouble.
 
85
#
 
86
 
 
87
import cmd
 
88
import copy
 
89
import os
 
90
import re
 
91
import shlex
 
92
import sys
 
93
 
 
94
try:
 
95
    import readline
 
96
except ImportError:
 
97
    pass
 
98
 
 
99
class SConsInteractiveCmd(cmd.Cmd):
 
100
    """\
 
101
    build [TARGETS]         Build the specified TARGETS and their dependencies.
 
102
                            'b' is a synonym.
 
103
    clean [TARGETS]         Clean (remove) the specified TARGETS and their
 
104
                            dependencies.  'c' is a synonym.
 
105
    exit                    Exit SCons interactive mode.
 
106
    help [COMMAND]          Prints help for the specified COMMAND.  'h' and
 
107
                            '?' are synonyms.
 
108
    shell [COMMANDLINE]     Execute COMMANDLINE in a subshell.  'sh' and '!'
 
109
                            are synonyms.
 
110
    version                 Prints SCons version information.
 
111
    """
 
112
 
 
113
    synonyms = {
 
114
        'b'     : 'build',
 
115
        'c'     : 'clean',
 
116
        'h'     : 'help',
 
117
        'scons' : 'build',
 
118
        'sh'    : 'shell',
 
119
    }
 
120
 
 
121
    def __init__(self, **kw):
 
122
        cmd.Cmd.__init__(self)
 
123
        for key, val in kw.items():
 
124
            setattr(self, key, val)
 
125
 
 
126
        if sys.platform == 'win32':
 
127
            self.shell_variable = 'COMSPEC'
 
128
        else:
 
129
            self.shell_variable = 'SHELL'
 
130
 
 
131
    def default(self, argv):
 
132
        print "*** Unknown command: %s" % argv[0]
 
133
 
 
134
    def onecmd(self, line):
 
135
        line = line.strip()
 
136
        if not line:
 
137
            print self.lastcmd
 
138
            return self.emptyline()
 
139
        self.lastcmd = line
 
140
        if line[0] == '!':
 
141
            line = 'shell ' + line[1:]
 
142
        elif line[0] == '?':
 
143
            line = 'help ' + line[1:]
 
144
        if os.sep == '\\':
 
145
            line = line.replace('\\', '\\\\')
 
146
        argv = shlex.split(line)
 
147
        argv[0] = self.synonyms.get(argv[0], argv[0])
 
148
        if not argv[0]:
 
149
            return self.default(line)
 
150
        else:
 
151
            try:
 
152
                func = getattr(self, 'do_' + argv[0])
 
153
            except AttributeError:
 
154
                return self.default(argv)
 
155
            return func(argv)
 
156
 
 
157
    def do_build(self, argv):
 
158
        """\
 
159
        build [TARGETS]         Build the specified TARGETS and their
 
160
                                dependencies.  'b' is a synonym.
 
161
        """
 
162
        import SCons.Node
 
163
        import SCons.SConsign
 
164
        import SCons.Script.Main
 
165
 
 
166
        options = copy.deepcopy(self.options)
 
167
 
 
168
        options, targets = self.parser.parse_args(argv[1:], values=options)
 
169
 
 
170
        SCons.Script.COMMAND_LINE_TARGETS = targets
 
171
 
 
172
        if targets:
 
173
            SCons.Script.BUILD_TARGETS = targets
 
174
        else:
 
175
            # If the user didn't specify any targets on the command line,
 
176
            # use the list of default targets.
 
177
            SCons.Script.BUILD_TARGETS = SCons.Script._build_plus_default
 
178
 
 
179
        nodes = SCons.Script.Main._build_targets(self.fs,
 
180
                                                 options,
 
181
                                                 targets,
 
182
                                                 self.target_top)
 
183
 
 
184
        if not nodes:
 
185
            return
 
186
 
 
187
        # Call each of the Node's alter_targets() methods, which may
 
188
        # provide additional targets that ended up as part of the build
 
189
        # (the canonical example being a VariantDir() when we're building
 
190
        # from a source directory) and which we therefore need their
 
191
        # state cleared, too.
 
192
        x = []
 
193
        for n in nodes:
 
194
            x.extend(n.alter_targets()[0])
 
195
        nodes.extend(x)
 
196
 
 
197
        # Clean up so that we can perform the next build correctly.
 
198
        #
 
199
        # We do this by walking over all the children of the targets,
 
200
        # and clearing their state.
 
201
        #
 
202
        # We currently have to re-scan each node to find their
 
203
        # children, because built nodes have already been partially
 
204
        # cleared and don't remember their children.  (In scons
 
205
        # 0.96.1 and earlier, this wasn't the case, and we didn't
 
206
        # have to re-scan the nodes.)
 
207
        #
 
208
        # Because we have to re-scan each node, we can't clear the
 
209
        # nodes as we walk over them, because we may end up rescanning
 
210
        # a cleared node as we scan a later node.  Therefore, only
 
211
        # store the list of nodes that need to be cleared as we walk
 
212
        # the tree, and clear them in a separate pass.
 
213
        #
 
214
        # XXX: Someone more familiar with the inner workings of scons
 
215
        # may be able to point out a more efficient way to do this.
 
216
 
 
217
        SCons.Script.Main.progress_display("scons: Clearing cached node information ...")
 
218
 
 
219
        seen_nodes = {}
 
220
 
 
221
        def get_unseen_children(node, parent, seen_nodes=seen_nodes):
 
222
            def is_unseen(node, seen_nodes=seen_nodes):
 
223
                return node not in seen_nodes
 
224
            return list(filter(is_unseen, node.children(scan=1)))
 
225
 
 
226
        def add_to_seen_nodes(node, parent, seen_nodes=seen_nodes):
 
227
            seen_nodes[node] = 1
 
228
 
 
229
            # If this file is in a VariantDir and has a
 
230
            # corresponding source file in the source tree, remember the
 
231
            # node in the source tree, too.  This is needed in
 
232
            # particular to clear cached implicit dependencies on the
 
233
            # source file, since the scanner will scan it if the
 
234
            # VariantDir was created with duplicate=0.
 
235
            try:
 
236
                rfile_method = node.rfile
 
237
            except AttributeError:
 
238
                return
 
239
            else:
 
240
                rfile = rfile_method()
 
241
            if rfile != node:
 
242
                seen_nodes[rfile] = 1
 
243
 
 
244
        for node in nodes:
 
245
            walker = SCons.Node.Walker(node,
 
246
                                        kids_func=get_unseen_children,
 
247
                                        eval_func=add_to_seen_nodes)
 
248
            n = walker.get_next()
 
249
            while n:
 
250
                n = walker.get_next()
 
251
 
 
252
        for node in seen_nodes.keys():
 
253
            # Call node.clear() to clear most of the state
 
254
            node.clear()
 
255
            # node.clear() doesn't reset node.state, so call
 
256
            # node.set_state() to reset it manually
 
257
            node.set_state(SCons.Node.no_state)
 
258
            node.implicit = None
 
259
 
 
260
            # Debug:  Uncomment to verify that all Taskmaster reference
 
261
            # counts have been reset to zero.
 
262
            #if node.ref_count != 0:
 
263
            #    from SCons.Debug import Trace
 
264
            #    Trace('node %s, ref_count %s !!!\n' % (node, node.ref_count))
 
265
 
 
266
        SCons.SConsign.Reset()
 
267
        SCons.Script.Main.progress_display("scons: done clearing node information.")
 
268
 
 
269
    def do_clean(self, argv):
 
270
        """\
 
271
        clean [TARGETS]         Clean (remove) the specified TARGETS
 
272
                                and their dependencies.  'c' is a synonym.
 
273
        """
 
274
        return self.do_build(['build', '--clean'] + argv[1:])
 
275
 
 
276
    def do_EOF(self, argv):
 
277
        print
 
278
        self.do_exit(argv)
 
279
 
 
280
    def _do_one_help(self, arg):
 
281
        try:
 
282
            # If help_<arg>() exists, then call it.
 
283
            func = getattr(self, 'help_' + arg)
 
284
        except AttributeError:
 
285
            try:
 
286
                func = getattr(self, 'do_' + arg)
 
287
            except AttributeError:
 
288
                doc = None
 
289
            else:
 
290
                doc = self._doc_to_help(func)
 
291
            if doc:
 
292
                sys.stdout.write(doc + '\n')
 
293
                sys.stdout.flush()
 
294
        else:
 
295
            doc = self.strip_initial_spaces(func())
 
296
            if doc:
 
297
                sys.stdout.write(doc + '\n')
 
298
                sys.stdout.flush()
 
299
 
 
300
    def _doc_to_help(self, obj):
 
301
        doc = obj.__doc__
 
302
        if doc is None:
 
303
            return ''
 
304
        return self._strip_initial_spaces(doc)
 
305
 
 
306
    def _strip_initial_spaces(self, s):
 
307
        #lines = s.split('\n')
 
308
        lines = s.split('\n')
 
309
        spaces = re.match(' *', lines[0]).group(0)
 
310
        #def strip_spaces(l):
 
311
        #    if l.startswith(spaces):
 
312
        #        l = l[len(spaces):]
 
313
        #    return l
 
314
        #return '\n'.join([ strip_spaces(l) for l in lines ])
 
315
        def strip_spaces(l, spaces=spaces):
 
316
            if l[:len(spaces)] == spaces:
 
317
                l = l[len(spaces):]
 
318
            return l
 
319
        lines = list(map(strip_spaces, lines))
 
320
        return '\n'.join(lines)
 
321
 
 
322
    def do_exit(self, argv):
 
323
        """\
 
324
        exit                    Exit SCons interactive mode.
 
325
        """
 
326
        sys.exit(0)
 
327
 
 
328
    def do_help(self, argv):
 
329
        """\
 
330
        help [COMMAND]          Prints help for the specified COMMAND.  'h'
 
331
                                and '?' are synonyms.
 
332
        """
 
333
        if argv[1:]:
 
334
            for arg in argv[1:]:
 
335
                if self._do_one_help(arg):
 
336
                    break
 
337
        else:
 
338
            # If bare 'help' is called, print this class's doc
 
339
            # string (if it has one).
 
340
            doc = self._doc_to_help(self.__class__)
 
341
            if doc:
 
342
                sys.stdout.write(doc + '\n')
 
343
                sys.stdout.flush()
 
344
 
 
345
    def do_shell(self, argv):
 
346
        """\
 
347
        shell [COMMANDLINE]     Execute COMMANDLINE in a subshell.  'sh' and
 
348
                                '!' are synonyms.
 
349
        """
 
350
        import subprocess
 
351
        argv = argv[1:]
 
352
        if not argv:
 
353
            argv = os.environ[self.shell_variable]
 
354
        try:
 
355
            # Per "[Python-Dev] subprocess insufficiently platform-independent?"
 
356
            # http://mail.python.org/pipermail/python-dev/2008-August/081979.html "+
 
357
            # Doing the right thing with an argument list currently
 
358
            # requires different shell= values on Windows and Linux.
 
359
            p = subprocess.Popen(argv, shell=(sys.platform=='win32'))
 
360
        except EnvironmentError, e:
 
361
            sys.stderr.write('scons: %s: %s\n' % (argv[0], e.strerror))
 
362
        else:
 
363
            p.wait()
 
364
 
 
365
    def do_version(self, argv):
 
366
        """\
 
367
        version                 Prints SCons version information.
 
368
        """
 
369
        sys.stdout.write(self.parser.version + '\n')
 
370
 
 
371
def interact(fs, parser, options, targets, target_top):
 
372
    c = SConsInteractiveCmd(prompt = 'scons>>> ',
 
373
                            fs = fs,
 
374
                            parser = parser,
 
375
                            options = options,
 
376
                            targets = targets,
 
377
                            target_top = target_top)
 
378
    c.cmdloop()
 
379
 
 
380
# Local Variables:
 
381
# tab-width:4
 
382
# indent-tabs-mode:nil
 
383
# End:
 
384
# vim: set expandtab tabstop=4 shiftwidth=4: