#122 - Allow logger re-routing to logfile.

This commit is contained in:
Mark Paluch
2019-07-09 15:04:10 +02:00
parent 242c88d4e4
commit b33d7dc386
7 changed files with 178 additions and 111 deletions

View File

@@ -41,12 +41,11 @@ import org.springframework.data.release.model.Module;
import org.springframework.data.release.model.ModuleIteration; import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Phase; import org.springframework.data.release.model.Phase;
import org.springframework.data.release.model.Project; import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.TrainIteration; import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.ExecutionUtils;
import org.springframework.data.release.utils.Logger; import org.springframework.data.release.utils.Logger;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.xmlbeam.ProjectionFactory; import org.xmlbeam.ProjectionFactory;
import org.xmlbeam.io.XBFileIO; import org.xmlbeam.io.XBFileIO;
@@ -116,7 +115,18 @@ class MavenBuildSystem implements BuildSystem {
logger.log(project, "Triggering distribution build…"); logger.log(project, "Triggering distribution build…");
mvn.execute(project, CommandLine.of(Goal.CLEAN, Goal.DEPLOY, // mvn.execute(project, CommandLine.of(Goal.CLEAN, Goal.DEPLOY, //
SKIP_TESTS, profile("distribute"), Argument.of("-B"))); SKIP_TESTS, profile("distribute"), Argument.of("-B"),
arg("artifactory.server").withValue(properties.getServer().getUri()),
arg("distribution-repository").withValue(properties.getDistributionRepository()),
arg("artifactory.username").withValue(properties.getUsername()),
arg("artifactory.password").withValue(properties.getPassword())));
mvn.execute(project, CommandLine.of(Goal.CLEAN, Goal.DEPLOY, //
SKIP_TESTS, profile("distribute-schema"), Argument.of("-B"),
arg("artifactory.server").withValue(properties.getServer().getUri()),
arg("distribution-repository").withValue(properties.getDistributionRepository()),
arg("artifactory.username").withValue(properties.getUsername()),
arg("artifactory.password").withValue(properties.getPassword())));
logger.log(project, "Successfully finished distribution build!"); logger.log(project, "Successfully finished distribution build!");
@@ -192,36 +202,6 @@ class MavenBuildSystem implements BuildSystem {
return true; return true;
} }
/**
* Triggers building the distribution artifacts for all Maven projects of the given {@link Train}.
*
* @param iteration
* @throws Exception
*/
public void triggerDistributionBuild(TrainIteration iteration) throws Exception {
ExecutionUtils.run(iteration, module -> {
Project project = module.getProject();
if (BUILD.equals(project)) {
return;
}
if (!isMavenProject(project)) {
logger.log(project, "Skipping project as no pom.xml could be found in the working directory!");
return;
}
logger.log(project, "Triggering distribution build…");
mvn.execute(project,
CommandLine.of(Goal.CLEAN, Goal.DEPLOY, ReleaseVersion.of(module).getDistributionProfiles(), SKIP_TESTS));
logger.log(project, "Successfully finished distribution build!");
});
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.data.release.build.BuildSystem#prepareVersion(org.springframework.data.release.model.ModuleIteration, org.springframework.data.release.model.Phase) * @see org.springframework.data.release.build.BuildSystem#prepareVersion(org.springframework.data.release.model.ModuleIteration, org.springframework.data.release.model.Phase)
@@ -388,42 +368,4 @@ class MavenBuildSystem implements BuildSystem {
throw new RuntimeException(o_O); throw new RuntimeException(o_O);
} }
} }
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
private static class ReleaseVersion {
private final ArtifactVersion version;
/**
* Creates a new {@link ReleaseVersion} for the given {@link ModuleIteration}.
*
* @param module must not be {@literal null}.
* @return
*/
public static ReleaseVersion of(ModuleIteration module) {
ArtifactVersion artifactVersion = ArtifactVersion.of(module);
Assert.isTrue(artifactVersion.isMilestoneVersion() || artifactVersion.isReleaseVersion(),
String.format("Given module is not in a fixed version, detected %s!", artifactVersion));
return new ReleaseVersion(ArtifactVersion.of(module));
}
/**
* Returns the Maven profiles to be used during the distribution build.
*
* @return
*/
public Argument getDistributionProfiles() {
if (version.isMilestoneVersion()) {
return profile("distribute", "milestone");
} else if (version.isReleaseVersion()) {
return profile("distribute", "release");
}
throw new IllegalStateException("Should not occur!");
}
}
} }

