Skip to content
Permalink
Browse files
[NO ISSUE][HYR][LIC] Configurable multiple LICENSE/NOTICE handling
- += license.onMultipleEmbedded[License|Notice] flag, with gav:[concat|first] values
- 'concat' takes the contents of all LICENSE/NOTICE files, and concatenates them
  with delimiters indicating the source of each content
- 'first' selects the first match encountered in the 'jar'

The default behavior without flag is 'concat', with a WARNING emitted

Change-Id: I0cd5a008f71f80ac99eaf29f1e286eb222640480
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/14104
Reviewed-by: Michael Blow <mblow@apache.org>
Reviewed-by: Hussain Towaileb <hussainht@gmail.com>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Michael Blow <mblow@apache.org>
  • Loading branch information
mblow committed Nov 17, 2021
1 parent ded5f56 commit 46e830fddbefd652f6242a6c786e436edfc35e5a
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 18 deletions.
@@ -18,11 +18,15 @@
*/
package org.apache.hyracks.maven.license;

import static org.apache.hyracks.maven.license.GenerateFileMojo.EmbeddedArtifact.LICENSE;
import static org.apache.hyracks.maven.license.GenerateFileMojo.EmbeddedArtifact.NOTICE;
import static org.apache.hyracks.maven.license.ProjectFlag.ALTERNATE_LICENSE_FILE;
import static org.apache.hyracks.maven.license.ProjectFlag.ALTERNATE_NOTICE_FILE;
import static org.apache.hyracks.maven.license.ProjectFlag.IGNORE_MISSING_EMBEDDED_LICENSE;
import static org.apache.hyracks.maven.license.ProjectFlag.IGNORE_MISSING_EMBEDDED_NOTICE;
import static org.apache.hyracks.maven.license.ProjectFlag.IGNORE_NOTICE_OVERRIDE;
import static org.apache.hyracks.maven.license.ProjectFlag.ON_MULTIPLE_EMBEDDED_LICENSE;
import static org.apache.hyracks.maven.license.ProjectFlag.ON_MULTIPLE_EMBEDDED_NOTICE;

import java.io.File;
import java.io.FileOutputStream;
@@ -334,26 +338,55 @@ private void prependSourcePointerToNotice(Project project) {
}
}

enum EmbeddedArtifact {
NOTICE,
LICENSE
}

private void resolveNoticeFiles() throws MojoExecutionException, IOException {
// TODO(mblow): this will match *any* NOTICE[.(txt|md)] file located within the artifact-
// this seems way too liberal
resolveArtifactFiles("NOTICE", IGNORE_MISSING_EMBEDDED_NOTICE, ALTERNATE_NOTICE_FILE,
entry -> entry.getName().matches("(.*/|^)" + "NOTICE" + "(.(txt|md))?"), Project::setNoticeText,
text -> stripFoundationAssertionFromNotices ? FOUNDATION_PATTERN.matcher(text).replaceAll("") : text);
resolveArtifactFiles(NOTICE);
}

private void resolveLicenseFiles() throws MojoExecutionException, IOException {
// TODO(mblow): this will match *any* LICENSE[.(txt|md)] file located within the artifact-
// this seems way too liberal
resolveArtifactFiles("LICENSE", IGNORE_MISSING_EMBEDDED_LICENSE, ALTERNATE_LICENSE_FILE,
entry -> entry.getName().matches("(.*/|^)" + "LICENSE" + "(.(txt|md))?"), Project::setLicenseText,
UnaryOperator.identity());
resolveArtifactFiles(LICENSE);
}

