Interactive.py
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:13k
源码类别:

外挂编程

开发平台:

Windows_Unix

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