diff --git a/BUILD b/BUILD index 5449bf8..7e89545 100644 --- a/BUILD +++ b/BUILD @@ -156,6 +156,15 @@ py_test( python_version = python_version, ) +py_test( + name = "labeltest", + srcs = ["tests/labeltest.py"], + deps = [":pomgen_lib"], + imports = ["src"], + size = "small", + python_version = python_version, +) + py_test( name = "libaggregatortest", srcs = ["tests/libaggregatortest.py"], @@ -230,7 +239,6 @@ py_test( py_test( name = "versiontest", - srcs = ["tests/versiontest.py"], deps = [":pomgen_lib"], imports = ["src"], diff --git a/misc/extdeps_pomgen.py b/misc/extdeps_pomgen.py index 71394a0..f7a41a0 100755 --- a/misc/extdeps_pomgen.py +++ b/misc/extdeps_pomgen.py @@ -53,7 +53,6 @@ class ThirdPartyDepsPomGen(pom.DynamicPomGen): def __init__(self, workspace, artifact_def, dependencies, pom_template): super(ThirdPartyDepsPomGen, self).__init__(workspace, artifact_def, - dependency=None, pom_template=pom_template) self.dependencies = dependencies diff --git a/src/common/label.py b/src/common/label.py new file mode 100644 index 0000000..ea4f981 --- /dev/null +++ b/src/common/label.py @@ -0,0 +1,297 @@ +""" +Copyright (c) 2025, salesforce.com, inc. +All rights reserved. +SPDX-License-Identifier: BSD-3-Clause +For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause + +This module has abstractions for Bazel labels. +""" + + +import os + + +_BUILD_FILE_NAMES = ("BUILD", "BUILD.bazel") + + +def for_package(root_dir, package_path): + """ + Returns a label instance for the Bazel package at the given relative path, + rooted at the given root_dir. Returns None if no build file exists at that + location. + """ + for fname in _BUILD_FILE_NAMES: + rel_path = os.path.join(package_path, fname) + abs_path = os.path.join(root_dir, rel_path) + if os.path.isfile(abs_path): + return Label(rel_path) + return None + + +def find_packages(root_dir, package_path=""): + """ + Walks the directory tree, starting at root dir, and returns a list of + Label instances for all Bazel packages that exist under the given root_dir. + + If package_path is specified, the search starts at that location. + """ + labels = [] + for path, dirs, files in os.walk(os.path.join(root_dir, package_path)): + for fname in files: + if fname in _BUILD_FILE_NAMES: + rel_path = os.path.join(os.path.relpath(path, root_dir), fname) + if rel_path.startswith("./"): + # build file at root dir, remove "./" so that the package + # of the Label is empty + rel_path = rel_path[2:] + labels.append(Label(rel_path)) + return labels + + +class Label(object): + """ + Represents a Bazel Label. + """ + + def __init__(self, name): + """ + Initializes a Label with the given name, a string. name represents + a path-like structure with an optional target [path:target]. + + If the last path segment is a build file (/BUILD or /BUILD.bazel), + it is removed from the path. + + """ + assert name is not None + name = name.strip() + if name.endswith("/"): + name = name[:-1] + fname = os.path.basename(name) + if fname in ("BUILD", "BUILD.bazel"): + name = os.path.dirname(name) + self._build_file_name = fname + else: + self._build_file_name = None + self._name = name + + @property + def name(self): + """ + The name this instance was initialized with. + """ + return self._name + + @property + def package(self): + """ + The Bazel Package of this label. + For example, for "//a/b/c:foo", return "//a/b/c" + """ + i = self._name.find(":") + if i == -1: + if self._name.endswith("..."): + return self._name[:-3] + return self._name + return self._name[0:i] + + @property + def package_path(self): + """ + Returns the Package of this label as a valid relative path. + """ + p = self.package + if p.startswith("//"): + p = p[2:] + if p.endswith("/"): + p = p[:-1] + return p + + @property + def target(self): + """ + The Bazel Target of this label. + For example, for "//a/b/c:foo", return "foo" + """ + i = self._name.find(":") + if i == -1: + return os.path.basename(self._name) + return self._name[i+1:] + + @property + def target_name(self): + """ + An alias for the "target" property. + """ + return self.target + + @property + def is_default_target(self): + """ + Returns True if this label refers to the default target in the package, + ie the target that has the same name as the directory the BUILD file + lives in. + """ + package = self.package + target = self.target + if package is None: + return False + if target is None: + return True + return os.path.basename(package) == target + + @property + def is_root_target(self): + """ + Returns True if this label's target is defined in the root BUILD + file, ie if the label has this pattern "//:" + """ + return "//:" in self._name + + @property + def fqname(self): + """ + The name of this label with a default repo prefix, iff the + initial name did not specify such a prefix and this is not a src ref. + """ + if self.is_source_ref: + return self._name + if self.has_repo_prefix: + return self._name + else: + # the default prefix we use for names without repo prefix: + # if name is foo, fqname will be @maven//:foo + # "maven" doesn't really make sense to use anymore, but it isn't + # clear what to use instead - probably defaulting the repo doesn't + # make sense + default_repo = "maven" + return self.prefix_with(default_repo).name + + @property + def simple_name(self): + """ + The name of this label without the remote repo prefix. + If this label does not have a remote repo prefix, returns just + its name. + """ + if self.is_source_ref: + return self._name + if self.has_repo_prefix: + prefix = self.repo_prefix + return self._name[len(prefix)+4:] # 4 = additional chars @//: + else: + return self._name + + @property + def is_private(self): + """ + Returns True if this label refers to a private target (starts with ":") + """ + return self._name.startswith(":") + + @property + def has_repo_prefix(self): + """ + Whether this label name has a remote repo prefix. + """ + return self.repo_prefix is not None + + @property + def repo_prefix(self): + """ + The remote repo prefix, or workspace name of this label; None if this + label name doesn't have one. + + For example, for a label like "@pomgen//maven", returns "pomgen". + """ + if self._name.startswith("@"): + i = self._name.find("//") + if i != -1: + return self._name[1:i] + return None + + @property + def is_source_ref(self): + """ + True if this name is a reference to source in the same repository. + """ + return self._name.startswith("//") + + @property + def has_file_extension(self): + ext = os.path.splitext(self._name)[1] + return ext in (".jar", ".proto", ".h", ".c", ".cc", ".cpp", ".m", ".py", ".pyc", ".java", ".go") + + @property + def has_extension_suffix(self): + return self._name.endswith("_extension") + + @property + def is_sources_artifact(self): + return "_jar_sources" in self._name + + @property + def build_file_path(self): + """ + The path to the build file of this package, if this Label instance was + created with a path that pointed to a build file. + None if this Label instance does not know about the build file it was + created for. + """ + if self._build_file_name is None: + return None + return os.path.join(self.package_path, self._build_file_name) + + def prefix_with(self, repo_prefix): + """ + Returns a new Label instance that is qualified with the + specified repo_prefix. This method asserts that this instance is not + already fully qualified. + """ + assert not self.has_repo_prefix, "This label already has a repo prefix: %s" % self._name + return Label("@%s//:%s" % (repo_prefix, self._name)) + + def with_target(self, target): + """ + Returns a new Label instance that has the specified target. + """ + return Label("%s:%s" % (self.package, target)) + + def as_wildcard_label(self, wildcard): + if wildcard == "...": + return Label("%s/%s" % (self.package, wildcard)) + else: + return Label("%s:%s" % (self.package, wildcard)) + + def as_alternate_default_target_syntax(self): + """ + Labels may omit the target if they refer to the default target, or they + may not omit it. If this Label instance refers to the default target, + this method returns the other syntax. + So: + Given this Label instance is: //a/b/c, returns //a/b/c:c + Or, given this Label instance is //a/b/c:c, returns //a/b/c + """ + assert self.is_default_target, "label must refer to the default target" + if ":" in self.name: + return Label(self.package) + else: + return Label("%s:%s" % (self.package, self.target)) + + def __hash__(self): + return hash((self.package_path, self.target)) + + def __eq__(self, other): + if other is None: + return False + return self.package_path == other.package_path and self.target == other.target + + def __ne__(self, other): + return not self == other + + def __len__(self): + return len(self._name) + + def __repr__(self): + return self._name + + __str__ = __repr__ diff --git a/src/crawl/artifactgenctx.py b/src/crawl/artifactgenctx.py index ca5d290..9416b97 100644 --- a/src/crawl/artifactgenctx.py +++ b/src/crawl/artifactgenctx.py @@ -16,7 +16,7 @@ def __init__(self, workspace, pom_template, artifact_def, dependency): # TODO remove/make this factory/config based self._generator = crawl.pom.get_pom_generator( - workspace, pom_template, artifact_def, dependency) + workspace, pom_template, artifact_def) @property def artifact_def(self): diff --git a/src/crawl/crawler.py b/src/crawl/crawler.py index c609987..9aa7ef7 100644 --- a/src/crawl/crawler.py +++ b/src/crawl/crawler.py @@ -8,6 +8,7 @@ Crawls Bazel BUILD file dependencies and builds a DAG. """ from collections import defaultdict +from common import label as labelm from common import logger from crawl import artifactgenctx from crawl import dependency @@ -533,20 +534,30 @@ def _crawl(self, package, dep, parent_node, follow_references): artifactctx = artifactgenctx.ArtifactGenerationContext( self.workspace, self.pom_template, artifact_def, dep) self.genctxs.append(artifactctx) - source_deps, all_deps = self._discover_dependencies(artifact_def, dep) + labels = self._discover_dependencies(artifact_def, dep) + + # TODO abstract this, as it assumes maven_install + all_deps = self.workspace.parse_dep_labels([lbl.name for lbl in labels]) self.target_to_dependencies[target_key] = all_deps + if self.verbose: - logger.debug("Determined deps for artifact: [%s] with target key [%s]" % (artifact_def, target_key)) - logger.debug("Source deps: %s" % "\n".join([str(d) for d in source_deps])) - logger.debug("All deps: %s" % "\n".join([str(d) for d in all_deps])) + logger.debug("Determined labels for artifact: [%s] with target key [%s]" % (artifact_def, target_key)) + logger.debug("Labels: %s" % "\n".join([lbl.name for lbl in labels])) + logger.debug("Dependencies: %s" % "\n".join([str(d) for d in all_deps])) node = Node(parent_node, artifact_def, dep) if follow_references: - # crawl BUILD file dependencies - for source_dep in source_deps: - child_node = self._crawl(source_dep.bazel_package, - source_dep, node, - follow_references) - node.children.append(child_node) + # this is where we crawl is source label: + for label in labels: + if label.is_source_ref: + deps = self.workspace.parse_dep_labels([label.name]) + if len(deps) == 0: + # there is some filtering we have to pull out of + # the parse method above + continue + child_node = self._crawl( + label.package_path, deps[0], node, + follow_references) + node.children.append(child_node) self.target_to_node[target_key] = node self.library_to_nodes[node.artifact_def.library_path].append(node) self._store_if_leafnode(node) @@ -554,54 +565,67 @@ def _crawl(self, package, dep, parent_node, follow_references): def _discover_dependencies(self, artifact_def, dep): """ - Discovers the dependencies of the given artifact (bazel target). + Discovers the dependencies of the given artifact (==bazel target). - This method returns a tuple of 2 lists of Dependency instances: - (l1, l2) - l1: all source dependencies (== references to other bazel packages) - l2: l1 + all external dependencies + This method returns a list of common.label.Label instances. """ assert artifact_def is not None assert dep is not None, "dep is None for artifact %s" % artifact_def - all_deps = () + labels = () if artifact_def.deps is not None: - all_deps = self.workspace.parse_dep_labels(artifact_def.deps) + labels = [labelm.Label(lbl) for lbl in artifact_def.deps] if artifact_def.has_build_file: - all_deps += self._query_dependencies(artifact_def, dep) - - source_dependencies = [] - ext_dependencies = [] - for dep in all_deps: - if dep.bazel_package is None: - ext_dependencies.append(dep) - else: - source_dependencies.append(dep) - - return (tuple(source_dependencies), tuple(all_deps)) + labels += self._query_labels(artifact_def, dep) + return labels - # this method delegates to bazel query to get the value of a bazel target's - # "deps" and "runtime_deps" attributes - def _query_dependencies(self, artifact_def, dependency): + def _query_labels(self, artifact_def, dependency): + """ + Delegates to bazel query to get the value of a bazel target's "deps" + and "runtime_deps" attributes. Returns an iterable of common.label.Label + instances. + """ if not artifact_def.include_deps: return () else: assert artifact_def.bazel_package is not None assert dependency.bazel_target is not None assert len(dependency.bazel_target) > 0 - label = "%s:%s" % (artifact_def.bazel_package, dependency.bazel_target) + artifact_def_label = "%s:%s" % (artifact_def.bazel_package, dependency.bazel_target) try: - # the rule attributes to query for dependencies, typically - # "deps" and "runtime_deps" - attrs = artifact_def.pom_generation_mode.dependency_attributes - dep_labels = bazel.query_java_library_deps_attributes( - self.workspace.repo_root_path, label, attrs, + labels = bazel.query_java_library_deps_attributes( + self.workspace.repo_root_path, + artifact_def_label, + artifact_def.pom_generation_mode.dependency_attributes, self.workspace.verbose) - deps = self.workspace.parse_dep_labels(dep_labels) - return self.workspace.normalize_deps(artifact_def, deps) + labels = [labelm.Label(lbl) for lbl in labels] + return Crawler._remove_package_private_labels(labels, artifact_def) except Exception as e: msg = e.message if hasattr(e, "message") else type(e) raise Exception("Error while processing dependencies: %s %s caused by %s\nOne possible cause for this error is that the java_libary rule that builds the jar artifact is not the default bazel package target (same name as dir it lives in)" % (msg, artifact_def, repr(e))) + @classmethod + def _remove_package_private_labels(clazz, labels, owning_artifact_def): + """ + This method removes labels that point back to the bazel package + of the current artifact (so private targets in the same build file), + except when no actual artifact is produced (-> the special "skip" + generation mode). + + Specifically, this method handles the case where, in the BUILD file, + a java_library has a dependency on a (private) target defined in the + same Bazel Package. This configuration is generally not supported. + """ + updated_labels = [] + for label in labels: + if label.package_path == owning_artifact_def.bazel_package: + # this label has the same package as the artifact referencing it + # is is therefore a private target ref - skip it unless this + # package does not produce any artifact + if owning_artifact_def.pom_generation_mode.produces_artifact: + continue + updated_labels.append(label) + return updated_labels + @classmethod def _get_target_key(clazz, package, dep, artifact_def=None): if dep is None: diff --git a/src/crawl/pom.py b/src/crawl/pom.py index b0eccae..ecbfa4f 100644 --- a/src/crawl/pom.py +++ b/src/crawl/pom.py @@ -34,7 +34,7 @@ class PomContentType: MASKED_VERSION = "***" -def get_pom_generator(workspace, pom_template, artifact_def, dependency): +def get_pom_generator(workspace, pom_template, artifact_def): """ Returns a pom.xml generator (AbstractPomGen implementation) for the specified artifact_def. @@ -44,33 +44,29 @@ def get_pom_generator(workspace, pom_template, artifact_def, dependency): pom_template: the template to use for generating dynamic (jar) pom.xmls artifact_def: the crawl.buildpom.MavenArtifactDef instance for access to the parsed MVN-INF/* metadata files - dependency: the dependency pointing to this artifact_def """ assert artifact_def is not None - assert dependency is not None mode = artifact_def.pom_generation_mode if mode is pomgenmode.DYNAMIC: also_generate_dep_man_pom = artifact_def.gen_dependency_management_pom if also_generate_dep_man_pom: return PomWithCompanionDependencyManagementPomGen( - workspace, artifact_def, dependency, pom_template) + workspace, artifact_def, pom_template) else: - return DynamicPomGen( - workspace, artifact_def, dependency, pom_template) + return DynamicPomGen(workspace, artifact_def, pom_template) elif mode is pomgenmode.TEMPLATE: - return TemplatePomGen(workspace, artifact_def, dependency) + return TemplatePomGen(workspace, artifact_def) elif mode is pomgenmode.SKIP: - return NoopPomGen(workspace, artifact_def, dependency) + return NoopPomGen(workspace, artifact_def) else: raise Exception("Bug: unknown pom_generation_mode [%s] for %s" % (mode, artifact_def.bazel_package)) class AbstractPomGen(object): - def __init__(self, workspace, artifact_def, dependency): + def __init__(self, workspace, artifact_def): self._artifact_def = artifact_def - self._dependency = dependency self._workspace = workspace self.dependencies = set() @@ -85,10 +81,6 @@ def artifact_def(self): def bazel_package(self): return self._artifact_def.bazel_package - @property - def dependency(self): - return self._dependency - def register_dependencies(self, dependencies): """ Registers the dependencies the backing artifact references explicitly. @@ -234,8 +226,8 @@ class NoopPomGen(AbstractPomGen): A placeholder pom generator that doesn't generate anything, but still follows references. """ - def __init__(self, workspace, artifact_def, dependency): - super(NoopPomGen, self).__init__(workspace, artifact_def, dependency) + def __init__(self, workspace, artifact_def): + super(NoopPomGen, self).__init__(workspace, artifact_def) class TemplatePomGen(AbstractPomGen): @@ -253,8 +245,8 @@ class TemplatePomGen(AbstractPomGen): """ Generates a pom.xml based on a template file. """ - def __init__(self, workspace, artifact_def, dependency): - super(TemplatePomGen, self).__init__(workspace, artifact_def, dependency) + def __init__(self, workspace, artifact_def): + super(TemplatePomGen, self).__init__(workspace, artifact_def) def gen(self, pomcontenttype): pom_content = self.artifact_def.custom_pom_template_content pom_content, parsed_dependencies = self._process_pom_template_content(pom_content) @@ -479,8 +471,8 @@ class DynamicPomGen(AbstractPomGen): #{group_id} #{version} """ - def __init__(self, workspace, artifact_def, dependency, pom_template): - super(DynamicPomGen, self).__init__(workspace, artifact_def, dependency) + def __init__(self, workspace, artifact_def, pom_template): + super(DynamicPomGen, self).__init__(workspace, artifact_def) self.pom_content = workspace.pom_content self.pom_template = pom_template @@ -568,8 +560,8 @@ class DependencyManagementPomGen(AbstractPomGen): #{group_id} #{version} """ - def __init__(self, workspace, artifact_def, dependency, pom_template): - super(DependencyManagementPomGen, self).__init__(workspace, artifact_def, dependency) + def __init__(self, workspace, artifact_def, pom_template): + super(DependencyManagementPomGen, self).__init__(workspace, artifact_def) self.pom_template = pom_template self.pom_content = workspace.pom_content @@ -614,10 +606,10 @@ class PomWithCompanionDependencyManagementPomGen(AbstractPomGen): Composite PomGen implementation with a companion PomGen the generates a DependencyManagement pom. """ - def __init__(self, workspace, artifact_def, dependency, pom_template): - super(PomWithCompanionDependencyManagementPomGen, self).__init__(workspace, artifact_def, dependency) - self.pomgen = DynamicPomGen(workspace, artifact_def, dependency, pom_template) - self.depmanpomgen = DependencyManagementPomGen(workspace, artifact_def, dependency, pom_template) + def __init__(self, workspace, artifact_def, pom_template): + super(PomWithCompanionDependencyManagementPomGen, self).__init__(workspace, artifact_def) + self.pomgen = DynamicPomGen(workspace, artifact_def, pom_template) + self.depmanpomgen = DependencyManagementPomGen(workspace, artifact_def, pom_template) def register_dependencies(self, dependencies): self.pomgen.register_dependencies(dependencies) diff --git a/src/crawl/workspace.py b/src/crawl/workspace.py index 5b33466..4b38e99 100644 --- a/src/crawl/workspace.py +++ b/src/crawl/workspace.py @@ -80,31 +80,6 @@ def parse_dep_labels(self, dep_labels): deps.append(dep) return deps - def normalize_deps(self, artifact_def, deps): - """ - Normalizes the specified deps, in the context of the specified - owning artifact_def. - - This method performs the following steps: - - - removes deps that point back to the artifact that references them - - Specifically, this method handles the case where, in the BUILD file, - a java_library has a dependency on a (private) target defined in the - same Bazel Package. This configuration is generally not supported, - except when the referenced targets are gRPC related. - """ - updated_deps = [] - for dep in deps: - if dep.bazel_package is not None and dep.bazel_package == artifact_def.bazel_package: - # this dep has the same bazel_package as the artifact - # referencing the dep, skip it, unless this bazel package - # actually does not produce artifacts - if artifact_def.pom_generation_mode.produces_artifact: - continue - updated_deps.append(dep) - return updated_deps - def filter_artifact_producing_packages(self, packages): """ Given a list of packages, returns those that are actually producing diff --git a/tests/crawlerunittest.py b/tests/crawlerunittest.py index 87c01af..9d44092 100644 --- a/tests/crawlerunittest.py +++ b/tests/crawlerunittest.py @@ -5,6 +5,8 @@ For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause """ + +from common import label from common import maveninstallinfo from common import pomgenmode from config import config @@ -504,6 +506,32 @@ def test_propagate_requires_release_up__two_children(self): self.assertTrue(a1_node.artifact_def.requires_release) self.assertIn("transitive", a1_node.artifact_def.release_reason) + def test_remove_package_private_labels(self): + package = "a/b/c" + art = buildpom.MavenArtifactDef("g1", "a1", "1", bazel_package=package, + pom_generation_mode=pomgenmode.DYNAMIC) + l1 = label.Label(package) + l2 = label.Label("%s:foo" % package) + l3 = label.Label("//something_else:foo") + l4 = label.Label("@maven_install//:guava") + + labels = crawlerm.Crawler._remove_package_private_labels([l1, l2, l3, l4], art) + + self.assertEqual([l3, l4], labels) + + def test_remove_package_private_labels__skip_mode_allows_them(self): + package = "a/b/c" + art = buildpom.MavenArtifactDef("g1", "a1", "1", bazel_package=package, + pom_generation_mode=pomgenmode.SKIP) + l1 = label.Label(package) + l2 = label.Label("%s:foo" % package) + l3 = label.Label("//something_else:foo") + l4 = label.Label("@maven_install//:guava") + + labels = crawlerm.Crawler._remove_package_private_labels([l1, l2, l3, l4], art) + + self.assertEqual([l1, l2, l3, l4], labels) + def _build_node(self, artifact_id, bazel_package, pom_generation_mode=pomgenmode.DYNAMIC, parent_node=None, library_path=None): diff --git a/tests/labeltest.py b/tests/labeltest.py new file mode 100644 index 0000000..71fdac1 --- /dev/null +++ b/tests/labeltest.py @@ -0,0 +1,262 @@ +from common import label +import unittest + + +class LabelTest(unittest.TestCase): + + def test_wildcard(self): + n1 = label.Label("//foo/blah:foo") + + self.assertEqual(label.Label("//foo/blah/..."), + n1.as_wildcard_label("...")) + self.assertEqual(label.Label("//foo/blah:*"), + n1.as_wildcard_label("*")) + + def test_with_target(self): + n1 = label.Label("//foo/blah:foo") + self.assertEqual(label.Label("//foo/blah:blah"), + n1.with_target("blah")) + + def test_invalid(self): + n1 = label.Label("//foo/blah/") + self.assertEqual("//foo/blah", n1.name) + + def test_name(self): + n = label.Label("name") + self.assertEqual("name", n.name) + + def test_package(self): + n = label.Label("name") + self.assertEqual("name", n.package) + + n = label.Label("name:foo/blah") + self.assertEqual("name", n.package) + + n = label.Label("name:foo/blah:goo") + self.assertEqual("name", n.package) + + n = label.Label("name/foo/...") + self.assertEqual("name/foo/", n.package) + + n = label.Label("...") + self.assertEqual("", n.package) + + n = label.Label("//...") + self.assertEqual("//", n.package) + + def test_package_path(self): + n = label.Label("name") + self.assertEqual("name", n.package_path) + + n = label.Label("//dir1/dir2:foo/blah") + self.assertEqual("dir1/dir2", n.package_path) + + n = label.Label("//name/name2") + self.assertEqual("name/name2", n.package_path) + + n = label.Label("//name/name2/...") + self.assertEqual("name/name2", n.package_path) + + n = label.Label("name/foo/...") + self.assertEqual("name/foo", n.package_path) + + n = label.Label("...") + self.assertEqual("", n.package_path) + + n = label.Label("//...") + self.assertEqual("", n.package_path) + + def test_target(self): + n = label.Label("//:name") + self.assertEqual("name", n.target) + self.assertEqual("name", n.target_name) + + n = label.Label("name:foo/blah") + self.assertEqual("foo/blah", n.target) + self.assertEqual("foo/blah", n.target_name) + + n = label.Label("name:foo/blah:goo") + self.assertEqual("foo/blah:goo", n.target) + self.assertEqual("foo/blah:goo", n.target_name) + + n = label.Label("a/b/c") + self.assertEqual("c", n.target) + self.assertEqual("c", n.target_name) + + n = label.Label("//foo") + self.assertEqual("foo", n.target) + self.assertEqual("foo", n.target_name) + + n = label.Label("foo") + self.assertEqual("foo", n.target) + self.assertEqual("foo", n.target_name) + + n = label.Label(":foo") + self.assertEqual("foo", n.target) + self.assertEqual("foo", n.target_name) + + def test_is_default_target(self): + n = label.Label("//name") + self.assertTrue(n.is_default_target) + + n = label.Label("name:name") + self.assertTrue(n.is_default_target) + + n = label.Label("//name:foo") + self.assertFalse(n.is_default_target) + + def test_alternate_default_target_syntax(self): + n1 = label.Label("//a/b/c") + alt = n1.as_alternate_default_target_syntax() + self.assertTrue(isinstance(alt, label.Label)) + self.assertEqual("//a/b/c:c", str(alt.name)) + + n1 = label.Label("//a/b/c:c") + alt = n1.as_alternate_default_target_syntax() + + self.assertTrue(isinstance(alt, label.Label)) + self.assertEqual("//a/b/c", str(alt.name)) + + + def test_alternate_default_target_syntax__error_on_non_default(self): + n1 = label.Label("//a/b/c:foo") + + with self.assertRaises(Exception): + n1.as_alternate_default_target_syntax() + + def test_is_root_target(self): + n = label.Label("//name") + self.assertFalse(n.is_root_target) + + n = label.Label("@pomgen//:query") + self.assertTrue(n.is_root_target) + + n = label.Label("//:query") + self.assertTrue(n.is_root_target) + + def test_is_private(self): + n = label.Label("name") + self.assertFalse(n.is_private) + + n = label.Label(":name") + self.assertTrue(n.is_private) + + def test_fqname(self): + n = label.Label("name") + self.assertEqual("@maven//:name", n.fqname) + + n = label.Label("@bazel//:name") + self.assertEqual("@bazel//:name", n.fqname) + + n = label.Label("//foo/blah") + self.assertEqual("//foo/blah", n.fqname) + + def test_simple_name(self): + n = label.Label("name") + self.assertEqual("name", n.simple_name) + + n = label.Label("@bazel//:name") + self.assertEqual("name", n.simple_name) + + n = label.Label("//foo/blah") + self.assertEqual("//foo/blah", n.simple_name) + + def test_has_repo_prefix(self): + n = label.Label("name") + self.assertFalse(n.has_repo_prefix) + + n = label.Label("@foo//:name") + self.assertTrue(n.has_repo_prefix) + + n = label.Label("@pomgen//maven") + self.assertTrue(n.has_repo_prefix) + + def test_repo_prefix(self): + n = label.Label("name") + self.assertIsNone(n.repo_prefix) + + n = label.Label("@foo//:name") + self.assertEqual("foo", n.repo_prefix) + + n = label.Label("@pomgen//maven") + self.assertEqual("pomgen", n.repo_prefix) + + def test_has_extension_suffix(self): + n = label.Label("name-extension") + self.assertFalse(n.has_extension_suffix) + + n = label.Label("name_extension") + self.assertTrue(n.has_extension_suffix) + + def test_is_source_ref(self): + n = label.Label("name-extension") + self.assertFalse(n.is_source_ref) + + n = label.Label("//name_extension") + self.assertTrue(n.is_source_ref) + + def test_has_file_extension(self): + n = label.Label("name") + self.assertFalse(n.has_file_extension) + + n = label.Label("name.jar") + self.assertTrue(n.has_file_extension) + + def test_is_source_artifact(self): + n = label.Label("name") + self.assertFalse(n.is_sources_artifact) + + n = label.Label("name_jar_sources.jar") + self.assertTrue(n.is_sources_artifact) + + def test_len(self): + self.assertEqual(4, len(label.Label("1234"))) + + def test_hash(self): + n1 = label.Label("1234") + n2 = label.Label("1234") + self.assertEqual(hash(n1), hash(n2)) + + n1 = label.Label("a/b/c") + n2 = label.Label("a/b/c:c") + self.assertEqual(hash(n1), hash(n2)) + + def test_eq(self): + n1 = label.Label("1234") + n2 = label.Label("1234") + self.assertEqual(n1, n2) + self.assertFalse(n1 != n2) + + # n1 specifies the default target, n2 does not, the labels + # are equal + n1 = label.Label("//a/b/c:c") + n2 = label.Label("//a/b/c") + self.assertEqual(n1, n2) + self.assertFalse(n1 != n2) + + n1 = label.Label("1234") + n2 = label.Label("4567") + self.assertNotEqual(n1, n2) + self.assertFalse(n1 == n2) + + n1 = label.Label("a/b/c") + n2 = label.Label("//a/b/c") + self.assertEqual(n1, n2) + self.assertFalse(n1 != n2) + + def test_build_file(self): + n1 = label.Label("a/b/c/BUILD") + self.assertEqual("a/b/c", n1.package) + self.assertEqual("a/b/c/BUILD", n1.build_file_path) + + n1 = label.Label("a/b/c/BUILD.bazel") + self.assertEqual("a/b/c", n1.package) + self.assertEqual("a/b/c/BUILD.bazel", n1.build_file_path) + + n1 = label.Label("a/b/c/BUILDER") + self.assertEqual("a/b/c/BUILDER", n1.package) + self.assertIsNone(n1.build_file_path) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/pomtest.py b/tests/pomtest.py index a6168ea..bddf5f3 100644 --- a/tests/pomtest.py +++ b/tests/pomtest.py @@ -70,8 +70,7 @@ def test_dynamic_pom__sanity(self): label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("g1", "a2", "1.2.3") artifact_def = buildpom._augment_art_def_values(artifact_def, None, "pack1", None, None, pomgenmode.DYNAMIC) - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) - pomgen = pom.DynamicPomGen(ws, artifact_def, dep, TEST_POM_TEMPLATE) + pomgen = pom.DynamicPomGen(ws, artifact_def, TEST_POM_TEMPLATE) deps = [self.guava_dep, self.logback_dep, @@ -202,8 +201,7 @@ def test_dynamic_pom__gen_description(self): """ artifact_def = buildpom.MavenArtifactDef("g1", "a2", "1.2.3", bazel_target="t1") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) - pomgen = pom.DynamicPomGen(ws, artifact_def, dep, pom_template) + pomgen = pom.DynamicPomGen(ws, artifact_def, pom_template) generated_pom = pomgen.gen(pom.PomContentType.RELEASE) self.assertEqual(exepcted_pom, generated_pom) @@ -229,8 +227,7 @@ def test_dynamic_pom__remove_description_token_if_no_value(self): """ artifact_def = buildpom.MavenArtifactDef("g1", "a2", "1.2.3", bazel_target="t1") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) - pomgen = pom.DynamicPomGen(ws, artifact_def, dep, pom_template) + pomgen = pom.DynamicPomGen(ws, artifact_def, pom_template) generated_pom = pomgen.gen(pom.PomContentType.RELEASE) @@ -249,7 +246,6 @@ def test_dyamic_pom__no_explicit_transitives(self): bazel.parse_maven_install = lambda names, overrides, verbose: query_result artifact_def = buildpom.MavenArtifactDef("g1", "a2", "1.2.3", bazel_target="t2") artifact_def = buildpom._augment_art_def_values(artifact_def, None, "pack1", None, None, pomgenmode.DYNAMIC) - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) depmd = dependencym.DependencyMetadata(None) ws = workspace.Workspace("some/path", self._get_config(), @@ -257,7 +253,7 @@ def test_dyamic_pom__no_explicit_transitives(self): pomcontent.NOOP, depmd, label_to_overridden_fq_label={}) - pomgen = pom.DynamicPomGen(ws, artifact_def, dep, TEST_POM_TEMPLATE) + pomgen = pom.DynamicPomGen(ws, artifact_def, TEST_POM_TEMPLATE) pomgen.register_dependencies([self.guava_dep]) generated_pom = pomgen.gen(pom.PomContentType.RELEASE) @@ -283,9 +279,7 @@ def test_dynamic_pom__classifier(self): label_to_overridden_fq_label={}) root_artifact_def = buildpom.MavenArtifactDef("g1", "a2", "1.2.3") root_artifact_def = buildpom._augment_art_def_values(root_artifact_def, None, "pack1", None, None, pomgenmode.DYNAMIC) - root_dep = dependency.new_dep_from_maven_artifact_def(root_artifact_def) - - pomgen = pom.DynamicPomGen(ws, root_artifact_def, root_dep, TEST_POM_TEMPLATE) + pomgen = pom.DynamicPomGen(ws, root_artifact_def, TEST_POM_TEMPLATE) dep_art_def = buildpom.MavenArtifactDef("class-group", "class-art", "1", bazel_target="g1") dep = dependency.new_dep_from_maven_artifact_def(dep_art_def) @@ -312,8 +306,7 @@ def test_dynamic_pom__do_not_include_deps(self): label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef( "g1", "a2", "1.2.3", bazel_target="t1", include_deps=False) - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) - pomgen = pom.DynamicPomGen(ws, artifact_def, dep, "") + pomgen = pom.DynamicPomGen(ws, artifact_def, "") generated_pom = pomgen.gen(pom.PomContentType.RELEASE) @@ -332,8 +325,7 @@ def test_dynamic_pom_genmode__goldfile(self): label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("g1", "a2", "1.2.3", bazel_target="t1") artifact_def = buildpom._augment_art_def_values(artifact_def, None, "pack1", None, None, pomgenmode.DYNAMIC) - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) - pomgen = pom.DynamicPomGen(ws, artifact_def, dep, TEST_POM_TEMPLATE) + pomgen = pom.DynamicPomGen(ws, artifact_def, TEST_POM_TEMPLATE) deps = [self.guava_dep, self.aop_dep] pomgen.register_dependencies(deps) @@ -370,14 +362,13 @@ def test_template_var_sub(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.4.4", bazel_target="t1") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = """ unqualified #{ch_qos_logback_logback_classic.version} qualified #{@maven//:ch_qos_logback_logback_classic.version} coord #{ch.qos.logback:logback-classic:version} monorepo artifact version #{version} """ - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) generated_pom = pomgen.gen(pom.PomContentType.RELEASE) @@ -397,12 +388,11 @@ def test_template_var_sub__monorepo_deps(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.2.3", bazel_target="t") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = "srpc #{com.grail.srpc:srpc-api:version}" srpc_artifact_def = buildpom.MavenArtifactDef( "com.grail.srpc", "srpc-api", "5.6.7", bazel_package="a/b/c") srpc_dep = dependency.MonorepoDependency(srpc_artifact_def, bazel_target=None) - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) pomgen.register_dependencies_transitive_closure__library(set([srpc_dep])) generated_pom = pomgen.gen(pom.PomContentType.RELEASE) @@ -423,7 +413,6 @@ def test_template_var_sub__ext_deps_with_same_versions(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.4.4", bazel_target="c") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = """ 1 v1 #{@maven//:org_apache_maven_same_version.version} 2 v2 #{@maven2//:org_apache_maven_same_version.version} @@ -431,7 +420,7 @@ def test_template_var_sub__ext_deps_with_same_versions(self): 4 v #{org.apache.maven:same-version:version} """ - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) generated_pom = pomgen.gen(pom.PomContentType.RELEASE) @@ -453,12 +442,11 @@ def test_template_var_sub__ext_deps_with_diff_versions(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.4.4", bazel_target="t3") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = """ v1 #{@maven//:org_apache_maven_mult_versions.version} v2 #{@maven2//:org_apache_maven_mult_versions.version} """ - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) generated_pom = pomgen.gen(pom.PomContentType.RELEASE) @@ -479,11 +467,10 @@ def test_template_var_sub__ext_deps_with_diff_versions__no_unqual(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.4.4", bazel_target="t2") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = """ #{org_apache_maven_mult_versions.version} """ - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) with self.assertRaises(Exception) as ctx: pomgen.gen(pom.PomContentType.RELEASE) @@ -495,7 +482,7 @@ def test_template_var_sub__ext_deps_with_diff_versions__no_unqual(self): artifact_def.custom_pom_template_content = """ #{org.apache.maven:mult-versions:version} """ - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) with self.assertRaises(Exception) as ctx: pomgen.gen(pom.PomContentType.RELEASE) @@ -516,9 +503,8 @@ def test_template_var_sub__conflicting_gav__ext_and_BUILDpom_internal_dep(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.2.3", bazel_target="t4") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = "srpc #{com.google.guava:guava:version}" - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) # this guava dep is conflicting with an external dep -- internal package called a/b/c art = buildpom.MavenArtifactDef("com.google.guava","guava","29.0", bazel_package="a/b/c") @@ -543,9 +529,8 @@ def test_template_var_sub__conflicting_gav__ext_and_BUILDpom_no_internal_dep(sel depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.2.3", bazel_target="r") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = "srpc #{com.google.guava:guava:version}" - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) generated_pom = pomgen.gen(pom.PomContentType.RELEASE) #The maven_install guava version should be picked @@ -563,7 +548,6 @@ def test_template_genmode__goldfile(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.2.3", bazel_target="foo") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) srpc_artifact_def = buildpom.MavenArtifactDef("com.grail.srpc", "srpc-api", "5.6.7") srpc_artifact_def = buildpom._augment_art_def_values(srpc_artifact_def, None, "pack1", None, None, pomgenmode.DYNAMIC) @@ -575,7 +559,7 @@ def test_template_genmode__goldfile(self): logback unqualified #{ch_qos_logback_logback_classic.version} srpc #{com.grail.srpc:srpc-api:version} """ - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) pomgen.register_dependencies_transitive_closure__library(set([srpc_dep])) generated_pom = pomgen.gen(pomcontenttype=pom.PomContentType.GOLDFILE) @@ -617,9 +601,8 @@ def test_template__deps_config_setion_is_removed(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.2.3", bazel_target="t1") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = pom_template - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) generated_pom = pomgen.gen(pom.PomContentType.RELEASE) @@ -680,9 +663,8 @@ def test_template__unencountered_deps(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.2.3", bazel_target="d") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = pom_template - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) generated_pom = pomgen.gen(pom.PomContentType.RELEASE) @@ -729,9 +711,8 @@ def test_template__library_transitives(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.2.3", bazel_target="f") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = pom_template - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) srpc_artifact_def = buildpom.MavenArtifactDef( "com.grail.srpc", "srpc-api", "5.6.7", bazel_package="a/b/c") internal_dep = dependency.MonorepoDependency(srpc_artifact_def, bazel_target=None) @@ -808,9 +789,8 @@ def test_template__crawled_external_deps__configured_exclusions(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.2.3", bazel_target="123") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = pom_template - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) crawled_dep = dependency.ThirdPartyDependency("name", "cg", "ca", "0.0.1") pomgen.register_dependencies_transitive_closure__library(set([crawled_dep])) @@ -865,9 +845,8 @@ def test_template__crawled_external_deps__configured_attributes(self): depmd, label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.2.3", bazel_target="123") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = pom_template - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) crawled_dep = dependency.ThirdPartyDependency("name", "cg", "ca", "0.0.1") pomgen.register_dependencies_transitive_closure__library(set([crawled_dep])) @@ -889,9 +868,8 @@ def test_template_unknown_variable(self): label_to_overridden_fq_label={}) artifact_def = buildpom.MavenArtifactDef("groupId", "artifactId", "1.2.3", bazel_target="t") - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) artifact_def.custom_pom_template_content = "my pom template with a bad ref #{bad1} and also #{bad2}" - pomgen = pom.TemplatePomGen(ws, artifact_def, dep) + pomgen = pom.TemplatePomGen(ws, artifact_def) with self.assertRaises(Exception) as ctx: pomgen.gen(pom.PomContentType.RELEASE) @@ -913,8 +891,7 @@ def test_depman_pom__sanity(self): artifact_def = buildpom.MavenArtifactDef( "g1", "a2", "1.2.3", bazel_target="t1", gen_dependency_management_pom=True) - dep = dependency.new_dep_from_maven_artifact_def(artifact_def) - pomgen = pom.DependencyManagementPomGen(ws, artifact_def, dep, TEST_POM_TEMPLATE) + pomgen = pom.DependencyManagementPomGen(ws, artifact_def, TEST_POM_TEMPLATE) guava = dependency.new_dep_from_maven_art_str("google:guava:1", "guav") force = dependency.new_dep_from_maven_art_str("force:commons:1", "forc") diff --git a/tests/workspacetest.py b/tests/workspacetest.py index ab28508..a9e6811 100644 --- a/tests/workspacetest.py +++ b/tests/workspacetest.py @@ -7,11 +7,9 @@ from common.os_util import run_cmd from common import maveninstallinfo -from common import pomgenmode from config import config from config import exclusions from crawl import bazel -from crawl import buildpom from crawl import dependency from crawl import dependencymd as dependencym from crawl import git @@ -37,52 +35,6 @@ def setUp(self): def tearDown(self): bazel.parse_maven_install = self.orig_bazel_parse_maven_install - def test_normalize_deps__default_removes_refs_to_same_package(self): - depmd = dependencym.DependencyMetadata(None) - ws = workspace.Workspace("so/path", - self._get_config(), - maveninstallinfo.NOOP, - pom_content=pomcontent.NOOP, - dependency_metadata=depmd, - label_to_overridden_fq_label={}) - package = "a/b/c" - art1 = buildpom.MavenArtifactDef("g1", "a1", "1", bazel_package=package, - pom_generation_mode=pomgenmode.DYNAMIC) - dep1 = dependency.MonorepoDependency(art1, bazel_target=None) - art2 = buildpom.MavenArtifactDef("g2", "a2", "1", bazel_package=package) - dep2 = dependency.MonorepoDependency(art2, bazel_target=None) - art3 = buildpom.MavenArtifactDef("g1", "a1", "1", bazel_package="d/e/f") - dep3 = dependency.MonorepoDependency(art3, bazel_target=None) - dep4 = dependency.ThirdPartyDependency("name", "g101", "a101", "1") - - # the result of this method is based on bazel_package comparison - deps = ws.normalize_deps(art1, [dep1, dep2, dep3, dep4]) - - self.assertEqual([dep3, dep4], deps) - - def test_normalize_deps__skip_pomgen_mode_allows_refs_to_same_package(self): - depmd = dependencym.DependencyMetadata(None) - ws = workspace.Workspace("so/path", - self._get_config(), - maveninstallinfo.NOOP, - pom_content=pomcontent.NOOP, - dependency_metadata=depmd, - label_to_overridden_fq_label={}) - package = "a/b/c" - art1 = buildpom.MavenArtifactDef("g1", "a1", "1", bazel_package=package, - pom_generation_mode=pomgenmode.SKIP) - dep1 = dependency.MonorepoDependency(art1, bazel_target=None) - art2 = buildpom.MavenArtifactDef("g2", "a2", "1", bazel_package=package) - dep2 = dependency.MonorepoDependency(art2, bazel_target=None) - art3 = buildpom.MavenArtifactDef("g1", "a1", "1", bazel_package="d/e/f") - dep3 = dependency.MonorepoDependency(art3, bazel_target=None) - dep4 = dependency.ThirdPartyDependency("name", "g101", "a101", "1") - - # the result of this method is based on bazel_package comparison - deps = ws.normalize_deps(art1, [dep1, dep2, dep3, dep4]) - - self.assertEqual([dep1, dep2, dep3, dep4], deps) - def test_parse_ext_dep(self): """ Verifies that an external dependency label is correctly parsed into a