Index: chrome/third_party/chromevox/third_party/closure-library/closure/bin/build/depstree.py |
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/bin/build/depstree.py b/chrome/third_party/chromevox/third_party/closure-library/closure/bin/build/depstree.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f288dd3aa616a9a69390f5ac6dc4411a3a8a419b |
--- /dev/null |
+++ b/chrome/third_party/chromevox/third_party/closure-library/closure/bin/build/depstree.py |
@@ -0,0 +1,189 @@ |
+# Copyright 2009 The Closure Library Authors. All Rights Reserved. |
+# |
+# Licensed under the Apache License, Version 2.0 (the "License"); |
+# you may not use this file except in compliance with the License. |
+# You may obtain a copy of the License at |
+# |
+# http://www.apache.org/licenses/LICENSE-2.0 |
+# |
+# Unless required by applicable law or agreed to in writing, software |
+# distributed under the License is distributed on an "AS-IS" BASIS, |
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+# See the License for the specific language governing permissions and |
+# limitations under the License. |
+ |
+ |
+"""Class to represent a full Closure Library dependency tree. |
+ |
+Offers a queryable tree of dependencies of a given set of sources. The tree |
+will also do logical validation to prevent duplicate provides and circular |
+dependencies. |
+""" |
+ |
+__author__ = 'nnaze@google.com (Nathan Naze)' |
+ |
+ |
+class DepsTree(object): |
+ """Represents the set of dependencies between source files.""" |
+ |
+ def __init__(self, sources): |
+ """Initializes the tree with a set of sources. |
+ |
+ Args: |
+ sources: A set of JavaScript sources. |
+ |
+ Raises: |
+ MultipleProvideError: A namespace is provided by muplitple sources. |
+ NamespaceNotFoundError: A namespace is required but never provided. |
+ """ |
+ |
+ self._sources = sources |
+ self._provides_map = dict() |
+ |
+ # Ensure nothing was provided twice. |
+ for source in sources: |
+ for provide in source.provides: |
+ if provide in self._provides_map: |
+ raise MultipleProvideError( |
+ provide, [self._provides_map[provide], source]) |
+ |
+ self._provides_map[provide] = source |
+ |
+ # Check that all required namespaces are provided. |
+ for source in sources: |
+ for require in source.requires: |
+ if require not in self._provides_map: |
+ raise NamespaceNotFoundError(require, source) |
+ |
+ def GetDependencies(self, required_namespaces): |
+ """Get source dependencies, in order, for the given namespaces. |
+ |
+ Args: |
+ required_namespaces: A string (for one) or list (for one or more) of |
+ namespaces. |
+ |
+ Returns: |
+ A list of source objects that provide those namespaces and all |
+ requirements, in dependency order. |
+ |
+ Raises: |
+ NamespaceNotFoundError: A namespace is requested but doesn't exist. |
+ CircularDependencyError: A cycle is detected in the dependency tree. |
+ """ |
+ if isinstance(required_namespaces, str): |
+ required_namespaces = [required_namespaces] |
+ |
+ deps_sources = [] |
+ |
+ for namespace in required_namespaces: |
+ for source in DepsTree._ResolveDependencies( |
+ namespace, [], self._provides_map, []): |
+ if source not in deps_sources: |
+ deps_sources.append(source) |
+ |
+ return deps_sources |
+ |
+ @staticmethod |
+ def _ResolveDependencies(required_namespace, deps_list, provides_map, |
+ traversal_path): |
+ """Resolve dependencies for Closure source files. |
+ |
+ Follows the dependency tree down and builds a list of sources in dependency |
+ order. This function will recursively call itself to fill all dependencies |
+ below the requested namespaces, and then append its sources at the end of |
+ the list. |
+ |
+ Args: |
+ required_namespace: String of required namespace. |
+ deps_list: List of sources in dependency order. This function will append |
+ the required source once all of its dependencies are satisfied. |
+ provides_map: Map from namespace to source that provides it. |
+ traversal_path: List of namespaces of our path from the root down the |
+ dependency/recursion tree. Used to identify cyclical dependencies. |
+ This is a list used as a stack -- when the function is entered, the |
+ current namespace is pushed and popped right before returning. |
+ Each recursive call will check that the current namespace does not |
+ appear in the list, throwing a CircularDependencyError if it does. |
+ |
+ Returns: |
+ The given deps_list object filled with sources in dependency order. |
+ |
+ Raises: |
+ NamespaceNotFoundError: A namespace is requested but doesn't exist. |
+ CircularDependencyError: A cycle is detected in the dependency tree. |
+ """ |
+ |
+ source = provides_map.get(required_namespace) |
+ if not source: |
+ raise NamespaceNotFoundError(required_namespace) |
+ |
+ if required_namespace in traversal_path: |
+ traversal_path.append(required_namespace) # do this *after* the test |
+ |
+ # This must be a cycle. |
+ raise CircularDependencyError(traversal_path) |
+ |
+ # If we don't have the source yet, we'll have to visit this namespace and |
+ # add the required dependencies to deps_list. |
+ if source not in deps_list: |
+ traversal_path.append(required_namespace) |
+ |
+ for require in source.requires: |
+ |
+ # Append all other dependencies before we append our own. |
+ DepsTree._ResolveDependencies(require, deps_list, provides_map, |
+ traversal_path) |
+ deps_list.append(source) |
+ |
+ traversal_path.pop() |
+ |
+ return deps_list |
+ |
+ |
+class BaseDepsTreeError(Exception): |
+ """Base DepsTree error.""" |
+ |
+ def __init__(self): |
+ Exception.__init__(self) |
+ |
+ |
+class CircularDependencyError(BaseDepsTreeError): |
+ """Raised when a dependency cycle is encountered.""" |
+ |
+ def __init__(self, dependency_list): |
+ BaseDepsTreeError.__init__(self) |
+ self._dependency_list = dependency_list |
+ |
+ def __str__(self): |
+ return ('Encountered circular dependency:\n%s\n' % |
+ '\n'.join(self._dependency_list)) |
+ |
+ |
+class MultipleProvideError(BaseDepsTreeError): |
+ """Raised when a namespace is provided more than once.""" |
+ |
+ def __init__(self, namespace, sources): |
+ BaseDepsTreeError.__init__(self) |
+ self._namespace = namespace |
+ self._sources = sources |
+ |
+ def __str__(self): |
+ source_strs = map(str, self._sources) |
+ |
+ return ('Namespace "%s" provided more than once in sources:\n%s\n' % |
+ (self._namespace, '\n'.join(source_strs))) |
+ |
+ |
+class NamespaceNotFoundError(BaseDepsTreeError): |
+ """Raised when a namespace is requested but not provided.""" |
+ |
+ def __init__(self, namespace, source=None): |
+ BaseDepsTreeError.__init__(self) |
+ self._namespace = namespace |
+ self._source = source |
+ |
+ def __str__(self): |
+ msg = 'Namespace "%s" never provided.' % self._namespace |
+ if self._source: |
+ msg += ' Required in %s' % self._source |
+ return msg |