Skip to content

Commit

Permalink
Add rule executable_jar
Browse files Browse the repository at this point in the history
Rule executable_jar generates an executable jar for a set of libraries.
  • Loading branch information
joca-bt committed Sep 2, 2023
1 parent 86a2a08 commit f6a7a7f
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 0 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

Rules:

- [executable_jar](#executable_jar)
- [javadoc](#javadoc)

## Usage
Expand All @@ -19,6 +20,22 @@ http_archive(

## Rules

### executable_jar

```bazel
executable_jar(name, libs, main_class)
```

Generates an executable jar for a set of [libraries](https://bazel.build/reference/be/java#java_library).

**Arguments**

| Name | Type | Mandatory |
| --- | --- | --- |
| name | Name | Yes |
| libs | List of labels | Yes |
| main_class | String | Yes |

### javadoc

```bazel
Expand Down
2 changes: 2 additions & 0 deletions java/defs.bzl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
load("//java/private:executable_jar.bzl", _executable_jar = "executable_jar")
load("//java/private:javadoc.bzl", _javadoc = "javadoc")

executable_jar = _executable_jar
javadoc = _javadoc
4 changes: 4 additions & 0 deletions java/private/depsets.bzl
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
visibility("private")

def set_difference(a, b):
b = {element: True for element in b.to_list()}
return depset([element for element in a.to_list() if element not in b])

def to_paths(depset):
return [element.path for element in depset.to_list()]
63 changes: 63 additions & 0 deletions java/private/executable_jar.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
load(":depsets.bzl", "set_difference", "to_paths")
load(":files.bzl", "copy_files", "write_file")
load(":jars.bzl", "extract_jars")

def _manifest(ctx):
return """\
Main-Class: extrarulesjava.loader.Loader
Start-Class: {}\
""".format(ctx.attr.main_class)

def _executable_jar_impl(ctx):
app = depset(transitive = [depset(lib[JavaInfo].runtime_output_jars) for lib in ctx.attr.libs])
libs = depset(transitive = [lib[JavaInfo].transitive_runtime_jars for lib in ctx.attr.libs])
libs = set_difference(libs, app)
output = ctx.actions.declare_file("{}.jar".format(ctx.label.name))

java_home = ctx.attr._jdk[java_common.JavaRuntimeInfo].java_home
tmp_dir = "{}/_{}/".format(output.dirname, output.basename)
app_dir = "{}/app/".format(tmp_dir)
lib_dir = "{}/lib/".format(tmp_dir)
manifest_file = "{}/manifest".format(tmp_dir)

commands = [
"rm -rf {}".format(tmp_dir),
"mkdir {} {}".format(tmp_dir, lib_dir),
extract_jars(to_paths(app), app_dir),
extract_jars(to_paths(ctx.attr._loader.files), tmp_dir),
write_file(manifest_file, _manifest(ctx)),
"{0}/bin/jar -c -f {1} -m {2} -C {3} app/ -C {3} extrarulesjava/".format(java_home, output.path, manifest_file, tmp_dir),
copy_files(to_paths(libs), lib_dir),
"{}/bin/jar -u -0 -f {} -C {} lib/".format(java_home, output.path, tmp_dir),
]

ctx.actions.run_shell(
command = " && ".join(commands),
inputs = ctx.files._jdk + ctx.files._loader + app.to_list() + libs.to_list(),
outputs = [output],
)

return [DefaultInfo(files = depset([output]))]

executable_jar = rule(
doc = "Generates an executable jar for a set of libraries.",
implementation = _executable_jar_impl,
attrs = {
"libs": attr.label_list(
allow_empty = False,
mandatory = True,
providers = [JavaInfo],
),
"main_class": attr.string(
mandatory = True,
),
"_jdk": attr.label(
default = Label("@bazel_tools//tools/jdk:current_java_runtime"),
providers = [java_common.JavaRuntimeInfo],
),
"_loader": attr.label(
default = Label("//loader"),
providers = [JavaInfo],
),
},
)
7 changes: 7 additions & 0 deletions java/private/files.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
visibility("private")

def copy_files(files, dir):
return "cp {} {}".format(" ".join(files), dir)

def write_file(file, content):
return "echo '{}' > {}".format(content, file)

0 comments on commit f6a7a7f

Please sign in to comment.