8259530: Generated docs contain MIT/GPL-licenced works without reproducing the licence
Reviewed-by: prappo
This commit is contained in:
parent
d46a2c8ecf
commit
e9f3e325c2
@ -25,6 +25,13 @@
|
||||
|
||||
package jdk.javadoc.internal.doclets.formats.html;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
@ -285,6 +292,8 @@ public class HtmlDoclet extends AbstractDoclet {
|
||||
f = DocFile.createFileForOutput(configuration, DocPaths.JQUERY_OVERRIDES_CSS);
|
||||
f.copyResource(DOCLET_RESOURCES.resolve(DocPaths.JQUERY_OVERRIDES_CSS), true, true);
|
||||
}
|
||||
|
||||
copyLegalFiles(options.createIndex());
|
||||
}
|
||||
|
||||
private void copyJqueryFiles() throws DocletException {
|
||||
@ -312,6 +321,49 @@ public class HtmlDoclet extends AbstractDoclet {
|
||||
}
|
||||
}
|
||||
|
||||
private void copyLegalFiles(boolean includeJQuery) throws DocletException {
|
||||
Path legalNoticesDir;
|
||||
String legalNotices = configuration.getOptions().legalNotices();
|
||||
switch (legalNotices) {
|
||||
case "", "default" -> {
|
||||
Path javaHome = Path.of(System.getProperty("java.home"));
|
||||
legalNoticesDir = javaHome.resolve("legal").resolve(getClass().getModule().getName());
|
||||
}
|
||||
|
||||
case "none" -> {
|
||||
return;
|
||||
}
|
||||
|
||||
default -> {
|
||||
try {
|
||||
legalNoticesDir = Path.of(legalNotices);
|
||||
} catch (InvalidPathException e) {
|
||||
messages.error("doclet.Error_invalid_path_for_legal_notices",
|
||||
legalNotices, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Files.exists(legalNoticesDir)) {
|
||||
try (DirectoryStream<Path> ds = Files.newDirectoryStream(legalNoticesDir)) {
|
||||
for (Path entry: ds) {
|
||||
if (!Files.isRegularFile(entry)) {
|
||||
continue;
|
||||
}
|
||||
if (entry.getFileName().toString().startsWith("jquery") && !includeJQuery) {
|
||||
continue;
|
||||
}
|
||||
DocPath filePath = DocPaths.LEGAL.resolve(entry.getFileName().toString());
|
||||
DocFile df = DocFile.createFileForOutput(configuration, filePath);
|
||||
df.copyFile(DocFile.createFileForInput(configuration, entry));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
messages.error("doclet.Error_copying_legal_notices", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override // defined by AbstractDoclet
|
||||
protected void generateClassFiles(SortedSet<TypeElement> typeElems, ClassTree classTree)
|
||||
throws DocletException {
|
||||
|
@ -121,6 +121,11 @@ public class HtmlOptions extends BaseOptions {
|
||||
*/
|
||||
private String helpFile = "";
|
||||
|
||||
/**
|
||||
* Argument for command-line option {@code --legal-notices}.
|
||||
*/
|
||||
private String legalNotices = "";
|
||||
|
||||
/**
|
||||
* Argument for command-line option {@code -nodeprecatedlist}.
|
||||
* True if command-line option "-nodeprecatedlist" is used. Default value is
|
||||
@ -265,6 +270,14 @@ public class HtmlOptions extends BaseOptions {
|
||||
}
|
||||
},
|
||||
|
||||
new XOption(resources, "--legal-notices", 1) {
|
||||
@Override
|
||||
public boolean process(String opt, List<String> args) {
|
||||
legalNotices = args.get(0);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
new Option(resources, "-nohelp") {
|
||||
@Override
|
||||
public boolean process(String opt, List<String> args) {
|
||||
@ -600,6 +613,13 @@ public class HtmlOptions extends BaseOptions {
|
||||
return helpFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Argument for command-line option {@code --legal-notices}.
|
||||
*/
|
||||
public String legalNotices() {
|
||||
return legalNotices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Argument for command-line option {@code -nodeprecated}.
|
||||
* True if command-line option "-nodeprecated" is used. Default value is
|
||||
|
@ -353,6 +353,11 @@ doclet.Declared_Using_Preview.SEALED_PERMITS=Sealed Classes
|
||||
doclet.PreviewPlatformLeadingNote={0} is a preview API of the Java platform.
|
||||
doclet.ReflectivePreviewPlatformLeadingNote={0} is a reflective preview API of the Java platform.
|
||||
|
||||
# 0: an exception
|
||||
doclet.Error_copying_legal_notices=Error while copying legal notices: {0}
|
||||
# 0: the path; 1: the detail message for the exception
|
||||
doclet.Error_invalid_path_for_legal_notices=Invalid path ''{0}'' for legal notices: {1}
|
||||
|
||||
# option specifiers
|
||||
doclet.usage.add-stylesheet.parameters=\
|
||||
<file>
|
||||
@ -441,6 +446,11 @@ doclet.usage.group.parameters=\
|
||||
doclet.usage.group.description=\
|
||||
Group specified elements together in overview page
|
||||
|
||||
doclet.usage.legal-notices.parameters=\
|
||||
'default' | 'none' | <directory>
|
||||
doclet.usage.legal-notices.description=\
|
||||
Control legal notices in the generated output
|
||||
|
||||
doclet.usage.nocomment.description=\
|
||||
Suppress description and tags, generate only declarations
|
||||
|
||||
|
@ -32,6 +32,7 @@ import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Path;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@ -66,6 +67,11 @@ public abstract class DocFile {
|
||||
return DocFileFactory.getFactory(configuration).createFileForInput(file);
|
||||
}
|
||||
|
||||
/** Create a DocFile for a file that will be opened for reading. */
|
||||
public static DocFile createFileForInput(BaseConfiguration configuration, Path file) {
|
||||
return DocFileFactory.getFactory(configuration).createFileForInput(file);
|
||||
}
|
||||
|
||||
/** Create a DocFile for a file that will be opened for writing. */
|
||||
public static DocFile createFileForOutput(BaseConfiguration configuration, DocPath path) {
|
||||
return DocFileFactory.getFactory(configuration).createFileForOutput(path);
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package jdk.javadoc.internal.doclets.toolkit.util;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileManager.Location;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
@ -78,6 +79,9 @@ public abstract class DocFileFactory {
|
||||
/** Create a DocFile for a file that will be opened for reading. */
|
||||
abstract DocFile createFileForInput(String file);
|
||||
|
||||
/** Create a DocFile for a file that will be opened for reading. */
|
||||
abstract DocFile createFileForInput(Path file);
|
||||
|
||||
/** Create a DocFile for a file that will be opened for writing. */
|
||||
abstract DocFile createFileForOutput(DocPath path);
|
||||
|
||||
|
@ -100,7 +100,7 @@ public class DocPaths {
|
||||
/** The name of the stylesheet file overriding jQuery UI stylesheet. */
|
||||
public static final DocPath JQUERY_OVERRIDES_CSS = DocPath.create("jquery-ui.overrides.css");
|
||||
|
||||
/** The name of the directory for the jQuery. */
|
||||
/** The name of the directory for the jQuery files. */
|
||||
public static final DocPath JQUERY_FILES = DocPath.create("script-dir");
|
||||
|
||||
/** The name of the default jQuery javascript file. */
|
||||
@ -112,6 +112,9 @@ public class DocPaths {
|
||||
/** The name of the default jQuery UI javascript file. */
|
||||
public static final DocPath JQUERY_UI_JS = DocPath.create("jquery-ui.min.js");
|
||||
|
||||
/** The name of the directory for legal files. */
|
||||
public static final DocPath LEGAL = DocPath.create("legal");
|
||||
|
||||
/** The name of the member search index js file. */
|
||||
public static final DocPath MEMBER_SEARCH_INDEX_JS = DocPath.create("member-search-index.js");
|
||||
|
||||
|
@ -109,6 +109,11 @@ class StandardDocFileFactory extends DocFileFactory {
|
||||
return new StandardDocFile(Paths.get(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocFile createFileForInput(Path file) {
|
||||
return new StandardDocFile(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocFile createFileForOutput(DocPath path) {
|
||||
return new StandardDocFile(DocumentationTool.Location.DOCUMENTATION_OUTPUT, path);
|
||||
@ -140,12 +145,12 @@ class StandardDocFileFactory extends DocFileFactory {
|
||||
private final Path file;
|
||||
|
||||
/** Create a StandardDocFile for a given file. */
|
||||
private StandardDocFile(Path file) {
|
||||
StandardDocFile(Path file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
/** Create a StandardDocFile for a given location and relative path. */
|
||||
private StandardDocFile(Location location, DocPath path) {
|
||||
StandardDocFile(Location location, DocPath path) {
|
||||
super(location, path);
|
||||
Assert.check(location == DocumentationTool.Location.DOCUMENTATION_OUTPUT);
|
||||
this.file = newFile(getDestDir(), path.getPath());
|
||||
|
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8259530
|
||||
* @summary Generated docs contain MIT/GPL-licenced works without reproducing the licence
|
||||
* @library /tools/lib ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
* @build toolbox.ToolBox javadoc.tester.*
|
||||
* @run main TestLegalNotices
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javadoc.tester.JavadocTester;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
public class TestLegalNotices extends JavadocTester {
|
||||
public static void main(String... args) throws Exception {
|
||||
TestLegalNotices tester = new TestLegalNotices();
|
||||
tester.runTests(m -> new Object[]{Path.of(m.getName())});
|
||||
}
|
||||
|
||||
private final ToolBox tb = new ToolBox();
|
||||
|
||||
enum OptionKind {
|
||||
UNSET, DEFAULT, NONE, DIR
|
||||
}
|
||||
|
||||
enum IndexKind {
|
||||
INDEX, NO_INDEX
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCombo(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, "package p; public class C { }");
|
||||
Path legal = base.resolve("toy-legal");
|
||||
tb.writeFile(legal.resolve("TOY-LICENSE"), "This is a demo license.");
|
||||
|
||||
for (var optionKind : OptionKind.values()) {
|
||||
for (var indexKind : IndexKind.values()) {
|
||||
test(base, src, legal, optionKind, indexKind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test(Path base, Path src, Path legal, OptionKind optionKind, IndexKind indexKind) throws IOException {
|
||||
System.out.println("testing " + optionKind + " " + indexKind);
|
||||
Path out = base.resolve(optionKind + "-" + indexKind).resolve("out");
|
||||
List<String> args = new ArrayList<>();
|
||||
args.addAll(List.of(
|
||||
"-d", out.toString()));
|
||||
|
||||
if (indexKind == IndexKind.NO_INDEX) {
|
||||
args.add("-noindex");
|
||||
}
|
||||
|
||||
args.addAll(List.of(
|
||||
"-Xdoclint:-missing",
|
||||
"--source-path", src.toString(),
|
||||
"p"));
|
||||
|
||||
String value = switch (optionKind) {
|
||||
case UNSET -> null;
|
||||
case DEFAULT -> "default";
|
||||
case NONE -> "none";
|
||||
case DIR -> legal.toString();
|
||||
};
|
||||
if (value != null) {
|
||||
args.addAll(List.of("--legal-notices", value));
|
||||
}
|
||||
javadoc(args.toArray(new String[0]));
|
||||
|
||||
Set<Path> expectFiles = getExpectFiles(optionKind, indexKind, legal);
|
||||
Set<Path> foundFiles = listFiles(out.resolve("legal"));
|
||||
|
||||
checking("Checking legal notice files");
|
||||
super.out.println("Expected: " + expectFiles);
|
||||
super.out.println(" Found: " + foundFiles);
|
||||
if (foundFiles.equals(expectFiles)) {
|
||||
passed("Found all expected files");
|
||||
}
|
||||
}
|
||||
|
||||
Set<Path> getExpectFiles(OptionKind optionKind, IndexKind indexKind, Path legal) throws IOException {
|
||||
switch (optionKind) {
|
||||
case UNSET, DEFAULT -> {
|
||||
Path javaHome = Path.of(System.getProperty("java.home"));
|
||||
Path legal_javadoc = javaHome.resolve("legal").resolve("jdk.javadoc");
|
||||
return listFiles(legal_javadoc, p ->
|
||||
switch (indexKind) {
|
||||
case INDEX -> true;
|
||||
case NO_INDEX -> !p.getFileName().toString().contains("jquery");
|
||||
});
|
||||
}
|
||||
|
||||
case NONE -> {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
case DIR -> {
|
||||
return listFiles(legal);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
Set<Path> listFiles(Path dir) throws IOException {
|
||||
return listFiles(dir, p -> true);
|
||||
}
|
||||
|
||||
Set<Path> listFiles(Path dir, Predicate<Path> filter) throws IOException {
|
||||
if (!Files.exists(dir)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir)) {
|
||||
Set<Path> files = new TreeSet<>();
|
||||
for (Path p : ds) {
|
||||
if (!Files.isDirectory(p) && filter.test(p)) {
|
||||
files.add(p.getFileName());
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
}
|
||||
}
|
@ -173,8 +173,8 @@ public class CheckResourceKeys {
|
||||
// ignore this partial key, tested by usageTests
|
||||
if (ck.equals("main.opt."))
|
||||
continue;
|
||||
// ignore this system property name
|
||||
if (ck.equals("javadoc.internal.show.taglets"))
|
||||
// ignore these system property names
|
||||
if (ck.equals("javadoc.internal.show.taglets") || ck.equals("javadoc.legal-notices"))
|
||||
continue;
|
||||
if (resourceKeys.contains(ck))
|
||||
continue;
|
||||
|
@ -150,7 +150,9 @@ class APITest {
|
||||
missing.removeAll(foundFiles);
|
||||
if (!missing.isEmpty())
|
||||
error("the following files were not found in " + where + ": " + missing);
|
||||
Set<String> unexpected = new TreeSet<String>(foundFiles);
|
||||
Set<String> unexpected = foundFiles.stream()
|
||||
.filter(p -> !p.startsWith("legal"))
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
unexpected.removeAll(expectFiles);
|
||||
if (!unexpected.isEmpty())
|
||||
error("the following unexpected files were found in " + where + ": " + unexpected);
|
||||
|
Loading…
Reference in New Issue
Block a user