blob: 176296417dc87399f562f9453407e27dc6e3451d [file]
load("@rules_java//java:defs.bzl", "JavaInfo")
MavenInfo = provider(
fields = {
# Fields to do with maven coordinates
"coordinates": "Maven coordinates for the project, which may be None",
"maven_deps": "Depset of first-order maven dependencies",
"maven_export_deps": "Depset of first-order maven dependency exports",
"as_maven_dep": "Depset of this project if used as a maven dependency",
# Fields used for generating artifacts
"artifact_infos": "Depset of JavaInfo instances of targets to include in the maven artifact",
"dep_infos": "Depset of JavaInfo instances of dependencies that the maven artifact depends on",
"label_to_javainfo": "Dict mapping a label to the JavaInfo that label produces",
"transitive_exports": "Depset of Labels of exported targets",
},
)
MavenHintInfo = provider(
doc = """Provides hints to the `has_maven_deps` aspect about additional dependencies.
This is particularly useful if outputs are generated from aspects, and so may not be able
to offer `tags` to be used to infer maven information.
""",
fields = {
"maven_infos": "Depset of MavenInfo instances to also consider as dependencies",
},
)
_EMPTY_INFO = MavenInfo(
coordinates = None,
maven_deps = depset(),
as_maven_dep = depset(),
maven_export_deps = depset(),
artifact_infos = depset(),
dep_infos = depset(),
label_to_javainfo = {},
transitive_exports = depset(),
)
_STOPPED_INFO = MavenInfo(
coordinates = "STOPPED",
maven_deps = depset(),
as_maven_dep = depset(),
maven_export_deps = depset(),
artifact_infos = depset(),
dep_infos = depset(),
label_to_javainfo = {},
transitive_exports = depset(),
)
_MAVEN_PREFIX = "maven_coordinates="
_STOP_TAGS = [
"maven:compile-only",
"maven:compile_only",
"no-maven",
]
def read_coordinates(tags):
coordinates = []
for stop_tag in _STOP_TAGS:
if stop_tag in tags:
return None
for tag in tags:
if tag.startswith(_MAVEN_PREFIX):
coordinates.append(tag[len(_MAVEN_PREFIX):])
if len(coordinates) > 1:
fail("Zero or one set of coordinates should be defined: %s" % coordinates)
if len(coordinates) == 1:
return coordinates[0]
return None
_ASPECT_ATTRS = [
"deps",
"exports",
"runtime_deps",
]
def _set_diff(first, second):
"""Returns all items in `first` that are not in `second`"""
return [item for item in first if item not in second]
def _flatten(array_of_depsets):
flattened = {}
for dep in array_of_depsets:
for item in dep.to_list():
flattened.update({item: True})
return flattened.keys()
def calculate_artifact_jars(maven_info):
"""Calculate the actual jars to include in a maven artifact"""
all_jars = _flatten([i.transitive_runtime_jars for i in maven_info.artifact_infos.to_list()])
dep_jars = _flatten([i.transitive_runtime_jars for i in maven_info.dep_infos.to_list()])
return _set_diff(all_jars, dep_jars)
def calculate_artifact_source_jars(maven_info):
"""Calculate the actual jars to include in a maven artifact"""
all_jars = _flatten([i.transitive_source_jars for i in maven_info.artifact_infos.to_list()])
dep_jars = _flatten([i.transitive_source_jars for i in maven_info.dep_infos.to_list()])
return _set_diff(all_jars, dep_jars)
# Used to gather maven data
_gathered = provider(
fields = [
"all_infos",
"export_deps",
"label_to_javainfo",
"artifact_infos",
"transitive_exports",
"dep_infos",
],
)
def _extract_from(gathered, maven_info, dep, is_export_dep):
java_info = dep[JavaInfo] if dep and JavaInfo in dep else None
gathered.all_infos.append(maven_info)
gathered.label_to_javainfo.update(maven_info.label_to_javainfo)
if is_export_dep:
gathered.export_deps.append(maven_info)
if not java_info:
return
if maven_info.coordinates:
gathered.dep_infos.append(dep[JavaInfo])
else:
gathered.artifact_infos.append(dep[JavaInfo])
if is_export_dep:
gathered.transitive_exports.append(maven_info.transitive_exports)
def _has_maven_deps_impl(target, ctx):
if not JavaInfo in target:
return [_EMPTY_INFO]
# Check the stop tags first to let us exit quickly.
# When MavenInfo is set, _extract_from will add the dep to the dep_infos list, propagating
# the dependency info to the pom.xml and excluding its contents from the project-jar.
# If _EMPTY_INFO is used, _extract_from will add the dep to the artifact_infos list, which
# will include the contents in the project-jar.
# If _STOPPED_INFO is used, _extract_from will add the dep to the dep_infos list. This is useful
# when we want to stop the propagation of the dependency info to the pom.xml while also excluding
# the jar from the artifact.
for tag in ctx.rule.attr.tags:
if tag in _STOP_TAGS:
return [_STOPPED_INFO]
coordinates = read_coordinates(ctx.rule.attr.tags)
gathered = _gathered(
all_infos = [],
export_deps = [],
artifact_infos = [target[JavaInfo]],
transitive_exports = [],
dep_infos = [],
label_to_javainfo = {target.label: target[JavaInfo]},
)
for attr in _ASPECT_ATTRS:
for dep in getattr(ctx.rule.attr, attr, []):
if MavenHintInfo in dep:
for info in dep[MavenHintInfo].maven_infos.to_list():
_extract_from(gathered, info, None, attr == "exports")
if not MavenInfo in dep:
continue
info = dep[MavenInfo]
_extract_from(gathered, info, dep, attr == "exports")
all_infos = gathered.all_infos
artifact_infos = gathered.artifact_infos
transitive_exports_from_deps = gathered.transitive_exports
dep_infos = gathered.dep_infos
label_to_javainfo = gathered.label_to_javainfo
maven_deps = depset(transitive = [i.as_maven_dep for i in all_infos])
maven_export_deps = depset(transitive = [i.as_maven_dep for i in gathered.export_deps])
transitive_exports_from_exports = depset()
if hasattr(ctx.rule.attr, "exports"):
transitive_exports_from_exports = depset(
[e.label for e in ctx.rule.attr.exports],
transitive =
[e[MavenInfo].transitive_exports for e in ctx.rule.attr.exports],
)
info = MavenInfo(
coordinates = coordinates,
maven_deps = maven_deps,
maven_export_deps = maven_export_deps,
as_maven_dep = depset([coordinates]) if coordinates else maven_deps,
artifact_infos = depset(direct = artifact_infos),
dep_infos = depset(direct = dep_infos, transitive = [i.dep_infos for i in all_infos]),
label_to_javainfo = label_to_javainfo,
transitive_exports = depset(transitive = [transitive_exports_from_exports] + transitive_exports_from_deps),
)
return [
info,
]
has_maven_deps = aspect(
_has_maven_deps_impl,
attr_aspects = _ASPECT_ATTRS,
)