private void resolveArtifactFiles(final String name, final ProjectFlag ignoreFlag,
final ProjectFlag alternateFilenameFlag, final Predicate<JarEntry> filter,
final BiConsumer<Project, String> consumer, final UnaryOperator<String> contentTransformer)
throws MojoExecutionException, IOException {
private void resolveArtifactFiles(final EmbeddedArtifact artifact) throws MojoExecutionException, IOException {
final String name;
final ProjectFlag ignoreFlag;
final ProjectFlag alternateFilenameFlag;
final ProjectFlag onMultipleFlag;
final Predicate<JarEntry> filter;
final BiConsumer<Project, String> consumer;
final UnaryOperator<String> contentTransformer;

switch (artifact) {
case NOTICE:
name = "NOTICE";
ignoreFlag = IGNORE_MISSING_EMBEDDED_NOTICE;
alternateFilenameFlag = ALTERNATE_NOTICE_FILE;
onMultipleFlag = ON_MULTIPLE_EMBEDDED_NOTICE;
// TODO(mblow): this will match *any* NOTICE[.(txt|md)] file located within the artifact-
// this seems way too liberal
filter = entry -> entry.getName().matches("(.*/|^)" + "NOTICE" + "(.(txt|md))?");
consumer = Project::setNoticeText;
contentTransformer = UnaryOperator.identity();
break;
case LICENSE:
name = "LICENSE";
ignoreFlag = IGNORE_MISSING_EMBEDDED_LICENSE;
alternateFilenameFlag = ALTERNATE_LICENSE_FILE;
onMultipleFlag = ON_MULTIPLE_EMBEDDED_LICENSE;
// TODO(mblow): this will match *any* LICENSE[.(txt|md)] file located within the artifact-
// this seems way too liberal
filter = entry -> entry.getName().matches("(.*/|^)" + "LICENSE" + "(.(txt|md))?");
consumer = Project::setLicenseText;
contentTransformer = stripFoundationAssertionFromNotices
? text -> FOUNDATION_PATTERN.matcher(text).replaceAll("") : UnaryOperator.identity();
break;
default:
throw new IllegalStateException("NYI: " + artifact);
}
for (Project p : getProjects()) {
File artifactFile = new File(p.getArtifactPath());
if (!artifactFile.exists()) {
@@ -371,12 +404,45 @@ private void resolveArtifactFiles(final String name, final ProjectFlag ignoreFla
warnUnlessFlag(p, ignoreFlag, "No " + name + " file found for " + p.gav());
} else {
if (matches.size() > 1) {
getLog().warn("Multiple " + name + " files found for " + p.gav() + ": " + matches.keySet()
+ "; taking first");
// TODO(mblow): duplicate elimination on matches content
warnUnlessFlag(p, onMultipleFlag,
"Multiple " + name + " files found for " + p.gav() + ": " + matches.keySet() + "!");
String onMultiple = (String) getProjectFlag(p.gav(), onMultipleFlag);
if (onMultiple == null) {
onMultiple = "concat";
}
switch (onMultiple.toLowerCase()) {
case "concat":
getLog().info("...concatenating all " + matches.size() + " matches");
StringBuilder content = new StringBuilder();
for (Map.Entry<String, JarEntry> match : matches.entrySet()) {
resolveContent(p, jarFile, match.getValue(), contentTransformer, (p1, text) -> {
content.append("------------ BEGIN <").append(match.getKey())
.append("> ------------\n");
content.append(text);
if (content.charAt(content.length() - 1) != '\n') {
content.append('\n');
}
content.append("------------ END <").append(match.getKey())
.append("> ------------\n");
}, name);
}
consumer.accept(p, content.toString());
break;
case "first":
Map.Entry<String, JarEntry> first = matches.entrySet().iterator().next();
getLog().info("...taking first match: " + first.getKey());
resolveContent(p, jarFile, first.getValue(), contentTransformer, consumer, name);
break;
default:
throw new IllegalArgumentException("unknown value for " + onMultipleFlag.propName()
+ ": " + onMultiple.toLowerCase());
}
} else {
getLog().info(p.gav() + " has " + name + " file: " + matches.keySet());
Map.Entry<String, JarEntry> match = matches.entrySet().iterator().next();
getLog().info(p.gav() + " has " + name + " file: " + match.getKey());
resolveContent(p, jarFile, match.getValue(), contentTransformer, consumer, name);
}
resolveContent(p, jarFile, matches.values().iterator().next(), contentTransformer, consumer, name);
}
}
}
@@ -33,6 +33,8 @@ enum ProjectFlag {
IGNORE_MISSING_EMBEDDED_NOTICE,
IGNORE_LICENSE_OVERRIDE,
IGNORE_NOTICE_OVERRIDE,
ON_MULTIPLE_EMBEDDED_LICENSE,
ON_MULTIPLE_EMBEDDED_NOTICE,
ALTERNATE_LICENSE_FILE,
ALTERNATE_NOTICE_FILE;

@@ -59,6 +61,8 @@ void visit(MavenProject depObj, Properties properties, LicenseMojo licenseMojo)
break;
case ALTERNATE_LICENSE_FILE:
case ALTERNATE_NOTICE_FILE:
case ON_MULTIPLE_EMBEDDED_NOTICE:
case ON_MULTIPLE_EMBEDDED_LICENSE:
for (String spec : StringUtils.split(value, ",")) {
String[] specSplit = StringUtils.split(spec, ":");
if (specSplit.length != 2) {

0 comments on commit 46e830f

Please sign in to comment.