PageRenderTime 79ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/third_party/scons/scons-local/SCons/Script/Interactive.py

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