fwd/vendor/cxx/tools/buck/prelude/java/java_binary.bzl
John Doty 9c435dc440 Vendor dependencies
Let's see how I like this workflow.
2022-12-19 08:38:22 -08:00

175 lines
6.6 KiB
Python

# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
load("@prelude//linking:shared_libraries.bzl", "SharedLibraryInfo", "merge_shared_libraries", "traverse_shared_library_info")
load("@prelude//utils:utils.bzl", "expect")
load(
":java_providers.bzl",
"create_template_info",
"derive_compiling_deps",
"get_java_packaging_info",
)
def _generate_script(generate_wrapper: bool.type, native_libs: {str.type: "SharedLibrary"}) -> bool.type:
# if `generate_wrapper` is set and no native libs then it should be a wrapper script as result,
# otherwise fat jar will be generated (inner jar or script will be included inside a final fat jar)
return generate_wrapper and len(native_libs) == 0
def _create_fat_jar(
ctx: "context",
java_toolchain: JavaToolchainInfo.type,
jars: "cmd_args",
native_libs: {str.type: "SharedLibrary"},
generate_wrapper: bool.type) -> ["artifact"]:
extension = "sh" if _generate_script(generate_wrapper, native_libs) else "jar"
output = ctx.actions.declare_output("{}.{}".format(ctx.label.name, extension))
args = [
java_toolchain.fat_jar[RunInfo],
"--jar_tool",
java_toolchain.jar,
"--jar_builder_tool",
cmd_args(java_toolchain.jar_builder, delimiter = " "),
"--output",
output.as_output(),
"--jars_file",
ctx.actions.write("jars_file", jars),
]
if native_libs:
expect(
java_toolchain.is_bootstrap_toolchain == False,
"Bootstrap java toolchain could not be used for java_binary() with native code.",
)
args += [
"--fat_jar_lib",
java_toolchain.fat_jar_main_class_lib,
"--native_libs_file",
ctx.actions.write("native_libs", [cmd_args([so_name, native_lib.lib.output], delimiter = " ") for so_name, native_lib in native_libs.items()]),
# fat jar's main class
"--fat_jar_main_class",
"com.facebook.buck.jvm.java.FatJarMain",
# native libraries directory name. Main class expects to find libraries packed inside this directory.
"--fat_jar_native_libs_directory_name",
"nativelibs",
]
main_class = ctx.attrs.main_class
if main_class:
args += ["--main_class", main_class]
manifest_file = ctx.attrs.manifest_file
if manifest_file:
args += ["--manifest", manifest_file]
blocklist = ctx.attrs.blacklist
if blocklist:
args += ["--blocklist", ctx.actions.write("blocklist_args", blocklist)]
if ctx.attrs.meta_inf_directory:
args += ["--meta_inf_directory", ctx.attrs.meta_inf_directory]
outputs = [output]
if generate_wrapper:
classpath_args_output = ctx.actions.declare_output("classpath_args")
args += [
"--generate_wrapper",
"--classpath_args_output",
classpath_args_output.as_output(),
"--java_tool",
java_toolchain.java[RunInfo],
"--script_marker_file_name",
"wrapper_script",
]
outputs.append(classpath_args_output)
fat_jar_cmd = cmd_args(args)
fat_jar_cmd.hidden(jars, [native_lib.lib.output for native_lib in native_libs.values()])
ctx.actions.run(fat_jar_cmd, category = "fat_jar")
if generate_wrapper == False:
expect(
len(outputs) == 1,
"expected exactly one output when creating a fat jar",
)
# If `generate_wrapper` is not set then the result will contain only 1 item that represent fat jar artifact.
# Else if `generate_wrapper` is set then the first item in the result list will be script or far jar, and the second one is for @classpath_args file
return outputs
def _get_run_cmd(
attrs: struct.type,
script_mode: bool.type,
main_artifact: "artifact",
java_toolchain: JavaToolchainInfo.type) -> "cmd_args":
if script_mode:
return cmd_args(["/bin/bash", main_artifact])
else:
return cmd_args([java_toolchain.java[RunInfo]] + attrs.java_args_for_run_info + ["-jar", main_artifact])
def _get_java_tool_artifacts(java_toolchain: JavaToolchainInfo.type) -> ["artifact"]:
default_info = java_toolchain.java[DefaultInfo]
return default_info.default_outputs + default_info.other_outputs
def java_binary_impl(ctx: "context") -> ["provider"]:
"""
java_binary() rule implementation
Args:
ctx: rule analysis context
Returns:
list of created providers (DefaultInfo and RunInfo)
"""
if ctx.attrs._build_only_native_code:
return [
DefaultInfo(default_outputs = [ctx.actions.write("unused.jar", [])]),
RunInfo(),
]
packaging_info = get_java_packaging_info(ctx, ctx.attrs.deps, None)
first_order_deps = derive_compiling_deps(ctx.actions, None, ctx.attrs.deps)
first_order_libs = [dep.full_library for dep in (list(first_order_deps.traverse()) if first_order_deps else [])]
shared_library_info = merge_shared_libraries(
ctx.actions,
deps = filter(None, [x.get(SharedLibraryInfo) for x in ctx.attrs.deps]),
)
native_deps = traverse_shared_library_info(shared_library_info)
java_toolchain = ctx.attrs._java_toolchain[JavaToolchainInfo]
need_to_generate_wrapper = ctx.attrs.generate_wrapper == True
packaging_jar_args = packaging_info.packaging_deps.project_as_args("full_jar_args")
outputs = _create_fat_jar(ctx, java_toolchain, cmd_args(packaging_jar_args), native_deps, need_to_generate_wrapper)
main_artifact = outputs[0]
other_outputs = []
run_cmd = _get_run_cmd(
attrs = ctx.attrs,
script_mode = _generate_script(need_to_generate_wrapper, native_deps),
main_artifact = main_artifact,
java_toolchain = java_toolchain,
)
if need_to_generate_wrapper:
classpath_file = outputs[1]
run_cmd.hidden(
java_toolchain.java[RunInfo],
classpath_file,
packaging_jar_args,
)
other_outputs = [classpath_file] + [packaging_jar_args] + _get_java_tool_artifacts(java_toolchain)
return [
DefaultInfo(default_outputs = [main_artifact], other_outputs = other_outputs),
RunInfo(args = run_cmd),
create_template_info(packaging_info, first_order_libs),
]