View File

@@ -27,8 +27,9 @@ import org.springframework.util.Assert;
/** /**
* Maven configuration properties. * Maven configuration properties.
* *
* @author Oliver Gierke * @author Oliver Gierke
* @author Mark Paluch
*/ */
@Slf4j @Slf4j
@Data @Data
@@ -39,11 +40,12 @@ class MavenProperties {
private File mavenHome; private File mavenHome;
private File localRepository; private File localRepository;
private Map<String, String> plugins; private Map<String, String> plugins;
private boolean consoleLogger = true;
/** /**
* Configures the local Maven repository location to use. In case the given folder does not already exists it's * Configures the local Maven repository location to use. In case the given folder does not already exists it's
* created. * created.
* *
* @param localRepository must not be {@literal null} or empty. * @param localRepository must not be {@literal null} or empty.
*/ */
public void setLocalRepository(String localRepository) { public void setLocalRepository(String localRepository) {
@@ -61,7 +63,7 @@ class MavenProperties {
/** /**
* Returns the fully-qualified plugin goal for the given local one. * Returns the fully-qualified plugin goal for the given local one.
* *
* @param goal must not be {@literal null} or empty. * @param goal must not be {@literal null} or empty.
* @return * @return
*/ */

View File

@@ -15,15 +15,22 @@
*/ */
package org.springframework.data.release.build; package org.springframework.data.release.build;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.maven.shared.invoker.DefaultInvocationRequest; import org.apache.maven.shared.invoker.DefaultInvocationRequest;
import org.apache.maven.shared.invoker.DefaultInvoker; import org.apache.maven.shared.invoker.DefaultInvoker;
import org.apache.maven.shared.invoker.InvocationResult; import org.apache.maven.shared.invoker.InvocationResult;
import org.apache.maven.shared.invoker.Invoker; import org.apache.maven.shared.invoker.Invoker;
import org.apache.maven.shared.invoker.MavenInvocationException;
import org.springframework.data.release.io.OsOperations; import org.springframework.data.release.io.OsOperations;
import org.springframework.data.release.io.Workspace; import org.springframework.data.release.io.Workspace;
import org.springframework.data.release.model.Project; import org.springframework.data.release.model.Project;
@@ -62,37 +69,126 @@ class MavenRuntime {
public void execute(Project project, CommandLine arguments) { public void execute(Project project, CommandLine arguments) {
String logPrefix = StringUtils.padRight(project.getName(), 10);
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome(properties.getMavenHome());
invoker.setOutputHandler(line -> log.info(logPrefix + ": " + line));
invoker.setErrorHandler(line -> log.warn(logPrefix + ": " + line));
File localRepository = properties.getLocalRepository();
if (localRepository != null) {
invoker.setLocalRepositoryDirectory(localRepository);
}
DefaultInvocationRequest request = new DefaultInvocationRequest();
request.setJavaHome(os.getJavaHome());
request.setShellEnvironmentInherited(true);
request.setBaseDirectory(workspace.getProjectDirectory(project));
logger.log(project, "Executing mvn %s", arguments.toString()); logger.log(project, "Executing mvn %s", arguments.toString());
request.setGoals(arguments.toCommandLine(it -> properties.getFullyQualifiedPlugin(it.getGoal()))); try (MavenLogger mavenLogger = getLogger(project, arguments.getGoals())) {
try { Invoker invoker = new DefaultInvoker();
invoker.setMavenHome(properties.getMavenHome());
invoker.setOutputHandler(mavenLogger::info);
invoker.setErrorHandler(mavenLogger::warn);
File localRepository = properties.getLocalRepository();
if (localRepository != null) {
invoker.setLocalRepositoryDirectory(localRepository);
}
DefaultInvocationRequest request = new DefaultInvocationRequest();
request.setJavaHome(os.getJavaHome());
request.setShellEnvironmentInherited(true);
request.setBaseDirectory(workspace.getProjectDirectory(project));
request.setGoals(arguments.toCommandLine(it -> properties.getFullyQualifiedPlugin(it.getGoal())));
InvocationResult result = invoker.execute(request); InvocationResult result = invoker.execute(request);
if (result.getExitCode() != 0) { if (result.getExitCode() != 0) {
throw new RuntimeException(result.getExecutionException()); throw new RuntimeException(result.getExecutionException());
} }
} catch (Exception e) {
} catch (MavenInvocationException o_O) { throw new RuntimeException(e);
throw new RuntimeException(o_O);
} }
} }
private MavenLogger getLogger(Project project, List<CommandLine.Goal> goals) {
if (this.properties.isConsoleLogger()) {
return new SlfLogger(log, project);
}
return new FileLogger(log, project, this.workspace.getLogsDirectory(), goals);
}
/**
* Maven Logging Forwarder.
*/
interface MavenLogger extends Closeable {
void info(String message);
void warn(String message);
}
@RequiredArgsConstructor
static class SlfLogger implements MavenLogger {
private final org.slf4j.Logger logger;
private final String logPrefix;
SlfLogger(org.slf4j.Logger logger, Project project) {
this.logger = logger;
this.logPrefix = StringUtils.padRight(project.getName(), 10);
}
@Override
public void info(String message) {
logger.info(logPrefix + ": " + message);
}
@Override
public void warn(String message) {
logger.warn(logPrefix + ": " + message);
}
@Override
public void close() throws IOException {
// no-op
}
}
static class FileLogger implements MavenLogger {
private final PrintWriter printWriter;
private final FileOutputStream outputStream;
FileLogger(org.slf4j.Logger logger, Project 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);
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);
}
@Override
public void warn(String message) {
printWriter.println(message);
}
@Override
public void close() throws IOException {
printWriter.close();
outputStream.close();
}
}
} }

View File

@@ -28,6 +28,7 @@ import org.springframework.web.util.UriTemplate;
/** /**
* @author Oliver Gierke * @author Oliver Gierke
* @author Mark Paluch
*/ */
@Data @Data
@Component @Component
@@ -56,6 +57,11 @@ public class DeploymentProperties {
*/ */
private String stagingRepository; private String stagingRepository;
/**
* The repository to deploy docs/schemas to.
*/
private String distributionRepository;
private String repositoryPrefix = ""; private String repositoryPrefix = "";
private Gpg gpg; private Gpg gpg;
@@ -64,9 +70,13 @@ public class DeploymentProperties {
return repositoryPrefix.concat(stagingRepository); return repositoryPrefix.concat(stagingRepository);
} }
public String getDistributionRepository() {
return repositoryPrefix.concat(distributionRepository);
}
/** /**
* Returns the URI of the staging repository. * Returns the URI of the staging repository.
* *
* @return * @return
*/ */
public String getStagingRepositoryUrl() { public String getStagingRepositoryUrl() {
@@ -88,7 +98,7 @@ public class DeploymentProperties {
/** /**
* Returns the URI to the resource that a promotion can be triggered at. * Returns the URI to the resource that a promotion can be triggered at.
* *
* @param information must not be {@literal null}. * @param information must not be {@literal null}.
* @return * @return
*/ */

View File

@@ -25,6 +25,7 @@ import org.springframework.stereotype.Component;
/** /**
* @author Oliver Gierke * @author Oliver Gierke
* @author Mark Paluch
*/ */
@Slf4j @Slf4j
@Data @Data
@@ -32,7 +33,7 @@ import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "io") @ConfigurationProperties(prefix = "io")
class IoProperties { class IoProperties {
private File workDir, javaHome; private File workDir, javaHome, logs;
public void setWorkDir(String workDir) { public void setWorkDir(String workDir) {

View File

@@ -48,7 +48,7 @@ import org.springframework.util.Assert;
/** /**
* Abstraction of the workspace that is used to work with the {@link Project}'s repositories, execute builds, etc. * Abstraction of the workspace that is used to work with the {@link Project}'s repositories, execute builds, etc.
* *
* @author Oliver Gierke * @author Oliver Gierke
*/ */
@Component @Component
@@ -64,25 +64,38 @@ public class Workspace {
/** /**
* Returns the current working directory. * Returns the current working directory.
* *
* @return * @return
*/ */
public File getWorkingDirectory() { public File getWorkingDirectory() {
return ioProperties.getWorkDir(); return ioProperties.getWorkDir();
} }
/**
* Returns the current logs directory.
*
* @return
*/
public File getLogsDirectory() {
return ioProperties.getLogs();
}
/** /**
* Cleans up the working directory by removing all files and folders in it. * Cleans up the working directory by removing all files and folders in it.
* *
* @throws IOException * @throws IOException
*/ */
public void cleanup() throws IOException { public void cleanup() throws IOException {
logger.log("Workspace", "Cleaning up workspace directory at %s.", getWorkingDirectory().getAbsolutePath()); delete(getWorkingDirectory().toPath(), "workspace");
delete(getLogsDirectory().toPath(), "logs");
}
Path workingDirPath = getWorkingDirectory().toPath(); private void delete(Path path, String type) throws IOException {
Files.walkFileTree(workingDirPath, new SimpleFileVisitor<Path>() { logger.log("Workspace", "Cleaning up %s directory at %s.", type, path.toAbsolutePath());
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override @Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
@@ -93,7 +106,7 @@ public class Workspace {
@Override @Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (!workingDirPath.equals(dir)) { if (!path.equals(dir)) {
Files.delete(dir); Files.delete(dir);
} }
@@ -130,7 +143,7 @@ public class Workspace {
/** /**
* Returns the directory for the given {@link Project}. * Returns the directory for the given {@link Project}.
* *
* @param project must not be {@literal null}. * @param project must not be {@literal null}.
* @return * @return
*/ */
@@ -142,7 +155,7 @@ public class Workspace {
/** /**
* Returns whether the project directory for the given project already exists. * Returns whether the project directory for the given project already exists.
* *
* @param project must not be {@literal null}. * @param project must not be {@literal null}.
* @return * @return
*/ */
@@ -154,7 +167,7 @@ public class Workspace {
/** /**
* Returns a file with the given name relative to the working directory for the given {@link Project}. * Returns a file with the given name relative to the working directory for the given {@link Project}.
* *
* @param name must not be {@literal null} or empty. * @param name must not be {@literal null} or empty.
* @param project must not be {@literal null}. * @param project must not be {@literal null}.
* @return * @return
@@ -218,7 +231,7 @@ public class Workspace {
/** /**
* Initializes the working directory and creates the folders if necessary. * Initializes the working directory and creates the folders if necessary.
* *
* @throws IOException * @throws IOException
*/ */
@PostConstruct @PostConstruct

View File

@@ -1,11 +1,14 @@
io.work-dir=~/temp/spring-data-shell/workspace io.work-dir=~/temp/spring-data-shell/workspace
io.logs=logs
# Maven setup # Maven setup
maven.local-repository=~/temp/spring-data-shell/repository maven.local-repository=~/temp/spring-data-shell/repository
maven.plugins.versions=org.codehaus.mojo:versions-maven-plugin:2.2 maven.plugins.versions=org.codehaus.mojo:versions-maven-plugin:2.2
maven.console-logger=true
deployment.server.uri=https://repo.spring.io deployment.server.uri=https://repo.spring.io
deployment.staging-repository=libs-staging-local deployment.staging-repository=libs-staging-local
deployment.distribution-repository=temp-private-local
deployment.username=buildmaster deployment.username=buildmaster
#deployment.password <- local #deployment.password <- local