From 29d27f73738b95ea89bef62530617f57e9187674 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 10 Jul 2024 09:04:23 +1000 Subject: [PATCH] Fix #265 list licenses (#11993) List licenses in --list-classpath Add SPDX to all our manifests handle License and Licence --- .../java/org/eclipse/jetty/start/Main.java | 101 +++++++++++++++++- pom.xml | 1 + 2 files changed, 97 insertions(+), 5 deletions(-) diff --git a/jetty-core/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java b/jetty-core/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java index c7bf741455ac..636f0540a541 100644 --- a/jetty-core/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java +++ b/jetty-core/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java @@ -29,8 +29,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; import java.util.stream.Collectors; import org.eclipse.jetty.start.Props.Prop; @@ -135,7 +141,7 @@ private void copyInThread(final InputStream in, final OutputStream out) }).start(); } - private void dumpClasspathWithVersions(String name, PrintStream out, Classpath classpath) + private void listClasspath(String name, PrintStream out, Classpath classpath) { StartLog.endStartLog(); out.println(); @@ -154,8 +160,93 @@ private void dumpClasspathWithVersions(String name, PrintStream out, Classpath c int i = 0; for (Path element : classpath.getElements()) { - out.printf("%2d: %24s | %s\n", i++, getVersion(element), baseHome.toShortForm(element)); + String license = getLicenceFromJar(element); + if (license != null && !license.isEmpty()) + out.printf("%2d: %24s | %s | %s\n", i++, getVersion(element), baseHome.toShortForm(element), license); + else + out.printf("%2d: %24s | %s\n", i++, getVersion(element), baseHome.toShortForm(element)); + } + } + + private String getLicenceFromJar(Path jar) + { + if (!Files.exists(jar) || Files.isDirectory(jar) || !Files.isReadable(jar)) + return null; + try + { + try (JarFile jarFile = new JarFile(jar.toFile())) + { + Manifest manifest = jarFile.getManifest(); + if (manifest != null) + { + String spdxLicense = manifest.getMainAttributes().getValue("SPDX-License-Identifier"); + if (spdxLicense != null) + return spdxLicense; + + String bundleLicense = manifest.getMainAttributes().getValue("Bundle-License"); + if (bundleLicense != null) + return bundleLicense; + } + + Optional license = jarFile.stream().filter(Main::isLicenseFile).map(e -> getLicenceFromFile(jarFile, e)).filter(Objects::nonNull).findFirst(); + if (license.isPresent()) + return license.get(); + + } + } + catch (Throwable ignored) + { + } + return null; + } + + private static boolean isLicenseFile(JarEntry entry) + { + String name = entry.getName(); + return name.matches("(?i)^(META-INF/)?LICEN[SC]E.*") || name.matches("(?i)^LICEN[SC]E.*"); + } + + private String getLicenceFromFile(JarFile jarFile, JarEntry entry) + { + try + { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(jarFile.getInputStream(entry)))) + { + String line; + StringBuilder licenseBuilder = new StringBuilder(); + int nonEmptyLines = 0; + + List links = new ArrayList<>(); + + while ((line = reader.readLine()) != null) + { + line = line.trim(); + if (!line.isEmpty()) + { + if (line.contains("SPDX-License-Identifier:")) + return line.substring(line.indexOf(':') + 1).trim(); + + if (line.startsWith("http:") || line.startsWith("https:")) + links.add(line); + + if (nonEmptyLines < 2) + { + licenseBuilder.append(line).append(" "); + nonEmptyLines++; + } + } + } + + if (!links.isEmpty()) + return links.stream().max(Comparator.comparingInt(String::length)).get(); + + return nonEmptyLines > 0 ? licenseBuilder.toString().trim() : null; + } + } + catch (Throwable ignored) + { } + return null; } public BaseHome getBaseHome() @@ -243,7 +334,7 @@ public void listConfig(PrintStream out, StartArgs args) // Dump Jetty Properties jettyEnvironment.dumpProperties(out); // Dump Jetty Classpath - dumpClasspathWithVersions(jettyEnvironment.getName(), out, jettyEnvironment.getClasspath()); + listClasspath(jettyEnvironment.getName(), out, jettyEnvironment.getClasspath()); // Dump Jetty Resolved XMLs jettyEnvironment.dumpActiveXmls(out); @@ -252,7 +343,7 @@ public void listConfig(PrintStream out, StartArgs args) // Dump Properties environment.dumpProperties(out); // Dump Classpath - dumpClasspathWithVersions(environment.getName(), out, environment.getClasspath()); + listClasspath(environment.getName(), out, environment.getClasspath()); // Dump Resolved XMLs environment.dumpActiveXmls(out); } @@ -400,7 +491,7 @@ public void start(StartArgs args) throws IOException, InterruptedException // Show the version information and return if (args.isListClasspath()) { - dumpClasspathWithVersions("Jetty", System.out, classpath); + listClasspath("Jetty", System.out, classpath); } // Show configuration diff --git a/pom.xml b/pom.xml index 233b7873695c..194a8cfea207 100644 --- a/pom.xml +++ b/pom.xml @@ -1413,6 +1413,7 @@ ${project.version} Eclipse Jetty Project + EPL-2.0 OR Apache-2.0 ${jetty.url}