Add MavenRuntime detector.
Support SDKman, MAVEN_HOME, Maven Wrapper and a provided maven home File.
This commit is contained in:
@@ -49,4 +49,5 @@ class BuildConfiguration {
|
||||
|
||||
return new XBProjector(config, Flags.TO_STRING_RENDERS_XML);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,11 @@ import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
@@ -36,7 +40,7 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Value
|
||||
class CommandLine {
|
||||
public class CommandLine {
|
||||
|
||||
@NonNull List<Goal> goals;
|
||||
@NonNull List<Argument> arguments;
|
||||
|
||||
@@ -17,59 +17,32 @@ package org.springframework.data.release.build;
|
||||
|
||||
import static org.springframework.data.release.build.CommandLine.Argument.*;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.apache.commons.io.filefilter.PrefixFileFilter;
|
||||
import org.apache.maven.shared.invoker.DefaultInvocationRequest;
|
||||
import org.apache.maven.shared.invoker.DefaultInvoker;
|
||||
import org.apache.maven.shared.invoker.InvocationRequest;
|
||||
import org.apache.maven.shared.invoker.InvocationResult;
|
||||
import org.apache.maven.shared.invoker.Invoker;
|
||||
import org.apache.maven.shared.invoker.MavenInvocationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import org.springframework.data.release.io.JavaRuntimes;
|
||||
import org.springframework.data.release.io.Workspace;
|
||||
import org.springframework.data.release.model.JavaVersion;
|
||||
import org.springframework.data.release.model.Named;
|
||||
import org.springframework.data.release.model.SupportedProject;
|
||||
import org.springframework.data.release.utils.Logger;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.shell.support.util.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MavenRuntime {
|
||||
public class MavenRuntime extends MavenRuntimeSupport {
|
||||
|
||||
private static final Pattern versionPattern = Pattern.compile("Apache Maven ((\\d\\.?)+) \\(.*\\)");
|
||||
private final Workspace workspace;
|
||||
private final Logger logger;
|
||||
private final MavenProperties properties;
|
||||
private final JavaRuntimes.JdkInstallation jdk;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MavenRuntime} for the given {@link Workspace} and Maven home.
|
||||
@@ -78,82 +51,24 @@ public class MavenRuntime {
|
||||
* @param logger must not be {@literal null}.
|
||||
* @param properties must not be {@literal null}.
|
||||
*/
|
||||
@Autowired
|
||||
public MavenRuntime(Workspace workspace, Logger logger, MavenProperties properties) {
|
||||
this(workspace, logger, properties, JavaVersion.VERSION_1_8);
|
||||
public MavenRuntime(Workspace workspace, Logger logger, MavenRuntimes.MavenInstallation mavenInstallation,
|
||||
MavenProperties properties) {
|
||||
this(workspace, logger, mavenInstallation.getHome(), properties, JavaVersion.VERSION_1_8);
|
||||
}
|
||||
|
||||
private MavenRuntime(Workspace workspace, Logger logger, MavenProperties properties,
|
||||
private MavenRuntime(Workspace workspace, Logger logger, File mavenHome, MavenProperties properties,
|
||||
JavaVersion requiredJavaVersion) {
|
||||
|
||||
super(mavenHome, properties.getLocalRepository(),
|
||||
JavaRuntimes.Selector.from(requiredJavaVersion).notGraalVM().getRequiredJdkInstallation());
|
||||
this.workspace = workspace;
|
||||
this.logger = logger;
|
||||
this.properties = properties;
|
||||
this.jdk = JavaRuntimes.Selector.from(requiredJavaVersion).notGraalVM().getRequiredJdkInstallation();
|
||||
logger.log("Maven", "Using" + jdk + " as default Java Runtime");
|
||||
logger.log("Maven", "Using " + getJdk() + " as default Java Runtime");
|
||||
}
|
||||
|
||||
public MavenRuntime withJavaVersion(JavaVersion javaVersion) {
|
||||
return new MavenRuntime(workspace, logger, properties, javaVersion);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public String getVersion() throws IllegalStateException {
|
||||
|
||||
String version = detectBuildPropertiesVersion();
|
||||
|
||||
return version != null ? version : runVersionCommand();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SneakyThrows
|
||||
private String detectBuildPropertiesVersion() {
|
||||
|
||||
File libs = new File(properties.getMavenHome(), "lib");
|
||||
File[] files = libs.listFiles((FileFilter) new PrefixFileFilter("maven-core-"));
|
||||
|
||||
if (files == null || files.length != 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try (ZipFile zipFile = new ZipFile(files[0])) {
|
||||
|
||||
ZipEntry entry = zipFile.getEntry("org/apache/maven/messages/build.properties");
|
||||
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Properties properties = new Properties();
|
||||
try (InputStream inputStream = zipFile.getInputStream(entry)) {
|
||||
properties.load(inputStream);
|
||||
}
|
||||
|
||||
return properties.getProperty("version");
|
||||
}
|
||||
}
|
||||
|
||||
private String runVersionCommand() throws MavenInvocationException {
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Invoker invoker = new DefaultInvoker();
|
||||
invoker.setMavenHome(properties.getMavenHome());
|
||||
invoker.setErrorHandler(builder::append);
|
||||
invoker.setOutputHandler(builder::append);
|
||||
|
||||
doWithMaven(invoker, mvn -> {
|
||||
mvn.setShowVersion(true);
|
||||
mvn.setGoals(Collections.emptyList());
|
||||
});
|
||||
|
||||
Matcher matcher = versionPattern.matcher(builder);
|
||||
boolean foundVersion = matcher.find();
|
||||
|
||||
if (!foundVersion) {
|
||||
throw new IllegalStateException("Cannot determine Maven Version: " + builder);
|
||||
}
|
||||
|
||||
return matcher.group(1);
|
||||
return new MavenRuntime(workspace, logger, getMavenHome(), properties, javaVersion);
|
||||
}
|
||||
|
||||
public MavenInvocationResult execute(SupportedProject project, CommandLine arguments) {
|
||||
@@ -163,14 +78,14 @@ public class MavenRuntime {
|
||||
try (MavenLogger mavenLogger = getLogger(project, arguments.getGoals())) {
|
||||
|
||||
Invoker invoker = new DefaultInvoker();
|
||||
invoker.setMavenHome(properties.getMavenHome());
|
||||
invoker.setMavenHome(getMavenHome());
|
||||
invoker.setOutputHandler(mavenLogger::info);
|
||||
invoker.setErrorHandler(mavenLogger::warn);
|
||||
|
||||
InvocationResult result = doWithMaven(invoker, mvn -> {
|
||||
|
||||
mvn.setBaseDirectory(workspace.getProjectDirectory(project));
|
||||
mavenLogger.info(String.format("Java Home: %s", jdk));
|
||||
mavenLogger.info(String.format("Java Home: %s", getJavaHome()));
|
||||
mavenLogger.info(String.format("Executing: mvn %s", arguments));
|
||||
|
||||
CommandLine disabledGradleBuildCache = arguments.and(arg("gradle.cache.local.enabled=false"))
|
||||
@@ -198,31 +113,8 @@ public class MavenRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
private InvocationResult doWithMaven(Invoker invoker, Consumer<InvocationRequest> mvn)
|
||||
throws MavenInvocationException {
|
||||
|
||||
File localRepository = properties.getLocalRepository();
|
||||
|
||||
if (localRepository != null) {
|
||||
invoker.setLocalRepositoryDirectory(localRepository);
|
||||
}
|
||||
|
||||
File javaHome = getJavaHome();
|
||||
InvocationRequest request = new DefaultInvocationRequest();
|
||||
request.setJavaHome(javaHome);
|
||||
request.setShellEnvironmentInherited(true);
|
||||
request.setBatchMode(true);
|
||||
|
||||
mvn.accept(request);
|
||||
|
||||
return invoker.execute(request);
|
||||
}
|
||||
|
||||
private File getJavaHome() {
|
||||
return jdk.getHome().getAbsoluteFile();
|
||||
}
|
||||
|
||||
private MavenLogger getLogger(Named project, List<CommandLine.Goal> goals) {
|
||||
@Override
|
||||
MavenLogger getLogger(Named project, List<CommandLine.Goal> goals) {
|
||||
|
||||
if (this.properties.isConsoleLogger()) {
|
||||
return new SlfLogger(log, project);
|
||||
@@ -231,114 +123,4 @@ public class MavenRuntime {
|
||||
return new FileLogger(log, project, this.workspace.getLogsDirectory(), goals);
|
||||
}
|
||||
|
||||
public static class MavenInvocationResult {
|
||||
|
||||
private final List<String> log = new ArrayList<>();
|
||||
|
||||
public List<String> getLog() {
|
||||
return log;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maven Logging Forwarder.
|
||||
*/
|
||||
interface MavenLogger extends Closeable {
|
||||
|
||||
void info(String message);
|
||||
|
||||
void warn(String message);
|
||||
|
||||
List<String> getLines();
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
static class SlfLogger implements MavenLogger {
|
||||
|
||||
private final org.slf4j.Logger logger;
|
||||
private final String logPrefix;
|
||||
private final List<String> contents;
|
||||
|
||||
SlfLogger(org.slf4j.Logger logger, Named project) {
|
||||
this.logger = logger;
|
||||
this.logPrefix = StringUtils.padRight(project.getName(), 10);
|
||||
this.contents = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String message) {
|
||||
String msg = logPrefix + ": " + message;
|
||||
contents.add(msg);
|
||||
logger.info(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message) {
|
||||
String msg = logPrefix + ": " + message;
|
||||
contents.add(msg);
|
||||
logger.warn(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLines() {
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
static class FileLogger implements MavenLogger {
|
||||
|
||||
private final PrintWriter printWriter;
|
||||
private final FileOutputStream outputStream;
|
||||
private final List<String> contents = new ArrayList<>();
|
||||
|
||||
FileLogger(org.slf4j.Logger logger, Named project, File logsDirectory, List<CommandLine.Goal> goals) {
|
||||
|
||||
if (!logsDirectory.exists()) {
|
||||
logsDirectory.mkdirs();
|
||||
}
|
||||
|
||||
String goalNames = goals.stream().map(CommandLine.Goal::getGoal).collect(Collectors.joining("-"));
|
||||
|
||||
String filename = String.format("mvn-%s-%s.log", project.getName(), goalNames).replace(':', '.');
|
||||
|
||||
try {
|
||||
File file = new File(logsDirectory, filename);
|
||||
logger.info("Routing Maven output to " + file.getCanonicalPath());
|
||||
outputStream = new FileOutputStream(file, true);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
printWriter = new PrintWriter(outputStream, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String message) {
|
||||
printWriter.println(message);
|
||||
contents.add(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message) {
|
||||
printWriter.println(message);
|
||||
contents.add(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
printWriter.close();
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLines() {
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright 2015-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.release.build;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.apache.commons.io.filefilter.PrefixFileFilter;
|
||||
import org.apache.maven.shared.invoker.DefaultInvocationRequest;
|
||||
import org.apache.maven.shared.invoker.DefaultInvoker;
|
||||
import org.apache.maven.shared.invoker.InvocationRequest;
|
||||
import org.apache.maven.shared.invoker.InvocationResult;
|
||||
import org.apache.maven.shared.invoker.Invoker;
|
||||
import org.apache.maven.shared.invoker.MavenInvocationException;
|
||||
|
||||
import org.springframework.data.release.io.JavaRuntimes;
|
||||
import org.springframework.data.release.model.Named;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.shell.support.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Slf4j
|
||||
public class MavenRuntimeSupport {
|
||||
|
||||
private static final Pattern versionPattern = Pattern.compile("Apache Maven ((\\d\\.?)+) \\(.*\\)");
|
||||
private final File mavenHome;
|
||||
private final @Nullable File localRepository;
|
||||
private final JavaRuntimes.JdkInstallation jdk;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MavenRuntimeSupport}
|
||||
*
|
||||
* @param mavenHome
|
||||
* @param localRepository
|
||||
* @param jdk
|
||||
*/
|
||||
public MavenRuntimeSupport(File mavenHome, @Nullable File localRepository, JavaRuntimes.JdkInstallation jdk) {
|
||||
this.mavenHome = mavenHome;
|
||||
this.localRepository = localRepository;
|
||||
this.jdk = jdk;
|
||||
}
|
||||
|
||||
JavaRuntimes.JdkInstallation getJdk() {
|
||||
return jdk;
|
||||
}
|
||||
|
||||
File getMavenHome() {
|
||||
return mavenHome;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public String getVersion() throws IllegalStateException {
|
||||
|
||||
String version = detectBuildPropertiesVersion();
|
||||
|
||||
return version != null ? version : runVersionCommand();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SneakyThrows
|
||||
private String detectBuildPropertiesVersion() {
|
||||
|
||||
File libs = new File(mavenHome, "lib");
|
||||
File[] files = libs.listFiles((FileFilter) new PrefixFileFilter("maven-core-"));
|
||||
|
||||
if (files == null || files.length != 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try (ZipFile zipFile = new ZipFile(files[0])) {
|
||||
|
||||
ZipEntry entry = zipFile.getEntry("org/apache/maven/messages/build.properties");
|
||||
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Properties properties = new Properties();
|
||||
try (InputStream inputStream = zipFile.getInputStream(entry)) {
|
||||
properties.load(inputStream);
|
||||
}
|
||||
|
||||
return properties.getProperty("version");
|
||||
}
|
||||
}
|
||||
|
||||
private String runVersionCommand() throws MavenInvocationException {
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Invoker invoker = new DefaultInvoker();
|
||||
invoker.setMavenHome(mavenHome);
|
||||
invoker.setErrorHandler(builder::append);
|
||||
invoker.setOutputHandler(builder::append);
|
||||
|
||||
doWithMaven(invoker, mvn -> {
|
||||
mvn.setShowVersion(true);
|
||||
mvn.setGoals(Collections.emptyList());
|
||||
});
|
||||
|
||||
Matcher matcher = versionPattern.matcher(builder);
|
||||
boolean foundVersion = matcher.find();
|
||||
|
||||
if (!foundVersion) {
|
||||
throw new IllegalStateException("Cannot determine Maven Version: " + builder);
|
||||
}
|
||||
|
||||
return matcher.group(1);
|
||||
}
|
||||
|
||||
protected InvocationResult doWithMaven(Invoker invoker, Consumer<InvocationRequest> mvn)
|
||||
throws MavenInvocationException {
|
||||
|
||||
if (this.localRepository != null) {
|
||||
invoker.setLocalRepositoryDirectory(this.localRepository);
|
||||
}
|
||||
|
||||
File javaHome = getJavaHome();
|
||||
InvocationRequest request = new DefaultInvocationRequest();
|
||||
request.setJavaHome(javaHome);
|
||||
request.setShellEnvironmentInherited(true);
|
||||
request.setBatchMode(true);
|
||||
|
||||
mvn.accept(request);
|
||||
|
||||
return invoker.execute(request);
|
||||
}
|
||||
|
||||
File getJavaHome() {
|
||||
return jdk.getHome().getAbsoluteFile();
|
||||
}
|
||||
|
||||
MavenLogger getLogger(Named project, List<CommandLine.Goal> goals) {
|
||||
return new SlfLogger(log, project);
|
||||
}
|
||||
|
||||
public static class MavenInvocationResult {
|
||||
|
||||
private final List<String> log = new ArrayList<>();
|
||||
|
||||
public List<String> getLog() {
|
||||
return log;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maven Logging Forwarder.
|
||||
*/
|
||||
interface MavenLogger extends Closeable {
|
||||
|
||||
void info(String message);
|
||||
|
||||
void warn(String message);
|
||||
|
||||
List<String> getLines();
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
static class SlfLogger implements MavenLogger {
|
||||
|
||||
private final org.slf4j.Logger logger;
|
||||
private final String logPrefix;
|
||||
private final List<String> contents;
|
||||
|
||||
SlfLogger(org.slf4j.Logger logger, Named project) {
|
||||
this.logger = logger;
|
||||
this.logPrefix = StringUtils.padRight(project.getName(), 10);
|
||||
this.contents = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String message) {
|
||||
String msg = logPrefix + ": " + message;
|
||||
contents.add(msg);
|
||||
logger.info(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message) {
|
||||
String msg = logPrefix + ": " + message;
|
||||
contents.add(msg);
|
||||
logger.warn(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLines() {
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
static class FileLogger implements MavenLogger {
|
||||
|
||||
private final PrintWriter printWriter;
|
||||
private final FileOutputStream outputStream;
|
||||
private final List<String> contents = new ArrayList<>();
|
||||
|
||||
FileLogger(org.slf4j.Logger logger, Named project, File logsDirectory, List<CommandLine.Goal> goals) {
|
||||
|
||||
if (!logsDirectory.exists()) {
|
||||
logsDirectory.mkdirs();
|
||||
}
|
||||
|
||||
String goalNames = goals.stream().map(CommandLine.Goal::getGoal).collect(Collectors.joining("-"));
|
||||
|
||||
String filename = String.format("mvn-%s-%s.log", project.getName(), goalNames).replace(':', '.');
|
||||
|
||||
try {
|
||||
File file = new File(logsDirectory, filename);
|
||||
logger.info("Routing Maven output to " + file.getCanonicalPath());
|
||||
outputStream = new FileOutputStream(file, true);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
printWriter = new PrintWriter(outputStream, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String message) {
|
||||
printWriter.println(message);
|
||||
contents.add(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message) {
|
||||
printWriter.println(message);
|
||||
contents.add(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
printWriter.close();
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLines() {
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,415 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.release.build;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.filefilter.RegexFileFilter;
|
||||
|
||||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.data.release.io.JavaRuntimes;
|
||||
import org.springframework.data.release.model.Version;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Utility to detect a Java runtime version.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MavenRuntimes {
|
||||
|
||||
private static final List<MavenDetector> DETECTORS = Arrays.asList(new SDKmanJdkDetector(),
|
||||
new MavenWrapperDetector(), new MavenHomeEnvironmentDetector());
|
||||
|
||||
private final List<MavenDetector> detectors;
|
||||
|
||||
public MavenRuntimes(MavenDetector... detectors) {
|
||||
this.detectors = new ArrayList<>(DETECTORS);
|
||||
this.detectors.addAll(Arrays.asList(detectors));
|
||||
}
|
||||
|
||||
public static MavenDetector detector(File mavenHome) {
|
||||
return new MavenHomeJdkDetectorSupport(mavenHome);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup a {@link MavenInstallation} by detecting installed Maven installations and applying the {@link Predicate
|
||||
* filter}. Returns the first matching one {@code null}
|
||||
*/
|
||||
@Nullable
|
||||
public MavenInstallation findMavenInstallation(JavaRuntimes.JdkInstallation jdk,
|
||||
Predicate<MavenInstallation> filter) {
|
||||
|
||||
List<MavenInstallation> jdks = getMavenInstallations(jdk);
|
||||
|
||||
return jdks.stream().filter(filter).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup a {@link MavenInstallation} by detecting installed Maven installations and applying the {@link Predicate
|
||||
* filter}. Returns the first matching one or throws {@link NoSuchElementException}.
|
||||
*/
|
||||
public MavenInstallation getRequiredMaven(JavaRuntimes.JdkInstallation jdk, Predicate<MavenInstallation> filter,
|
||||
String runtimeName, Supplier<String> message) {
|
||||
|
||||
List<MavenInstallation> jdks = getMavenInstallations(jdk);
|
||||
|
||||
return jdks.stream().filter(filter).findFirst().orElseThrow(() -> new NoSuchMavenRuntimeException(
|
||||
String.format("%s%nAvailable Maven: %s", message.get(), jdks), jdks, runtimeName));
|
||||
}
|
||||
|
||||
public List<MavenInstallation> getMavenInstallations(JavaRuntimes.JdkInstallation jdk) {
|
||||
return DETECTORS.stream() //
|
||||
.filter(MavenDetector::isAvailable) //
|
||||
.flatMap(it -> it.detect(jdk).stream()) //
|
||||
.sorted() //
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static boolean isDirectory(File file) {
|
||||
return file.exists() && file.isDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maven detection strategy.
|
||||
*/
|
||||
public interface MavenDetector {
|
||||
|
||||
/**
|
||||
* @return {@code true} if the detector strategy is available.
|
||||
*/
|
||||
boolean isAvailable();
|
||||
|
||||
/**
|
||||
* @return a list of Maven installations.
|
||||
*/
|
||||
List<MavenInstallation> detect(JavaRuntimes.JdkInstallation jdk);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector to determine a {@link MavenInstallation}.
|
||||
*/
|
||||
public static class Selector {
|
||||
|
||||
private final MavenDetector[] detectors;
|
||||
private String notFoundMessage;
|
||||
|
||||
private String mavenRuntimeName;
|
||||
private Predicate<MavenInstallation> predicate;
|
||||
|
||||
private Selector(MavenDetector[] detectors) {
|
||||
this.detectors = detectors;
|
||||
}
|
||||
|
||||
public static Selector builder(MavenDetector... detectors) {
|
||||
return new Selector(detectors);
|
||||
}
|
||||
|
||||
public Selector version(Version mavenVersion) {
|
||||
|
||||
return and(it -> it.version.equals(mavenVersion)).name("Maven version " + mavenVersion)
|
||||
.message("Cannot find required Maven version " + mavenVersion);
|
||||
}
|
||||
|
||||
public Selector and(Predicate<MavenInstallation> predicate) {
|
||||
this.predicate = this.predicate == null ? predicate : this.predicate.and(predicate);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Selector message(String notFoundMessage) {
|
||||
this.notFoundMessage = notFoundMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Selector name(String mavenRuntimeName) {
|
||||
this.mavenRuntimeName = mavenRuntimeName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MavenInstallation getRequiredMavenInstallation(JavaRuntimes.JdkInstallation jdk) {
|
||||
return new MavenRuntimes(detectors).getRequiredMaven(jdk, predicate, mavenRuntimeName, () -> notFoundMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Detector using the SDKman utility storing Java installations in {@code ~/.sdkman/candidates/maven}.
|
||||
*/
|
||||
static class SDKmanJdkDetector implements MavenDetector {
|
||||
|
||||
private static final File sdkManMavenHome;
|
||||
|
||||
private static final Pattern CANDIDATE = Pattern.compile("(\\d+[\\.\\d+]+)");
|
||||
|
||||
static {
|
||||
|
||||
if (System.getenv().containsKey("SDKMAN_CANDIDATES_DIR")) {
|
||||
sdkManMavenHome = new File(System.getenv().get("SDKMAN_CANDIDATES_DIR"), "maven");
|
||||
} else if (System.getenv().containsKey("SDKMAN_DIR")) {
|
||||
sdkManMavenHome = new File(System.getenv().get("SDKMAN_DIR"), "candidates/maven");
|
||||
} else {
|
||||
sdkManMavenHome = new File(FileUtils.getUserDirectoryPath(), ".sdkman/candidates/maven");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return isDirectory(sdkManMavenHome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MavenInstallation> detect(JavaRuntimes.JdkInstallation jdk) {
|
||||
|
||||
File[] files = sdkManMavenHome.listFiles((FileFilter) new RegexFileFilter(CANDIDATE));
|
||||
|
||||
return Arrays.stream(files).map(it -> {
|
||||
|
||||
Matcher matcher = CANDIDATE.matcher(it.getName());
|
||||
if (!matcher.find()) {
|
||||
throw new IllegalArgumentException("Cannot determine Maven version number from SDKman candidate name "
|
||||
+ it.getName() + ". This should not happen in an ideal world, check the CANDIDATE regex.");
|
||||
}
|
||||
|
||||
String candidateVersion = matcher.group(1);
|
||||
Version version = Version.parse(candidateVersion);
|
||||
|
||||
return new MavenInstallation(version, it);
|
||||
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Detector Maven wrapper installations in {@code ~/.m2/wrapper/dists}.
|
||||
*/
|
||||
static class MavenWrapperDetector implements MavenDetector {
|
||||
|
||||
private static final Pattern CANDIDATE = Pattern.compile("apache-maven-((:?\\d+(:?\\.\\d+)*)(:?_+\\d+)?)-bin");
|
||||
|
||||
private static final String userHome = System.getProperty("user.home");
|
||||
private static final File dists = new File(userHome, ".m2/wrapper/dists");
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return isDirectory(dists);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MavenInstallation> detect(JavaRuntimes.JdkInstallation jdk) {
|
||||
|
||||
File[] files = dists.listFiles((FileFilter) new RegexFileFilter(CANDIDATE));
|
||||
|
||||
class WrapperCandidate {
|
||||
|
||||
final File home;
|
||||
final File hash;
|
||||
final File realHome;
|
||||
final Version version;
|
||||
|
||||
public WrapperCandidate(File home, File hash, Version version, File realHome) {
|
||||
this.home = home;
|
||||
this.hash = hash;
|
||||
this.realHome = realHome;
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
return Arrays.stream(files).map(it -> {
|
||||
|
||||
File[] hashes = it.listFiles();
|
||||
File hash = hashes != null && hashes.length == 1 ? hashes[0] : null;
|
||||
|
||||
Matcher matcher = CANDIDATE.matcher(it.getName());
|
||||
if (!matcher.find()) {
|
||||
throw new IllegalArgumentException("Cannot determine Maven version number from Maven Wrapper candidate name "
|
||||
+ it.getName() + ". This should not happen in an ideal world, check the CANDIDATE regex.");
|
||||
}
|
||||
String candidateVersion = matcher.group(1);
|
||||
Version version = Version.parse(candidateVersion);
|
||||
|
||||
return new WrapperCandidate(it, hash, version, hash != null ? new File(hash, "apache-maven-" + version) : null);
|
||||
|
||||
}).filter(it -> {
|
||||
|
||||
if (it.hash == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isDirectory(it.realHome);
|
||||
}).map(it -> new MavenInstallation(it.version, it.realHome)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Detector using the {@code java.home} system property.
|
||||
*/
|
||||
static class MavenHomeEnvironmentDetector implements MavenDetector {
|
||||
|
||||
private static final String maven_home_property = System.getProperty("maven.home");
|
||||
private static final @Nullable MavenHomeJdkDetectorSupport mavenHome = StringUtils.hasText(maven_home_property)
|
||||
? new MavenHomeJdkDetectorSupport(new File(maven_home_property))
|
||||
: null;
|
||||
private static final String MAVEN_HOME_ENV = System.getenv("MAVEN_HOME");
|
||||
private static final @Nullable MavenHomeJdkDetectorSupport MAVEN_HOME = StringUtils.hasText(MAVEN_HOME_ENV)
|
||||
? new MavenHomeJdkDetectorSupport(new File(MAVEN_HOME_ENV))
|
||||
: null;
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return hasMavenHomeProperty() || hasMavenHomeEnv();
|
||||
}
|
||||
|
||||
private boolean hasMavenHomeProperty() {
|
||||
return StringUtils.hasText(maven_home_property) && mavenHome != null;
|
||||
}
|
||||
|
||||
private boolean hasMavenHomeEnv() {
|
||||
return StringUtils.hasText(MAVEN_HOME_ENV) && MAVEN_HOME != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MavenInstallation> detect(JavaRuntimes.JdkInstallation jdk) {
|
||||
|
||||
List<MavenInstallation> installations = new ArrayList<>();
|
||||
|
||||
if (hasMavenHomeProperty()) {
|
||||
installations.addAll(mavenHome.detect(jdk));
|
||||
}
|
||||
|
||||
if (hasMavenHomeEnv()) {
|
||||
installations.addAll(MAVEN_HOME.detect(jdk));
|
||||
}
|
||||
|
||||
return installations;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detector using a Maven Home directory.
|
||||
*/
|
||||
static class MavenHomeJdkDetectorSupport implements MavenDetector {
|
||||
|
||||
private final File mavenHome;
|
||||
|
||||
public MavenHomeJdkDetectorSupport(File mavenHome) {
|
||||
this.mavenHome = mavenHome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return mavenHome != null && isDirectory(mavenHome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MavenInstallation> detect(JavaRuntimes.JdkInstallation jdk) {
|
||||
|
||||
SimpleMavenRuntime mavenRuntime = new SimpleMavenRuntime(mavenHome, jdk);
|
||||
return Collections.singletonList(new MavenInstallation(Version.parse(mavenRuntime.getVersion()), mavenHome));
|
||||
}
|
||||
}
|
||||
|
||||
@Value
|
||||
public static class MavenInstallation implements Comparable<MavenInstallation> {
|
||||
|
||||
Version version;
|
||||
File home;
|
||||
|
||||
@Override
|
||||
public int compareTo(MavenInstallation o) {
|
||||
return this.version.compareTo(o.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Version " + version + " at " + home;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NoSuchMavenRuntimeException extends NoSuchElementException {
|
||||
|
||||
private final List<MavenInstallation> installations;
|
||||
|
||||
private final String requiredMavenVersion;
|
||||
|
||||
public NoSuchMavenRuntimeException(String message, List<MavenInstallation> installations,
|
||||
String requiredMavenVersion) {
|
||||
super(message);
|
||||
this.installations = installations;
|
||||
this.requiredMavenVersion = requiredMavenVersion;
|
||||
}
|
||||
|
||||
public List<MavenInstallation> getInstallations() {
|
||||
return installations;
|
||||
}
|
||||
|
||||
public String getRequiredMavenVersion() {
|
||||
return requiredMavenVersion;
|
||||
}
|
||||
}
|
||||
|
||||
static class NoSuchMavenRuntimeExceptionFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMavenRuntimeException> {
|
||||
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure, NoSuchMavenRuntimeException cause) {
|
||||
|
||||
String action = " Make sure to install %s using your platform installation method or SDKman.%n%n"
|
||||
+ " Detected Maven Runtimes are: %n" + "%s";
|
||||
|
||||
StringBuilder detectedRuntimes = new StringBuilder();
|
||||
|
||||
for (MavenInstallation installation : cause.getInstallations()) {
|
||||
detectedRuntimes.append(String.format(" - %-10s %s%n", installation.getVersion(), installation.getHome()));
|
||||
}
|
||||
|
||||
return new FailureAnalysis("⚠️ A required Maven version was not found: " + cause.getRequiredMavenVersion(),
|
||||
String.format(action, cause.getRequiredMavenVersion(), detectedRuntimes), cause);
|
||||
}
|
||||
}
|
||||
|
||||
static class SimpleMavenRuntime extends MavenRuntimeSupport {
|
||||
|
||||
/**
|
||||
* Creates a new {@link MavenRuntimeSupport}
|
||||
*
|
||||
* @param mavenHome
|
||||
* @param jdk
|
||||
*/
|
||||
public SimpleMavenRuntime(File mavenHome, JavaRuntimes.JdkInstallation jdk) {
|
||||
super(mavenHome, null, jdk);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.release.cli;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Getter
|
||||
class InvalidMavenVersionException extends IllegalStateException {
|
||||
|
||||
private final String expectedVersion;
|
||||
private final String actualVersion;
|
||||
|
||||
private final File home;
|
||||
|
||||
public InvalidMavenVersionException(String expectedVersion, String installedVersion, File home) {
|
||||
super(String.format("Invalid Maven version: Expected %s, found version %s", expectedVersion, installedVersion));
|
||||
this.expectedVersion = expectedVersion;
|
||||
this.actualVersion = installedVersion;
|
||||
this.home = home;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.release.cli;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
@@ -25,7 +27,12 @@ import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.release.build.MavenProperties;
|
||||
import org.springframework.data.release.build.MavenRuntime;
|
||||
import org.springframework.data.release.build.MavenRuntimes;
|
||||
import org.springframework.data.release.io.JavaRuntimes;
|
||||
import org.springframework.data.release.io.Workspace;
|
||||
import org.springframework.data.release.model.JavaVersion;
|
||||
import org.springframework.data.release.utils.Logger;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Configuration to verify build infrastructure.
|
||||
@@ -33,10 +40,14 @@ import org.springframework.data.release.utils.Logger;
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
class JavaToolingConfiguration {
|
||||
|
||||
private static final Resource javaTools = new FileSystemResource("ci/java-tools.properties");
|
||||
|
||||
private final Workspace workspace;
|
||||
private final Logger logger;
|
||||
|
||||
@Bean
|
||||
PropertiesFactoryBean javaTools() {
|
||||
|
||||
@@ -51,8 +62,50 @@ class JavaToolingConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
JavaToolingVerifier verifier(@Qualifier("javaTools") Properties javaTools, MavenRuntime mavenRuntime,
|
||||
MavenProperties mavenProperties, Logger logger) {
|
||||
return new JavaToolingVerifier(javaTools, mavenRuntime, mavenProperties, logger);
|
||||
JavaVersions javaVersions(@Qualifier("javaTools") Properties javaTools) {
|
||||
|
||||
JavaVersions javaVersions = new JavaVersions(JavaVersions.parse(javaTools));
|
||||
|
||||
logger.log("JavaTooling", "🕵️ Checking presence of JDKs %s…",
|
||||
StringUtils.collectionToDelimitedString(javaVersions.getExpectedVersions(), ", "));
|
||||
|
||||
for (String jdk : javaVersions.getExpectedVersions()) {
|
||||
|
||||
JavaVersion javaVersion = JavaVersion.of(jdk.trim());
|
||||
|
||||
JavaRuntimes.JdkInstallation jdkInstallation = javaVersions.getInstallation(javaVersion);
|
||||
logger.log("JavaTooling", "✅ Found %s by %s", javaVersion.getName(), jdkInstallation.getImplementor());
|
||||
}
|
||||
|
||||
return javaVersions;
|
||||
}
|
||||
|
||||
@Bean
|
||||
MavenVersion mavenVersion(@Qualifier("javaTools") Properties javaTools) {
|
||||
return MavenVersion.parse(javaTools);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MavenRuntime mavenRuntime(JavaVersions javaVersions, MavenVersion mavenVersion, MavenProperties properties) {
|
||||
|
||||
logger.log("JavaTooling", "🕵️ Checking presence of Maven %s…", mavenVersion.getExpectedVersion());
|
||||
|
||||
String firstJdk = javaVersions.getExpectedVersions().get(0);
|
||||
JavaRuntimes.JdkInstallation installation = javaVersions.getInstallation(firstJdk);
|
||||
|
||||
MavenRuntimes.Selector selector;
|
||||
if (properties.getMavenHome() != null) {
|
||||
selector = MavenRuntimes.Selector.builder(MavenRuntimes.detector(properties.getMavenHome()));
|
||||
} else {
|
||||
selector = MavenRuntimes.Selector.builder();
|
||||
}
|
||||
|
||||
MavenRuntimes.MavenInstallation mavenInstallation = selector.version(mavenVersion.getExpectedVersion())
|
||||
.getRequiredMavenInstallation(installation);
|
||||
|
||||
logger.log("JavaTooling", "✅ Found Maven %s", mavenInstallation);
|
||||
|
||||
return new MavenRuntime(workspace, logger, mavenInstallation, properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.release.cli;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.data.release.build.MavenProperties;
|
||||
import org.springframework.data.release.build.MavenRuntime;
|
||||
import org.springframework.data.release.io.JavaRuntimes.JdkInstallation;
|
||||
import org.springframework.data.release.io.JavaRuntimes.Selector;
|
||||
import org.springframework.data.release.model.JavaVersion;
|
||||
import org.springframework.data.release.utils.Logger;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Utility to verify early on that your build environment contains all the required Java and Maven versions.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
class JavaToolingVerifier {
|
||||
|
||||
private final Properties javaTools;
|
||||
|
||||
private final MavenRuntime mavenRuntime;
|
||||
|
||||
private final MavenProperties mavenProperties;
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
@PostConstruct
|
||||
public void verify() {
|
||||
|
||||
String jdksProperty = javaTools.getProperty("jdks");
|
||||
String[] jdks = jdksProperty.split(",");
|
||||
|
||||
logger.log("JavaTooling", "🕵️ Checking presence of JDKs %s…", StringUtils.arrayToDelimitedString(jdks, ", "));
|
||||
|
||||
for (String jdk : jdks) {
|
||||
|
||||
JavaVersion javaVersion = JavaVersion.of(jdk.trim());
|
||||
|
||||
JdkInstallation jdkInstallation = Selector.notGraalVM(javaVersion).getRequiredJdkInstallation();
|
||||
logger.log("JavaTooling", "✅ Found %s by %s", javaVersion.getName(), jdkInstallation.getImplementor());
|
||||
}
|
||||
|
||||
String expectedMavenVersion = javaTools.getProperty("maven");
|
||||
|
||||
logger.log("JavaTooling", "🕵️ Checking presence of Maven %s…", expectedMavenVersion);
|
||||
|
||||
String installedMavenVersion = mavenRuntime.getVersion();
|
||||
if (!expectedMavenVersion.equals(installedMavenVersion)) {
|
||||
throw new InvalidMavenVersionException(expectedMavenVersion, installedMavenVersion,
|
||||
mavenProperties.getMavenHome());
|
||||
}
|
||||
|
||||
logger.log("JavaTooling", "✅ Found Maven %s", installedMavenVersion);
|
||||
}
|
||||
|
||||
static class InvalidMavenVersionExceptionFailureAnalyzer
|
||||
extends AbstractFailureAnalyzer<InvalidMavenVersionException> {
|
||||
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure, InvalidMavenVersionException cause) {
|
||||
|
||||
return new FailureAnalysis(
|
||||
String.format("⚠️ The configured Maven version %s at %s does not match the required version %s.",
|
||||
cause.getActualVersion(), cause.getHome(), cause.getExpectedVersion()),
|
||||
String.format(" Make sure to use Maven %s or update your maven.maven-home property.",
|
||||
cause.getExpectedVersion()),
|
||||
cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.release.cli;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.data.release.io.JavaRuntimes;
|
||||
import org.springframework.data.release.model.JavaVersion;
|
||||
|
||||
/**
|
||||
* Value object to encapsulate expected Java versions.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class JavaVersions {
|
||||
|
||||
private final List<String> expectedVersions;
|
||||
|
||||
public JavaVersions(List<String> expectedVersions) {
|
||||
this.expectedVersions = expectedVersions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the Java versions from the given {@link Properties} at the key {@code jdks}.
|
||||
*
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
public static List<String> parse(Properties properties) {
|
||||
|
||||
String jdksProperty = properties.getProperty("jdks");
|
||||
return Arrays.asList(jdksProperty.split(","));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the required Java Installation for the given {@code version}.
|
||||
*
|
||||
* @param version
|
||||
* @return
|
||||
*/
|
||||
public JavaRuntimes.JdkInstallation getInstallation(String version) {
|
||||
return getInstallation(JavaVersion.of(version.trim()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the required Java Installation for the given {@link JavaVersion}.
|
||||
*
|
||||
* @param version
|
||||
* @return
|
||||
*/
|
||||
public JavaRuntimes.JdkInstallation getInstallation(JavaVersion version) {
|
||||
return JavaRuntimes.Selector.notGraalVM(version).getRequiredJdkInstallation();
|
||||
}
|
||||
|
||||
public List<String> getExpectedVersions() {
|
||||
return this.expectedVersions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.release.cli;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.data.release.model.Version;
|
||||
|
||||
/**
|
||||
* Value object for a Maven version.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Value(staticConstructor = "of")
|
||||
class MavenVersion {
|
||||
|
||||
String expectedVersion;
|
||||
|
||||
/**
|
||||
* Parse the Maven version from the given {@link Properties} at the key {@code maven}.
|
||||
*
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
public static MavenVersion parse(Properties properties) {
|
||||
return of(properties.getProperty("maven"));
|
||||
}
|
||||
|
||||
public Version getExpectedVersion() {
|
||||
return Version.parse(this.expectedVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return expectedVersion;
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
org.springframework.boot.diagnostics.FailureAnalyzer=org.springframework.data.release.io.JavaRuntimes$NoSuchJavaRuntimeExceptionFailureAnalyzer,\
|
||||
org.springframework.data.release.cli.JavaToolingVerifier.InvalidMavenVersionExceptionFailureAnalyzer
|
||||
org.springframework.data.release.cli.JavaToolingVerifier.InvalidMavenVersionExceptionFailureAnalyzer,\
|
||||
org.springframework.data.release.build.MavenRuntimes$NoSuchMavenRuntimeExceptionFailureAnalyzer
|
||||
|
||||
Reference in New Issue
Block a user