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