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

外挂编程

开发平台:

Windows_Unix

  1. """SCons.Scanner
  2. The Scanner package for the SCons software construction utility.
  3. """
  4. #
  5. # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
  6. #
  7. # Permission is hereby granted, free of charge, to any person obtaining
  8. # a copy of this software and associated documentation files (the
  9. # "Software"), to deal in the Software without restriction, including
  10. # without limitation the rights to use, copy, modify, merge, publish,
  11. # distribute, sublicense, and/or sell copies of the Software, and to
  12. # permit persons to whom the Software is furnished to do so, subject to
  13. # the following conditions:
  14. #
  15. # The above copyright notice and this permission notice shall be included
  16. # in all copies or substantial portions of the Software.
  17. #
  18. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
  19. # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  20. # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  22. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  23. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  24. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25. #
  26. __revision__ = "src/engine/SCons/Scanner/__init__.py 3057 2008/06/09 22:21:00 knight"
  27. import re
  28. import string
  29. import SCons.Node.FS
  30. import SCons.Util
  31. class _Null:
  32.     pass
  33. # This is used instead of None as a default argument value so None can be
  34. # used as an actual argument value.
  35. _null = _Null
  36. def Scanner(function, *args, **kw):
  37.     """
  38.     Public interface factory function for creating different types
  39.     of Scanners based on the different types of "functions" that may
  40.     be supplied.
  41.     TODO:  Deprecate this some day.  We've moved the functionality
  42.     inside the Base class and really don't need this factory function
  43.     any more.  It was, however, used by some of our Tool modules, so
  44.     the call probably ended up in various people's custom modules
  45.     patterned on SCons code.
  46.     """
  47.     if SCons.Util.is_Dict(function):
  48.         return apply(Selector, (function,) + args, kw)
  49.     else:
  50.         return apply(Base, (function,) + args, kw)
  51. class FindPathDirs:
  52.     """A class to bind a specific *PATH variable name to a function that
  53.     will return all of the *path directories."""
  54.     def __init__(self, variable):
  55.         self.variable = variable
  56.     def __call__(self, env, dir=None, target=None, source=None, argument=None):
  57.         import SCons.PathList
  58.         try:
  59.             path = env[self.variable]
  60.         except KeyError:
  61.             return ()
  62.         dir = dir or env.fs._cwd
  63.         path = SCons.PathList.PathList(path).subst_path(env, target, source)
  64.         return tuple(dir.Rfindalldirs(path))
  65. class Base:
  66.     """
  67.     The base class for dependency scanners.  This implements
  68.     straightforward, single-pass scanning of a single file.
  69.     """
  70.     def __init__(self,
  71.                  function,
  72.                  name = "NONE",
  73.                  argument = _null,
  74.                  skeys = _null,
  75.                  path_function = None,
  76.                  node_class = SCons.Node.FS.Entry,
  77.                  node_factory = None,
  78.                  scan_check = None,
  79.                  recursive = None):
  80.         """
  81.         Construct a new scanner object given a scanner function.
  82.         'function' - a scanner function taking two or three
  83.         arguments and returning a list of strings.
  84.         'name' - a name for identifying this scanner object.
  85.         'argument' - an optional argument that, if specified, will be
  86.         passed to both the scanner function and the path_function.
  87.         'skeys' - an optional list argument that can be used to determine
  88.         which scanner should be used for a given Node. In the case of File
  89.         nodes, for example, the 'skeys' would be file suffixes.
  90.         'path_function' - a function that takes four or five arguments
  91.         (a construction environment, Node for the directory containing
  92.         the SConscript file that defined the primary target, list of
  93.         target nodes, list of source nodes, and optional argument for
  94.         this instance) and returns a tuple of the directories that can
  95.         be searched for implicit dependency files.  May also return a
  96.         callable() which is called with no args and returns the tuple
  97.         (supporting Bindable class).
  98.         'node_class' - the class of Nodes which this scan will return.
  99.         If node_class is None, then this scanner will not enforce any
  100.         Node conversion and will return the raw results from the
  101.         underlying scanner function.
  102.         'node_factory' - the factory function to be called to translate
  103.         the raw results returned by the scanner function into the
  104.         expected node_class objects.
  105.         'scan_check' - a function to be called to first check whether
  106.         this node really needs to be scanned.
  107.         'recursive' - specifies that this scanner should be invoked
  108.         recursively on all of the implicit dependencies it returns
  109.         (the canonical example being #include lines in C source files).
  110.         May be a callable, which will be called to filter the list
  111.         of nodes found to select a subset for recursive scanning
  112.         (the canonical example being only recursively scanning
  113.         subdirectories within a directory).
  114.         The scanner function's first argument will be a Node that should
  115.         be scanned for dependencies, the second argument will be an
  116.         Environment object, the third argument will be the tuple of paths
  117.         returned by the path_function, and the fourth argument will be
  118.         the value passed into 'argument', and the returned list should
  119.         contain the Nodes for all the direct dependencies of the file.
  120.         Examples:
  121.         s = Scanner(my_scanner_function)
  122.         s = Scanner(function = my_scanner_function)
  123.         s = Scanner(function = my_scanner_function, argument = 'foo')
  124.         """
  125.         # Note: this class could easily work with scanner functions that take
  126.         # something other than a filename as an argument (e.g. a database
  127.         # node) and a dependencies list that aren't file names. All that
  128.         # would need to be changed is the documentation.
  129.         self.function = function
  130.         self.path_function = path_function
  131.         self.name = name
  132.         self.argument = argument
  133.         if skeys is _null:
  134.             if SCons.Util.is_Dict(function):
  135.                 skeys = function.keys()
  136.             else:
  137.                 skeys = []
  138.         self.skeys = skeys
  139.         self.node_class = node_class
  140.         self.node_factory = node_factory
  141.         self.scan_check = scan_check
  142.         if callable(recursive):
  143.             self.recurse_nodes = recursive
  144.         elif recursive:
  145.             self.recurse_nodes = self._recurse_all_nodes
  146.         else:
  147.             self.recurse_nodes = self._recurse_no_nodes
  148.     def path(self, env, dir=None, target=None, source=None):
  149.         if not self.path_function:
  150.             return ()
  151.         if not self.argument is _null:
  152.             return self.path_function(env, dir, target, source, self.argument)
  153.         else:
  154.             return self.path_function(env, dir, target, source)
  155.     def __call__(self, node, env, path = ()):
  156.         """
  157.         This method scans a single object. 'node' is the node
  158.         that will be passed to the scanner function, and 'env' is the
  159.         environment that will be passed to the scanner function. A list of
  160.         direct dependency nodes for the specified node will be returned.
  161.         """
  162.         if self.scan_check and not self.scan_check(node, env):
  163.             return []
  164.         self = self.select(node)
  165.         if not self.argument is _null:
  166.             list = self.function(node, env, path, self.argument)
  167.         else:
  168.             list = self.function(node, env, path)
  169.         kw = {}
  170.         if hasattr(node, 'dir'):
  171.             kw['directory'] = node.dir
  172.         node_factory = env.get_factory(self.node_factory)
  173.         nodes = []
  174.         for l in list:
  175.             if self.node_class and not isinstance(l, self.node_class):
  176.                 l = apply(node_factory, (l,), kw)
  177.             nodes.append(l)
  178.         return nodes
  179.     def __cmp__(self, other):
  180.         try:
  181.             return cmp(self.__dict__, other.__dict__)
  182.         except AttributeError:
  183.             # other probably doesn't have a __dict__
  184.             return cmp(self.__dict__, other)
  185.     def __hash__(self):
  186.         return id(self)
  187.     def __str__(self):
  188.         return self.name
  189.     def add_skey(self, skey):
  190.         """Add a skey to the list of skeys"""
  191.         self.skeys.append(skey)
  192.     def get_skeys(self, env=None):
  193.         if env and SCons.Util.is_String(self.skeys):
  194.             return env.subst_list(self.skeys)[0]
  195.         return self.skeys
  196.     def select(self, node):
  197.         if SCons.Util.is_Dict(self.function):
  198.             key = node.scanner_key()
  199.             try:
  200.                 return self.function[key]
  201.             except KeyError:
  202.                 return None
  203.         else:
  204.             return self
  205.     def _recurse_all_nodes(self, nodes):
  206.         return nodes
  207.     def _recurse_no_nodes(self, nodes):
  208.         return []
  209.     recurse_nodes = _recurse_no_nodes
  210.     def add_scanner(self, skey, scanner):
  211.         self.function[skey] = scanner
  212.         self.add_skey(skey)
  213. class Selector(Base):
  214.     """
  215.     A class for selecting a more specific scanner based on the
  216.     scanner_key() (suffix) for a specific Node.
  217.     TODO:  This functionality has been moved into the inner workings of
  218.     the Base class, and this class will be deprecated at some point.
  219.     (It was never exposed directly as part of the public interface,
  220.     although it is used by the Scanner() factory function that was
  221.     used by various Tool modules and therefore was likely a template
  222.     for custom modules that may be out there.)
  223.     """
  224.     def __init__(self, dict, *args, **kw):
  225.         apply(Base.__init__, (self, None,)+args, kw)
  226.         self.dict = dict
  227.         self.skeys = dict.keys()
  228.     def __call__(self, node, env, path = ()):
  229.         return self.select(node)(node, env, path)
  230.     def select(self, node):
  231.         try:
  232.             return self.dict[node.scanner_key()]
  233.         except KeyError:
  234.             return None
  235.     def add_scanner(self, skey, scanner):
  236.         self.dict[skey] = scanner
  237.         self.add_skey(skey)
  238. class Current(Base):
  239.     """
  240.     A class for scanning files that are source files (have no builder)
  241.     or are derived files and are current (which implies that they exist,
  242.     either locally or in a repository).
  243.     """
  244.     def __init__(self, *args, **kw):
  245.         def current_check(node, env):
  246.             return not node.has_builder() or node.is_up_to_date()
  247.         kw['scan_check'] = current_check
  248.         apply(Base.__init__, (self,) + args, kw)
  249. class Classic(Current):
  250.     """
  251.     A Scanner subclass to contain the common logic for classic CPP-style
  252.     include scanning, but which can be customized to use different
  253.     regular expressions to find the includes.
  254.     Note that in order for this to work "out of the box" (without
  255.     overriding the find_include() and sort_key() methods), the regular
  256.     expression passed to the constructor must return the name of the
  257.     include file in group 0.
  258.     """
  259.     def __init__(self, name, suffixes, path_variable, regex, *args, **kw):
  260.         self.cre = re.compile(regex, re.M)
  261.         def _scan(node, env, path=(), self=self):
  262.             node = node.rfile()
  263.             if not node.exists():
  264.                 return []
  265.             return self.scan(node, path)
  266.         kw['function'] = _scan
  267.         kw['path_function'] = FindPathDirs(path_variable)
  268.         kw['recursive'] = 1
  269.         kw['skeys'] = suffixes
  270.         kw['name'] = name
  271.         apply(Current.__init__, (self,) + args, kw)
  272.     def find_include(self, include, source_dir, path):
  273.         n = SCons.Node.FS.find_file(include, (source_dir,) + tuple(path))
  274.         return n, include
  275.     def sort_key(self, include):
  276.         return SCons.Node.FS._my_normcase(include)
  277.     def find_include_names(self, node):
  278.         return self.cre.findall(node.get_contents())
  279.     def scan(self, node, path=()):
  280.         # cache the includes list in node so we only scan it once:
  281.         if node.includes != None:
  282.             includes = node.includes
  283.         else:
  284.             includes = self.find_include_names (node)
  285.             node.includes = includes
  286.         # This is a hand-coded DSU (decorate-sort-undecorate, or
  287.         # Schwartzian transform) pattern.  The sort key is the raw name
  288.         # of the file as specifed on the #include line (including the
  289.         # " or <, since that may affect what file is found), which lets
  290.         # us keep the sort order constant regardless of whether the file
  291.         # is actually found in a Repository or locally.
  292.         nodes = []
  293.         source_dir = node.get_dir()
  294.         if callable(path):
  295.             path = path()
  296.         for include in includes:
  297.             n, i = self.find_include(include, source_dir, path)
  298.             if n is None:
  299.                 SCons.Warnings.warn(SCons.Warnings.DependencyWarning,
  300.                                     "No dependency generated for file: %s (included from: %s) -- file not found" % (i, node))
  301.             else:
  302.                 sortkey = self.sort_key(include)
  303.                 nodes.append((sortkey, n))
  304.         nodes.sort()
  305.         nodes = map(lambda pair: pair[1], nodes)
  306.         return nodes
  307. class ClassicCPP(Classic):
  308.     """
  309.     A Classic Scanner subclass which takes into account the type of
  310.     bracketing used to include the file, and uses classic CPP rules
  311.     for searching for the files based on the bracketing.
  312.     Note that in order for this to work, the regular expression passed
  313.     to the constructor must return the leading bracket in group 0, and
  314.     the contained filename in group 1.
  315.     """
  316.     def find_include(self, include, source_dir, path):
  317.         if include[0] == '"':
  318.             paths = (source_dir,) + tuple(path)
  319.         else:
  320.             paths = tuple(path) + (source_dir,)
  321.         n = SCons.Node.FS.find_file(include[1], paths)
  322.         return n, include[1]
  323.     def sort_key(self, include):
  324.         return SCons.Node.FS._my_normcase(string.join(include))