Skip to content
Permalink
Browse files
8272984: javadoc support for reproducible builds
Reviewed-by: hannesw
  • Loading branch information
jonathan-gibbons committed Jan 31, 2022
1 parent ee3be0b commit 96d0df72db277f127bd4c6b8c51bfc64d1c593e0
Showing 10 changed files with 255 additions and 21 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@

package jdk.javadoc.internal.doclets.formats.html;

import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.EnumSet;
@@ -166,6 +167,11 @@ public enum ConditionalPage {
*/
public final Set<ConditionalPage> conditionalPages;

/**
* The build date, to be recorded in generated files.
*/
private ZonedDateTime buildDate;

/**
* Constructs the full configuration needed by the doclet, including
* the format-specific part, defined in this class, and the format-independent
@@ -215,6 +221,7 @@ public HtmlConfiguration(Doclet doclet, Locale locale, Reporter reporter) {

conditionalPages = EnumSet.noneOf(ConditionalPage.class);
}

protected void initConfiguration(DocletEnvironment docEnv,
Function<String, String> resourceKeyMapper) {
super.initConfiguration(docEnv, resourceKeyMapper);
@@ -223,7 +230,6 @@ protected void initConfiguration(DocletEnvironment docEnv,
}

private final Runtime.Version docletVersion;
public final Date startTime = new Date();

@Override
public Runtime.Version getDocletVersion() {
@@ -259,6 +265,10 @@ public boolean finishOptionSettings() {
if (!options.validateOptions()) {
return false;
}

ZonedDateTime zdt = options.date();
buildDate = zdt != null ? zdt : ZonedDateTime.now();

if (!getSpecifiedTypeElements().isEmpty()) {
Map<String, PackageElement> map = new HashMap<>();
PackageElement pkg;
@@ -279,6 +289,13 @@ public boolean finishOptionSettings() {
return true;
}

/**
* {@return the date to be recorded in generated files}
*/
public ZonedDateTime getBuildDate() {
return buildDate;
}

/**
* Decide the page which will appear first in the right-hand frame. It will
* be "overview-summary.html" if "-overview" option is used or no
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -453,7 +453,7 @@ public void printHtmlDocument(List<String> metakeywords,
throws DocFileIOException {
List<DocPath> additionalStylesheets = configuration.getAdditionalStylesheets();
additionalStylesheets.addAll(localStylesheets);
Head head = new Head(path, configuration.getDocletVersion(), configuration.startTime)
Head head = new Head(path, configuration.getDocletVersion(), configuration.getBuildDate())
.setTimestamp(!options.noTimestamp())
.setDescription(description)
.setGenerator(getGenerator(getClass()))
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -74,7 +74,7 @@ private IndexRedirectWriter(HtmlConfiguration configuration, DocPath filename, D
* @throws DocFileIOException if there is a problem generating the file
*/
private void generateIndexFile() throws DocFileIOException {
Head head = new Head(path, configuration.getDocletVersion(), configuration.startTime)
Head head = new Head(path, configuration.getDocletVersion(), configuration.getBuildDate())
.setTimestamp(!options.noTimestamp())
.setDescription("index redirect")
.setGenerator(getGenerator(getClass()))
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -232,7 +232,7 @@ public void convertClass(TypeElement te, DocPath outputdir)
* @param path the path for the file.
*/
private void writeToFile(Content body, DocPath path, TypeElement te) throws DocFileIOException {
Head head = new Head(path, configuration.getDocletVersion(), configuration.startTime)
Head head = new Head(path, configuration.getDocletVersion(), configuration.getBuildDate())
// .setTimestamp(!options.notimestamp) // temporary: compatibility!
.setTitle(resources.getText("doclet.Window_Source_title"))
// .setCharset(options.charset) // temporary: compatibility!
@@ -27,12 +27,14 @@

import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
@@ -50,7 +52,7 @@
*/
public class Head extends Content {
private final Runtime.Version docletVersion;
private final Date generatedDate;
private final ZonedDateTime generatedDate;
private final DocPath pathToRoot;
private String title;
private String charset;
@@ -78,7 +80,7 @@ public class Head extends Content {
* @param path the path for the file that will include this HEAD element
* @param docletVersion the doclet version
*/
public Head(DocPath path, Runtime.Version docletVersion, Date generatedDate) {
public Head(DocPath path, Runtime.Version docletVersion, ZonedDateTime generatedDate) {
this.docletVersion = docletVersion;
this.generatedDate = generatedDate;
pathToRoot = path.parent().invert();
@@ -279,8 +281,8 @@ private Content toContent() {
}

if (showTimestamp) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
tree.add(HtmlTree.META("dc.created", dateFormat.format(generatedDate)));
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");
tree.add(HtmlTree.META("dc.created", generatedDate.format(dateFormat)));
}

if (description != null) {
@@ -309,11 +311,14 @@ private Content toContent() {
return tree;
}

private Comment getGeneratedBy(boolean timestamp, Date now) {

private Comment getGeneratedBy(boolean timestamp, ZonedDateTime buildDate) {
String text = "Generated by javadoc"; // marker string, deliberately not localized
text += " (" + docletVersion.feature() + ")";
if (timestamp) {
text += " on " + now;
DateTimeFormatter fmt =
DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy").withLocale(Locale.US);
text += " on " + buildDate.format(fmt);
}
return new Comment(text);
}
@@ -1,5 +1,5 @@
#
# Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -169,6 +169,12 @@ doclet.systemPropertiesSummary=System Properties Summary
doclet.Window_Source_title=Source code
doclet.Window_Help_title=API Help

# 0: a date
doclet.Option_date_out_of_range=value for ''--date'' out of range: {0}

# 0: a date
doclet.Option_date_not_valid=value for ''--date'' not valid: {0}

doclet.help.main_heading=\
JavaDoc Help
doclet.help.navigation.head=\
@@ -420,6 +426,12 @@ doclet.usage.windowtitle.parameters=\
doclet.usage.windowtitle.description=\
Browser window title for the documentation

doclet.usage.date.parameters=\
<date-and-time>
doclet.usage.date.description=\
Specifies the value to be used to timestamp the generated\n\
pages, in ISO 8601 format

doclet.usage.doctitle.parameters=\
<html-code>
doclet.usage.doctitle.description=\
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,8 +30,16 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
@@ -82,6 +90,12 @@ public abstract class BaseOptions {
*/
private final LinkedHashSet<List<String>> customTagStrs = new LinkedHashSet<>();

/**
* Argument for command-line option {@code --date}.
* {@code null} if option not given.
*/
private ZonedDateTime date;

/**
* Argument for command-line option {@code -d}.
* Destination directory name, in which doclet will generate the entire
@@ -338,6 +352,33 @@ public boolean process(String opt, List<String> args) {
}
},

new XOption(resources, "--date", 1) {
// Valid --date range: within ten years of now
private static final ZonedDateTime now = ZonedDateTime.now();
static final ZonedDateTime DATE_MIN = now.minusYears(10);
static final ZonedDateTime DATE_MAX = now.plusYears(10);

@Override
public boolean process(String opt, List<String> args) {
if (noTimestamp) {
messages.error("doclet.Option_conflict", "--date", "-notimestamp");
return false;
}
String arg = args.get(0);
try {
date = ZonedDateTime.parse(arg, DateTimeFormatter.ISO_ZONED_DATE_TIME);
if (date.isBefore(DATE_MIN) || date.isAfter(DATE_MAX)) {
messages.error("doclet.Option_date_out_of_range", arg);
return false;
}
return true;
} catch (DateTimeParseException x) {
messages.error("doclet.Option_date_not_valid", arg);
return false;
}
}
},

new Option(resources, "-docencoding", 1) {
@Override
public boolean process(String opt, List<String> args) {
@@ -471,6 +512,10 @@ public boolean process(String opt, List<String> args) {
@Override
public boolean process(String opt, List<String> args) {
noTimestamp = true;
if (date != null) {
messages.error("doclet.Option_conflict", "--date", "-notimestamp");
return false;
}
return true;
}
},
@@ -739,6 +784,13 @@ LinkedHashSet<List<String>> customTagStrs() {
return customTagStrs;
}

/**
* Argument for command-line option {@code --date}.
*/
public ZonedDateTime date() {
return date;
}

/**
* Argument for command-line option {@code -d}.
* Destination directory name, in which doclet will generate the entire

1 comment on commit 96d0df7

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on 96d0df7 Jan 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.