Skip to content

Commit

Permalink
Add exclusion info to pom.xml (#2)
Browse files Browse the repository at this point in the history
* Make java_export capable of writing exclusions to the POM file it generates.

* Reformatted _exclusion_spec_list_to_json_test_impl

---------

Co-authored-by: Patrick Prémont <[email protected]>
  • Loading branch information
vinnybod and patrick-premont authored Apr 10, 2024
1 parent 9a1ea8d commit 85fb8a5
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 6 deletions.
1 change: 0 additions & 1 deletion private/rules/has_maven_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ def _has_maven_deps_impl(target, ctx):
return _EMPTY_INFO

coordinates = read_coordinates(ctx.rule.attr.tags)
label_to_javainfo = {target.label: target[JavaInfo]}

gathered = _gathered(
all_infos = [],
Expand Down
18 changes: 18 additions & 0 deletions private/rules/java_export.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ load(":maven_bom_fragment.bzl", "maven_bom_fragment")
load(":maven_project_jar.bzl", "DEFAULT_EXCLUDED_WORKSPACES", "maven_project_jar")
load(":maven_publish.bzl", "maven_publish")
load(":pom_file.bzl", "pom_file")
load("//:specs.bzl", "parse", _json = "json")

def java_export(
name,
maven_coordinates,
manifest_entries = {},
deploy_env = [],
excluded_workspaces = {name: None for name in DEFAULT_EXCLUDED_WORKSPACES},
exclusions = {},
pom_template = None,
visibility = None,
tags = [],
Expand Down Expand Up @@ -70,6 +72,9 @@ def java_export(
that should not be included in the maven jar to a `Label` pointing to the dependency
that workspace should be replaced by, or `None` if the exclusion shouldn't be replaced
with an extra dependency.
exclusions: Mapping of target labels to a list of exclusions to be added to the POM file.
Each label must correspond to a direct maven dependency of this target.
Each exclusion is represented as a `group:artifact` string.
classifier_artifacts: A dict of classifier -> artifact of additional artifacts to publish to Maven.
doc_deps: Other `javadoc` targets that are referenced by the generated `javadoc` target
(if not using `tags = ["no-javadoc"]`)
Expand Down Expand Up @@ -104,6 +109,7 @@ def java_export(
manifest_entries = manifest_entries,
deploy_env = deploy_env,
excluded_workspaces = excluded_workspaces,
exclusions = exclusions,
pom_template = pom_template,
visibility = visibility,
tags = tags,
Expand All @@ -122,6 +128,7 @@ def maven_export(
manifest_entries = {},
deploy_env = [],
excluded_workspaces = {},
exclusions = {},
pom_template = None,
visibility = None,
tags = [],
Expand Down Expand Up @@ -185,6 +192,9 @@ def maven_export(
that should not be included in the maven jar to a `Label` pointing to the dependency
that workspace should be replaced by, or `None` if the exclusion shouldn't be replaced
with an extra dependency.
exclusions: Mapping of target labels to a list of exclusions to be added to the POM file.
Each label must correspond to a direct maven dependency of this target.
Each exclusion is represented as a `group:artifact` string.
doc_deps: Other `javadoc` targets that are referenced by the generated `javadoc` target
(if not using `tags = ["no-javadoc"]`)
doc_url: The URL at which the generated `javadoc` will be hosted (if not using
Expand Down Expand Up @@ -267,6 +277,13 @@ def maven_export(
)
classifier_artifacts.setdefault("javadoc", docs_jar)

exclusions_dict_json_strings = {
target: _json.write_exclusion_spec_list(
parse.parse_exclusion_spec_list(targetExclusions),
)
for target, targetExclusions in exclusions.items()
}

pom_file(
name = "%s-pom" % name,
target = ":%s" % lib_name,
Expand All @@ -276,6 +293,7 @@ def maven_export(
tags = tags,
testonly = testonly,
toolchains = toolchains,
exclusions = exclusions_dict_json_strings,
)

maven_publish(
Expand Down
34 changes: 30 additions & 4 deletions private/rules/maven_utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def _whitespace(indent):
whitespace = whitespace + " "
return whitespace

def format_dep(unpacked, indent = 8, include_version = True):
def format_dep(unpacked, indent = 8, include_version = True, exclusions = {}):
whitespace = _whitespace(indent)

dependency = [
Expand Down Expand Up @@ -70,6 +70,27 @@ def format_dep(unpacked, indent = 8, include_version = True):
" <scope>%s</scope>\n" % unpacked.scope,
])

if exclusions:
dependency.extend([
whitespace,
" <exclusions>\n",
])
for exclusion in exclusions:
dependency.extend([
whitespace,
" <exclusion>\n",
whitespace,
" <groupId>%s</groupId>\n" % exclusion["group"],
whitespace,
" <artifactId>%s</artifactId>\n" % exclusion["artifact"],
whitespace,
" </exclusion>\n",
])
dependency.extend([
whitespace,
" </exclusions>\n",
])

dependency.extend([
whitespace,
"</dependency>",
Expand All @@ -85,7 +106,8 @@ def generate_pom(
parent = None,
versioned_dep_coordinates = [],
unversioned_dep_coordinates = [],
indent = 8):
indent = 8,
exclusions = {}):
unpacked_coordinates = unpack_coordinates(coordinates)
substitutions = {
"{groupId}": unpacked_coordinates.groupId,
Expand All @@ -95,6 +117,10 @@ def generate_pom(
"{scope}": unpacked_coordinates.scope or "compile",
}

for key in exclusions:
if key not in versioned_dep_coordinates and key not in unversioned_dep_coordinates:
fail("Key %s in exclusions does not occur in versioned_dep_coordinates or unversioned_dep_coordinates" % key)

if parent:
# We only want the groupId, artifactID, and version
unpacked_parent = unpack_coordinates(parent)
Expand All @@ -113,10 +139,10 @@ def generate_pom(
deps = []
for dep in sorted(versioned_dep_coordinates):
unpacked = unpack_coordinates(dep)
deps.append(format_dep(unpacked, indent = indent))
deps.append(format_dep(unpacked, indent = indent, exclusions = exclusions.get(dep, {})))
for dep in sorted(unversioned_dep_coordinates):
unpacked = unpack_coordinates(dep)
deps.append(format_dep(unpacked, indent = indent, include_version = False))
deps.append(format_dep(unpacked, indent = indent, exclusions = exclusions.get(dep, {}), include_version = False))

substitutions.update({"{dependencies}": "\n".join(deps)})

Expand Down
22 changes: 21 additions & 1 deletion private/rules/pom_file.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ def _pom_file_impl(ctx):
artifact_jars = calculate_artifact_jars(info)
additional_deps = determine_additional_dependencies(artifact_jars, ctx.attr.additional_dependencies)

def get_coordinates(target):
if not info.label_to_javainfo.get(target.label):
fail("exclusions key %s not found in dependencies %s" % (target, info.label_to_javainfo.keys()))
else:
return ctx.expand_make_variables("exclusions", target[MavenInfo].coordinates, ctx.var)

exclusions = {
get_coordinates(target): json.decode(targetExclusions)
for target, targetExclusions in ctx.attr.exclusions.items()
}

all_maven_deps = info.maven_deps.to_list()
for dep in additional_deps:
for coords in dep[MavenInfo].as_maven_dep.to_list():
Expand All @@ -30,6 +41,7 @@ def _pom_file_impl(ctx):
versioned_dep_coordinates = sorted(expanded_maven_deps),
pom_template = ctx.file.pom_template,
out_name = "%s.xml" % ctx.label.name,
exclusions = exclusions,
)

return [
Expand All @@ -54,7 +66,8 @@ The following substitutions are performed on the template file:
{type}: Replaced by the maven coordinates type, if present (defaults to "jar")
{scope}: Replaced by the maven coordinates type, if present (defaults to "compile")
{dependencies}: Replaced by a list of maven dependencies directly relied upon
by java_library targets within the artifact.
by java_library targets within the artifact. Dependencies have exclusions
for any transitive dependencies that are occur in deploy_env.
""",
attrs = {
"pom_template": attr.label(
Expand Down Expand Up @@ -82,5 +95,12 @@ The following substitutions are performed on the template file:
has_maven_deps,
],
),
"exclusions": attr.label_keyed_string_dict(
doc = "Mapping of dependency labels to a list of exclusions (encoded as a json string). Each exclusion is a dict with a group and an artifact.",
allow_empty = True,
aspects = [
has_maven_deps,
],
),
},
)
7 changes: 7 additions & 0 deletions specs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,12 @@ def _exclusion_spec_to_json(exclusion_spec):
"""
return "{ \"group\": \"" + exclusion_spec["group"] + "\", \"artifact\": \"" + exclusion_spec["artifact"] + "\" }"

def _exclusion_spec_list_to_json(exclusion_spec):
"""
Given a list of artifact exclusion spec, returns its json serialization.
"""
return "[" + ", ".join([_exclusion_spec_to_json(spec) for spec in exclusion_spec]) + "]"

def _override_license_types_spec_to_json(override_license_types_spec):
"""
Given an override license types spec, returns the json serialization of the object.
Expand Down Expand Up @@ -246,6 +252,7 @@ json = struct(
write_repository_credentials_spec = _repository_credentials_spec_to_json,
write_repository_spec = _repository_spec_to_json,
write_exclusion_spec = _exclusion_spec_to_json,
write_exclusion_spec_list = _exclusion_spec_list_to_json,
write_override_license_types_spec = _override_license_types_spec_to_json,
write_artifact_spec = _artifact_spec_to_json,
)
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/specs_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,25 @@ def _exclusion_spec_to_json_test_impl(ctx):

exclusion_spec_to_json_test = unittest.make(_exclusion_spec_to_json_test_impl)

def _exclusion_spec_list_to_json_test_impl(ctx):
env = unittest.begin(ctx)
asserts.equals(
env,
"[" +
"{ \"group\": \"org.eclipse.aether\", \"artifact\": \"aether-api\" }, " +
"{ \"group\": \"org.eclipse.aether\", \"artifact\": \"aether-util\" }" +
"]",
json.write_exclusion_spec_list(
[
{"group": "org.eclipse.aether", "artifact": "aether-api"},
{"group": "org.eclipse.aether", "artifact": "aether-util"},
],
),
)
return unittest.end(env)

exclusion_spec_list_to_json_test = unittest.make(_exclusion_spec_list_to_json_test_impl)

def _override_license_types_to_json_test_impl(ctx):
env = unittest.begin(ctx)
asserts.equals(
Expand Down Expand Up @@ -383,6 +402,7 @@ def artifact_specs_test_suite():
repository_credentials_spec_to_json_test,
repository_spec_to_json_test,
exclusion_spec_to_json_test,
exclusion_spec_list_to_json_test,
override_license_types_spec_to_json_test,
artifact_spec_to_json_test,
)
Expand Down

0 comments on commit 85fb8a5

Please sign in to comment.