Skip to content

Commit b34d897

Browse files
committed
deploy: Simplify javadoc generation
By using a new `javadoc` attribute, we can build the javadocs offline and in a single step.
1 parent f99c2ff commit b34d897

File tree

5 files changed

+282
-49
lines changed

5 files changed

+282
-49
lines changed

CONTRIBUTING.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,5 @@ Requires an account on [Sonatype](https://issues.sonatype.org) with access to th
101101

102102
Javadocs are hosted at https://codeintelligencetesting.github.io/jazzer-docs, which is populated from https://github.com/CodeIntelligenceTesting/jazzer-docs.
103103

104-
To update the docs after a release with API changes, follow these steps to get properly linked cross-references:
105-
106-
1. Delete the contents of the `jazzer-api` subdirectory of `jazzer-docs`.
107-
2. Run `bazel build --//deploy:linked_javadoc //deploy:jazzer-api-docs` and unpack the jar into the `jazzer-api` subdirectory of `jazzer-docs`.
108-
3. Commit and push the changes, then wait for them to be published (can take a minute).
109-
4. Repeat the same steps with `jazzer-api` replaced by `jazzer` and then by `jazzer-junit`.
104+
To update the docs after a release with API changes, replace the contents of the `jazzer`, `jazzer-api`, and `jazzer-junit` subdirectories of `jazzer-docs` with the extracted contents of the `//deploy:jazzer-docs`, `//deploy:jazzer-api-docs`, and `//deploy:jazzer-junit-docs` targets, respectively.
105+
Then commit and push to have the docs published automatically (can take about a few minutes to appear).

deploy/BUILD.bazel

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,7 @@
1-
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
21
load("@rules_jvm_external//:defs.bzl", "java_export")
32
load("//:maven.bzl", "JAZZER_API_COORDINATES", "JAZZER_COORDINATES", "JAZZER_JUNIT_COORDINATES")
43
load("//bazel:compat.bzl", "SKIP_ON_WINDOWS")
54

6-
bool_flag(
7-
name = "linked_javadoc",
8-
build_setting_default = False,
9-
)
10-
11-
config_setting(
12-
name = "emit_linked_javadoc",
13-
flag_values = {
14-
":linked_javadoc": "True",
15-
},
16-
visibility = ["//:__subpackages__"],
17-
)
18-
195
sh_binary(
206
name = "deploy",
217
srcs = ["deploy.sh"],
@@ -28,13 +14,11 @@ sh_binary(
2814

2915
java_export(
3016
name = "jazzer-api",
31-
javadocopts = select({
32-
":emit_linked_javadoc": [
33-
"-link",
34-
"https://docs.oracle.com/en/java/javase/17/docs/api/",
35-
],
36-
"//conditions:default": [],
37-
}),
17+
doc_url = "https://codeintelligencetesting.github.io/jazzer-docs/jazzer-api/",
18+
javadocopts = [
19+
"-link",
20+
"https://docs.oracle.com/en/java/javase/17/docs/api/",
21+
],
3822
maven_coordinates = JAZZER_API_COORDINATES,
3923
pom_template = "//deploy:jazzer-api.pom",
4024
visibility = ["//visibility:public"],
@@ -69,19 +53,17 @@ java_export(
6953
# Exclude the unshaded classes comprising com.code-intelligence:jazzer since the java_library
7054
# target comprising jazzer-junit depend on the individual libraries, not the shaded jar.
7155
deploy_env = ["//src/main/java/com/code_intelligence/jazzer:jazzer_lib"],
72-
javadocopts = select({
73-
":emit_linked_javadoc": [
74-
"-link",
75-
"https://docs.oracle.com/en/java/javase/17/docs/api/",
76-
"-link",
77-
"https://codeintelligencetesting.github.io/jazzer-docs/jazzer-api/",
78-
"-link",
79-
"https://codeintelligencetesting.github.io/jazzer-docs/jazzer/",
80-
"-link",
81-
"https://junit.org/junit5/docs/current/api/",
82-
],
83-
"//conditions:default": [],
84-
}),
56+
doc_deps = [
57+
":jazzer-api-docs",
58+
":jazzer-docs",
59+
],
60+
doc_url = "https://codeintelligencetesting.github.io/jazzer-docs/jazzer-junit/",
61+
javadocopts = [
62+
"-link",
63+
"https://docs.oracle.com/en/java/javase/17/docs/api/",
64+
"-link",
65+
"https://junit.org/junit5/docs/current/api/",
66+
],
8567
maven_coordinates = JAZZER_JUNIT_COORDINATES,
8668
pom_template = "jazzer-junit.pom",
8769
visibility = ["//visibility:public"],

repositories.bzl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ def jazzer_dependencies(android = False):
6060
name = "rules_jvm_external",
6161
patch_args = ["-p1"],
6262
patches = [
63+
# https://github.com/bazelbuild/rules_jvm_external/pull/958
64+
# Allows javadoc targets to reference other javadoc targets.
65+
"//third_party:rules_jvm_external-javadoc-deps.patch",
6366
],
6467
sha256 = "aa17db9b810b22e411bf722095be34eeb66c76819b9c3423ad7740f452016aa3",
6568
strip_prefix = "rules_jvm_external-4b073de468eff9741406f475acb04e94bee7c9d0",

src/main/java/com/code_intelligence/jazzer/BUILD.bazel

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,12 @@ java_binary(
7373
# considered a public interface.
7474
javadoc(
7575
name = "jazzer-docs",
76-
javadocopts = select({
77-
"//deploy:emit_linked_javadoc": [
78-
"-link",
79-
"https://docs.oracle.com/en/java/javase/17/docs/api/",
80-
"-link",
81-
"https://codeintelligencetesting.github.io/jazzer-docs/jazzer-api/",
82-
],
83-
"//conditions:default": [],
84-
}),
76+
doc_deps = ["//deploy:jazzer-api-docs"],
77+
doc_url = "https://codeintelligencetesting.github.io/jazzer-docs/jazzer/",
78+
javadocopts = [
79+
"-link",
80+
"https://docs.oracle.com/en/java/javase/17/docs/api/",
81+
],
8582
visibility = ["//deploy:__pkg__"],
8683
deps = [":jazzer_lib"],
8784
)
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
From 119d0bf53b1a76436095986ffe11a0c97f1757db Mon Sep 17 00:00:00 2001
2+
From: Fabian Meumertzheim <[email protected]>
3+
Date: Mon, 11 Sep 2023 13:05:32 +0200
4+
Subject: [PATCH] javadoc: Allow `javadoc` targets to reference other `javadoc`
5+
targets
6+
7+
By setting the `doc_url` attribute on a `javadoc` target, other targets
8+
can depend on it via `doc_deps` and have references resolved
9+
automatically via appropriate `-linkoffline` arguments passed to
10+
javadoc.
11+
---
12+
private/rules/java_export.bzl | 21 ++++-
13+
private/rules/javadoc.bzl | 77 +++++++++++++++++--
14+
.../javadoc/JavadocJarMaker.java | 15 ++++
15+
3 files changed, 106 insertions(+), 7 deletions(-)
16+
17+
diff --git a/private/rules/java_export.bzl b/private/rules/java_export.bzl
18+
index 5c576f95..81138db1 100644
19+
--- a/private/rules/java_export.bzl
20+
+++ b/private/rules/java_export.bzl
21+
@@ -69,6 +69,10 @@ def java_export(
22+
that workspace should be replaced by, or `None` if the exclusion shouldn't be replaced
23+
with an extra dependency.
24+
classifier_artifacts: A dict of classifier -> artifact of additional artifacts to publish to Maven.
25+
+ doc_deps: Other `javadoc` targets that are referenced by the generated `javadoc` target
26+
+ (if not using `tags = ["no-javadoc"]`)
27+
+ doc_url: The URL at which the generated `javadoc` will be hosted (if not using
28+
+ `tags = ["no-javadoc"]`).
29+
visibility: The visibility of the target
30+
kwargs: These are passed to [`java_library`](https://bazel.build/reference/be/java#java_library),
31+
and so may contain any valid parameter for that rule.
32+
@@ -78,6 +82,8 @@ def java_export(
33+
lib_name = "%s-lib" % name
34+
35+
javadocopts = kwargs.pop("javadocopts", [])
36+
+ doc_deps = kwargs.pop("doc_deps", [])
37+
+ doc_url = kwargs.pop("doc_url", "")
38+
39+
# Construct the java_library we'll export from here.
40+
native.java_library(
41+
@@ -100,6 +106,8 @@ def java_export(
42+
testonly,
43+
javadocopts,
44+
classifier_artifacts = classifier_artifacts,
45+
+ doc_deps = doc_deps,
46+
+ doc_url = doc_url,
47+
)
48+
49+
def maven_export(
50+
@@ -113,7 +121,10 @@ def maven_export(
51+
tags = [],
52+
testonly = False,
53+
javadocopts = [],
54+
- classifier_artifacts = {}):
55+
+ classifier_artifacts = {},
56+
+ *,
57+
+ doc_deps = [],
58+
+ doc_url = ""):
59+
"""
60+
All arguments are the same as java_export with the addition of:
61+
lib_name: Name of the library that has been built.
62+
@@ -166,6 +177,10 @@ def maven_export(
63+
that should not be included in the maven jar to a `Label` pointing to the dependency
64+
that workspace should be replaced by, or `None` if the exclusion shouldn't be replaced
65+
with an extra dependency.
66+
+ doc_deps: Other `javadoc` targets that are referenced by the generated `javadoc` target
67+
+ (if not using `tags = ["no-javadoc"]`)
68+
+ doc_url: The URL at which the generated `javadoc` will be hosted (if not using
69+
+ `tags = ["no-javadoc"]`).
70+
visibility: The visibility of the target
71+
kwargs: These are passed to [`java_library`](https://bazel.build/reference/be/java#java_library),
72+
and so may contain any valid parameter for that rule.
73+
@@ -176,6 +191,8 @@ def maven_export(
74+
deploy_env = deploy_env if deploy_env else []
75+
excluded_workspaces = excluded_workspaces if excluded_workspaces else {}
76+
javadocopts = javadocopts if javadocopts else []
77+
+ doc_url = doc_url if doc_url else ""
78+
+ doc_deps = doc_deps if doc_deps else []
79+
tags = tags if tags else []
80+
classifier_artifacts = classifier_artifacts if classifier_artifacts else {}
81+
82+
@@ -227,6 +244,8 @@ def maven_export(
83+
":%s-project" % name,
84+
] + deploy_env,
85+
javadocopts = javadocopts,
86+
+ doc_deps = doc_deps,
87+
+ doc_url = doc_url,
88+
excluded_workspaces = excluded_workspaces.keys(),
89+
additional_dependencies = additional_dependencies,
90+
visibility = visibility,
91+
diff --git a/private/rules/javadoc.bzl b/private/rules/javadoc.bzl
92+
index 3261248a..98ce3a08 100644
93+
--- a/private/rules/javadoc.bzl
94+
+++ b/private/rules/javadoc.bzl
95+
@@ -1,16 +1,42 @@
96+
load(":maven_project_jar.bzl", "DEFAULT_EXCLUDED_WORKSPACES")
97+
98+
-def generate_javadoc(ctx, javadoc, source_jars, classpath, javadocopts, output):
99+
+_JavadocInfo = provider(
100+
+ fields = {
101+
+ "element_list": "The element-list or package-list file generated by javadoc",
102+
+ "url": "The URL at which this documentation will be hosted",
103+
+ },
104+
+)
105+
+
106+
+def generate_javadoc(
107+
+ ctx,
108+
+ javadoc,
109+
+ source_jars,
110+
+ classpath,
111+
+ javadocopts,
112+
+ doc_deps,
113+
+ output,
114+
+ element_list):
115+
+ inputs = []
116+
+ transitive_inputs = []
117+
args = ctx.actions.args()
118+
- args.add_all(["--out", output])
119+
+ args.add("--out", output)
120+
+ args.add("--element-list", element_list)
121+
args.add_all(source_jars, before_each = "--in")
122+
+ inputs.extend(source_jars)
123+
args.add_all(classpath, before_each = "--cp")
124+
+ transitive_inputs.append(classpath)
125+
+ for dep in doc_deps:
126+
+ dep_info = dep[_JavadocInfo]
127+
+ args.add("-linkoffline")
128+
+ args.add(dep_info.url)
129+
+ args.add(dep_info.element_list.dirname)
130+
+ inputs.append(dep_info.element_list)
131+
args.add_all(javadocopts)
132+
133+
ctx.actions.run(
134+
executable = javadoc,
135+
- outputs = [output],
136+
- inputs = depset(source_jars, transitive = [classpath]),
137+
+ outputs = [output, element_list],
138+
+ inputs = depset(inputs, transitive = transitive_inputs),
139+
arguments = [args],
140+
)
141+
142+
@@ -21,6 +47,10 @@ def _javadoc_impl(ctx):
143+
144+
jar_file = ctx.actions.declare_file("%s.jar" % ctx.attr.name)
145+
146+
+ # This needs to be a in a separate directory as javadoc accepts the containing directory as
147+
+ # an argument rather than the file itself.
148+
+ element_list = ctx.actions.declare_file("%s-element-list-dir/element-list" % ctx.attr.name)
149+
+
150+
# javadoc may need to inspect compile-time dependencies (neverlink)
151+
# of the runtime classpath.
152+
classpath = depset(
153+
@@ -34,11 +64,29 @@ def _javadoc_impl(ctx):
154+
# `None` https://github.com/bazelbuild/bazel/issues/10170). For this
155+
# reason we allow people to set javadocopts via the rule attrs.
156+
157+
- generate_javadoc(ctx, ctx.executable._javadoc, sources, classpath, ctx.attr.javadocopts, jar_file)
158+
+ generate_javadoc(
159+
+ ctx,
160+
+ ctx.executable._javadoc,
161+
+ sources,
162+
+ classpath,
163+
+ ctx.attr.javadocopts,
164+
+ ctx.attr.doc_deps,
165+
+ jar_file,
166+
+ element_list,
167+
+ )
168+
169+
- return [
170+
+ providers = [
171+
DefaultInfo(files = depset([jar_file])),
172+
]
173+
+ if ctx.attr.doc_url:
174+
+ providers.append(
175+
+ _JavadocInfo(
176+
+ element_list = element_list,
177+
+ url = ctx.attr.doc_url,
178+
+ ),
179+
+ )
180+
+
181+
+ return providers
182+
183+
javadoc = rule(
184+
_javadoc_impl,
185+
@@ -61,6 +109,23 @@ javadoc = rule(
186+
options can be passed here.
187+
""",
188+
),
189+
+ "doc_deps": attr.label_list(
190+
+ doc = """`javadoc` targets referenced by the current target.
191+
+
192+
+ Use this to automatically add appropriate `-linkoffline` javadoc options to resolve
193+
+ references to packages documented by the given javadoc targets that have `url`
194+
+ specified.
195+
+ """,
196+
+ providers = [
197+
+ [_JavadocInfo],
198+
+ ],
199+
+ ),
200+
+ "doc_url": attr.string(
201+
+ doc = """The URL at which this documentation will be hosted.
202+
+
203+
+ This information is only used by javadoc targets depending on this target.
204+
+ """,
205+
+ ),
206+
"excluded_workspaces": attr.string_list(
207+
doc = "A list of bazel workspace names to exclude from the generated jar",
208+
allow_empty = True,
209+
diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/javadoc/JavadocJarMaker.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/javadoc/JavadocJarMaker.java
210+
index 6e8b57e6..550e075a 100644
211+
--- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/javadoc/JavadocJarMaker.java
212+
+++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/javadoc/JavadocJarMaker.java
213+
@@ -22,6 +22,7 @@
214+
import com.github.bazelbuild.rules_jvm_external.ByteStreams;
215+
import com.github.bazelbuild.rules_jvm_external.zip.StableZipEntry;
216+
import java.io.File;
217+
+import java.io.FileNotFoundException;
218+
import java.io.IOException;
219+
import java.io.InputStream;
220+
import java.io.OutputStream;
221+
@@ -57,6 +58,7 @@ public class JavadocJarMaker {
222+
public static void main(String[] args) throws IOException {
223+
Set<Path> sourceJars = new HashSet<>();
224+
Path out = null;
225+
+ Path elementList = null;
226+
Set<Path> classpath = new HashSet<>();
227+
List<String> options = new ArrayList<>();
228+
229+
@@ -80,6 +82,11 @@ public static void main(String[] args) throws IOException {
230+
out = Paths.get(next);
231+
break;
232+
233+
+ case "--element-list":
234+
+ next = args[++i];
235+
+ elementList = Paths.get(next);
236+
+ break;
237+
+
238+
default:
239+
options.add(flag);
240+
break;
241+
@@ -167,6 +174,14 @@ public static void main(String[] args) throws IOException {
242+
return;
243+
}
244+
245+
+ Path generatedElementList = outputTo.resolve("element-list");
246+
+ try {
247+
+ Files.copy(generatedElementList, elementList);
248+
+ } catch (FileNotFoundException e) {
249+
+ // Do not fail the action if the generated element-list couldn't be found.
250+
+ Files.createFile(generatedElementList);
251+
+ }
252+
+
253+
try (OutputStream os = Files.newOutputStream(out);
254+
ZipOutputStream zos = new ZipOutputStream(os);
255+
Stream<Path> walk = Files.walk(outputTo)) {

0 commit comments

Comments
 (0)