Skip to content

Commit c37ecf0

Browse files
committed
refactor: convert NoticeTask to java
Relates to elastic#34459
1 parent ed817fb commit c37ecf0

File tree

3 files changed

+227
-99
lines changed

3 files changed

+227
-99
lines changed

buildSrc/src/main/groovy/org/elasticsearch/gradle/NoticeTask.groovy

Lines changed: 0 additions & 99 deletions
This file was deleted.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.elasticsearch.gradle;
20+
21+
import java.io.File;
22+
import java.io.IOException;
23+
import java.nio.charset.Charset;
24+
import java.nio.file.Files;
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
import java.util.Map;
28+
import java.util.TreeMap;
29+
30+
import org.gradle.api.DefaultTask;
31+
import org.gradle.api.tasks.InputFile;
32+
import org.gradle.api.tasks.OutputFile;
33+
import org.gradle.api.tasks.TaskAction;
34+
35+
36+
/**
37+
* A task to create a notice file which includes dependencies' notices.
38+
*/
39+
public class NoticeTask extends DefaultTask {
40+
41+
private static final Charset UTF8 = Charset.forName("UTF-8");
42+
@InputFile
43+
private File inputFile = getProject().getRootProject().file("NOTICE.txt");
44+
45+
@OutputFile
46+
private File outputFile = new File(getProject().getBuildDir(), "notices/" + getName() + "/NOTICE.txt");
47+
48+
/**
49+
* Directories to include notices from
50+
*/
51+
private List<File> licensesDirs = new ArrayList<>();
52+
53+
public NoticeTask() {
54+
setDescription("Create a notice file from dependencies");
55+
// Default licenses directory is ${projectDir}/licenses (if it exists)
56+
File licensesDir = new File(getProject().getProjectDir(), "licenses");
57+
if (licensesDir.exists()) {
58+
licensesDirs.add(licensesDir);
59+
}
60+
}
61+
62+
/**
63+
* Add notices from the specified directory.
64+
*/
65+
public void setLicensesDir(File licensesDir) {
66+
licensesDirs.add(licensesDir);
67+
}
68+
69+
public void setInputFile(File inputFile) {
70+
this.inputFile = inputFile;
71+
}
72+
73+
@TaskAction
74+
public void generateNotice() throws IOException {
75+
StringBuilder output = new StringBuilder();
76+
output.append(read(inputFile));
77+
output.append("\n\n");
78+
// This is a map rather than a set so that the sort order is the 3rd
79+
// party component names, unaffected by the full path to the various files
80+
Map<String, File> seen = new TreeMap<>();
81+
for (File licensesDir : licensesDirs) {
82+
File[] files = licensesDir.listFiles((file) -> file.getName().matches(".*-NOTICE\\.txt"));
83+
if (files == null) {
84+
continue;
85+
}
86+
for (File file : files) {
87+
String name = file.getName().substring(0, file.getName().length() - "-NOTICE.txt".length());
88+
if (seen.containsKey(name)) {
89+
File prevFile = seen.get(name);
90+
if (!read(prevFile).equals(read(file))) {
91+
throw new RuntimeException("Two different notices exist for dependency '" +
92+
name + "': " + prevFile + " and " + file);
93+
}
94+
} else {
95+
seen.put(name, file);
96+
}
97+
}
98+
}
99+
for (Map.Entry<String, File> entry : seen.entrySet()) {
100+
String name = entry.getKey();
101+
File file = entry.getValue();
102+
appendFile(file, name, "NOTICE", output);
103+
appendFile(new File(file.getParent(), name + "-LICENSE.txt"), name, "LICENSE", output);
104+
}
105+
outputFile.getParentFile().mkdirs();
106+
outputFile.createNewFile();
107+
write(outputFile, output.toString());
108+
}
109+
110+
private String read(File file) throws IOException {
111+
return new String(Files.readAllBytes(file.toPath()), UTF8);
112+
}
113+
114+
private void write(File file, String content) throws IOException {
115+
Files.write(file.toPath(), content.getBytes(UTF8));
116+
}
117+
118+
private void appendFile(File file, String name, String type, StringBuilder output) throws IOException {
119+
String text = read(file);
120+
if (text.trim().isEmpty()) {
121+
return;
122+
}
123+
output.append("================================================================================\n");
124+
output.append(name).append(" ").append(type).append("\n");
125+
output.append("================================================================================\n");
126+
output.append(text).append("\n\n");
127+
}
128+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package org.elasticsearch.gradle;
2+
3+
import static java.nio.file.Files.readAllBytes;
4+
import static java.nio.file.Files.write;
5+
import static java.util.Collections.singletonMap;
6+
7+
import java.io.File;
8+
import java.io.IOException;
9+
import java.nio.charset.Charset;
10+
import java.nio.file.Path;
11+
12+
import org.elasticsearch.gradle.test.GradleUnitTestCase;
13+
import org.gradle.api.Project;
14+
import org.gradle.internal.impldep.org.junit.rules.ExpectedException;
15+
import org.gradle.internal.impldep.org.junit.rules.TemporaryFolder;
16+
import org.gradle.testfixtures.ProjectBuilder;
17+
import org.junit.Rule;
18+
19+
public class NoticeTaskTests extends GradleUnitTestCase {
20+
21+
private static final Charset UTF8 = Charset.forName("UTF-8");
22+
23+
@Rule
24+
public TemporaryFolder temporaryFolder = new TemporaryFolder();
25+
@Rule
26+
public ExpectedException expectedException = ExpectedException.none();
27+
28+
private Project project;
29+
private NoticeTask task;
30+
31+
private NoticeTask createTask(Project project) {
32+
return (NoticeTask) project.task(singletonMap("type", NoticeTask.class), "noticeTask");
33+
}
34+
35+
private Project createProject() throws IOException {
36+
temporaryFolder.create();
37+
File projectDir = temporaryFolder.newFolder();
38+
return ProjectBuilder.builder().withProjectDir(projectDir).build();
39+
}
40+
41+
42+
public void testGenerateAllNotices() throws Exception {
43+
project = createProject();
44+
task = createTask(project);
45+
Path projectDir = project.getProjectDir().toPath();
46+
createFileIn(projectDir, "NOTICE.txt", "This is\nthe root notice\n");
47+
Path licenseDir = projectDir.resolve("licenseDir");
48+
createFileIn(licenseDir, "myNotice-NOTICE.txt", "This is\nmy notice\n");
49+
createFileIn(licenseDir, "myNotice-LICENSE.txt", "This is\nmy license\n");
50+
task.setLicensesDir(licenseDir.toFile());
51+
52+
task.generateNotice();
53+
54+
Path notice = project.getBuildDir().toPath().resolve("notices").resolve(task.getName()).resolve("NOTICE.txt");
55+
String generatedContent = new String(readAllBytes(notice), UTF8);
56+
String expected = "This is\n" +
57+
"the root notice\n" +
58+
"\n" +
59+
"\n" +
60+
"================================================================================\n" +
61+
"myNotice NOTICE\n" +
62+
"================================================================================\n" +
63+
"This is\n" +
64+
"my notice\n" +
65+
"\n" +
66+
"\n" +
67+
"================================================================================\n" +
68+
"myNotice LICENSE\n" +
69+
"================================================================================\n" +
70+
"This is\n" +
71+
"my license";
72+
assertEquals(expected, generatedContent.trim());
73+
}
74+
75+
public void testShouldFailWhenMultipleNoticeIsPresent() throws Exception {
76+
project = createProject();
77+
task = createTask(project);
78+
Path projectDir = project.getProjectDir().toPath();
79+
createFileIn(projectDir, "NOTICE.txt", "This is\nthe root notice\n");
80+
Path licenseDir = projectDir.resolve("licenseDir");
81+
createFileIn(licenseDir, "myNotice1-NOTICE.txt", "This is\nmy notice\n");
82+
createFileIn(licenseDir, "myNotice1-LICENSE.txt", "This is\nmy notice\n");
83+
createFileIn(licenseDir, "myNotice2-NOTICE.txt", "This is\nmy notice\n");
84+
createFileIn(licenseDir, "myNotice2-LICENSE.txt", "This is\nmy notice\n");
85+
task.setLicensesDir(licenseDir.toFile());
86+
87+
expectedException.expect(RuntimeException.class);
88+
expectedException.expectMessage("Two different notices exist");
89+
90+
task.generateNotice();
91+
}
92+
93+
private void createFileIn(Path parent, String name, String content) throws IOException {
94+
parent.toFile().mkdir();
95+
Path file = parent.resolve(name);
96+
file.toFile().createNewFile();
97+
write(file, content.getBytes(UTF8));
98+
}
99+
}

0 commit comments

Comments
 (0)