summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/closure-library/closure/bin/build/depstree.py
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/closure-library/closure/bin/build/depstree.py')
-rwxr-xr-xdom/canvas/test/webgl-conf/checkout/closure-library/closure/bin/build/depstree.py189
1 files changed, 189 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/closure-library/closure/bin/build/depstree.py b/dom/canvas/test/webgl-conf/checkout/closure-library/closure/bin/build/depstree.py
new file mode 100755
index 0000000000..f288dd3aa6
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/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