[MNG-5729] Use monotonic time measurements (#1965)

This commit is contained in:
Guillaume Nodet 2024-12-12 12:02:17 +01:00 committed by GitHub
parent 5b7a6de55a
commit 54ffc5014e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
43 changed files with 502 additions and 248 deletions

View File

@ -59,6 +59,12 @@
<groupId>org.apache.maven</groupId>
<artifactId>maven-api-di</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -437,5 +437,13 @@ public final class Constants {
@Config(type = "java.lang.Integer")
public static final String MAVEN_DEPLOY_SNAPSHOT_BUILD_NUMBER = "maven.deploy.snapshot.buildNumber";
/**
* User property used to store the build timestamp.
*
* @since 4.1.0
*/
@Config(type = "java.time.Instant")
public static final String MAVEN_START_INSTANT = "maven.startInstant";
private Constants() {}
}

View File

@ -0,0 +1,120 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.maven.api;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
/**
* A Clock implementation that combines monotonic timing with wall-clock time.
* <p>
* This class provides precise time measurements using {@link System#nanoTime()}
* while maintaining wall-clock time information in UTC. The wall-clock time
* is computed from the monotonic duration since system start to ensure consistency
* between time measurements.
* <p>
* This implementation is singleton-based and always uses UTC timezone. The clock
* cannot be adjusted to different timezones to maintain consistent monotonic behavior.
* Users needing local time representation should convert the result of {@link #instant()}
* to their desired timezone:
* <pre>{@code
* Instant now = MonotonicClock.now();
* ZonedDateTime local = now.atZone(ZoneId.systemDefault());
* }</pre>
*
* @see System#nanoTime()
* @see Clock
*/
public class MonotonicClock extends Clock {
private static final MonotonicClock CLOCK = new MonotonicClock();
private final long startNanos;
private final Instant startInstant;
/**
* Private constructor to enforce singleton pattern.
* Initializes the clock with the current system time and nanoTime.
*/
private MonotonicClock() {
this.startNanos = System.nanoTime();
this.startInstant = Clock.systemUTC().instant();
}
/**
* Returns the singleton instance of MonotonicClock.
*
* @return the monotonic clock instance
*/
public static MonotonicClock get() {
return CLOCK;
}
/**
* Returns the current instant from the monotonic clock.
* This is a convenience method equivalent to {@code get().instant()}.
*
* @return the current instant using monotonic timing
*/
public static Instant now() {
return get().instant();
}
/**
* Returns a monotonically increasing instant.
* <p>
* The returned instant is calculated by adding the elapsed nanoseconds
* since clock creation to the initial wall clock time. This ensures that
* the time never goes backwards and maintains a consistent relationship
* with the wall clock time.
*
* @return the current instant using monotonic timing
*/
@Override
public Instant instant() {
long elapsedNanos = System.nanoTime() - startNanos;
return startInstant.plusNanos(elapsedNanos);
}
/**
* Returns the zone ID of this clock, which is always UTC.
*
* @return the UTC zone ID
*/
@Override
public ZoneId getZone() {
return ZoneOffset.UTC;
}
/**
* Returns this clock since timezone adjustments are not supported.
* <p>
* This implementation maintains UTC time to ensure monotonic behavior.
* The provided zone parameter is ignored.
*
* @param zone the target timezone (ignored)
* @return this clock instance
*/
@Override
public Clock withZone(ZoneId zone) {
// Monotonic clock is always UTC-based
return this;
}
}

View File

@ -106,7 +106,7 @@ public interface ProtoSession {
* Returns new builder from scratch.
*/
static Builder newBuilder() {
return new Builder().withStartTime(Instant.now());
return new Builder().withStartTime(MonotonicClock.now());
}
class Builder {

View File

@ -20,9 +20,13 @@ package org.apache.maven.cling.event;
import java.io.File;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.util.List;
import java.util.Objects;
import org.apache.maven.api.MonotonicClock;
import org.apache.maven.api.services.MessageBuilder;
import org.apache.maven.api.services.MessageBuilderFactory;
import org.apache.maven.execution.AbstractExecutionListener;
@ -223,7 +227,7 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
} else if (buildSummary instanceof BuildSuccess) {
buffer.append(builder().success("SUCCESS"));
buffer.append(" [");
String buildTimeDuration = formatDuration(buildSummary.getTime());
String buildTimeDuration = formatDuration(buildSummary.getExecTime());
int padSize = MAX_PADDED_BUILD_TIME_DURATION_LENGTH - buildTimeDuration.length();
if (padSize > 0) {
buffer.append(chars(' ', padSize));
@ -233,7 +237,7 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
} else if (buildSummary instanceof BuildFailure) {
buffer.append(builder().failure("FAILURE"));
buffer.append(" [");
String buildTimeDuration = formatDuration(buildSummary.getTime());
String buildTimeDuration = formatDuration(buildSummary.getExecTime());
int padSize = MAX_PADDED_BUILD_TIME_DURATION_LENGTH - buildTimeDuration.length();
if (padSize > 0) {
buffer.append(chars(' ', padSize));
@ -266,15 +270,15 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
private void logStats(MavenSession session) {
infoLine('-');
long finish = System.currentTimeMillis();
Instant finish = MonotonicClock.now();
long time = finish - session.getRequest().getStartTime().getTime();
Duration time = Duration.between(session.getRequest().getStartInstant(), finish);
String wallClock = session.getRequest().getDegreeOfConcurrency() > 1 ? " (Wall Clock)" : "";
logger.info("Total time: {}{}", formatDuration(time), wallClock);
logger.info("Finished at: {}", formatTimestamp(finish));
logger.info("Finished at: {}", formatTimestamp(finish.atZone(ZoneId.systemDefault())));
}
@Override

View File

@ -22,7 +22,6 @@ import java.io.FileNotFoundException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@ -33,6 +32,7 @@ import java.util.regex.Pattern;
import org.apache.maven.InternalErrorException;
import org.apache.maven.Maven;
import org.apache.maven.api.Constants;
import org.apache.maven.api.MonotonicClock;
import org.apache.maven.api.cli.InvokerRequest;
import org.apache.maven.api.cli.Logger;
import org.apache.maven.api.cli.mvn.MavenOptions;
@ -105,7 +105,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
mavenExecutionRequest.setIgnoreMissingArtifactDescriptor(true);
mavenExecutionRequest.setRecursive(true);
mavenExecutionRequest.setReactorFailureBehavior(MavenExecutionRequest.REACTOR_FAIL_FAST);
mavenExecutionRequest.setStartTime(new Date());
mavenExecutionRequest.setStartInstant(MonotonicClock.now());
mavenExecutionRequest.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_INFO);
mavenExecutionRequest.setDegreeOfConcurrency(1);
mavenExecutionRequest.setBuilderId("singlethreaded");

View File

@ -19,7 +19,10 @@
package org.apache.maven.cling.transfer;
import java.io.PrintWriter;
import java.time.Duration;
import java.time.Instant;
import org.apache.maven.api.MonotonicClock;
import org.apache.maven.api.services.MessageBuilder;
import org.apache.maven.api.services.MessageBuilderFactory;
import org.eclipse.aether.transfer.AbstractTransferListener;
@ -80,11 +83,12 @@ public abstract class AbstractMavenTransferListener extends AbstractTransferList
message.resetStyle().append(resource.getResourceName());
message.style(STYLE).append(" (").append(format.format(contentLength));
long duration = System.currentTimeMillis() - resource.getTransferStartTime();
if (duration > 0L) {
double bytesPerSecond = contentLength / (duration / 1000.0);
Duration duration =
Duration.between(Instant.ofEpochMilli(resource.getTransferStartTime()), MonotonicClock.now());
if ((duration.getSeconds() | duration.getNano()) > 0) { // duration.isPositive()
long bytesPerSecond = Math.round(contentLength / (double) duration.toSeconds());
message.append(" at ");
format.format(message, (long) bytesPerSecond);
format.format(message, bytesPerSecond);
message.append("/s");
}

View File

@ -18,6 +18,10 @@
*/
package org.apache.maven.cling.transfer;
import java.time.Duration;
import java.time.Instant;
import org.apache.maven.api.MonotonicClock;
import org.eclipse.aether.transfer.AbstractTransferListener;
import org.eclipse.aether.transfer.TransferCancelledException;
import org.eclipse.aether.transfer.TransferEvent;
@ -83,11 +87,12 @@ public class Slf4jMavenTransferListener extends AbstractTransferListener {
.append(" (");
format.format(message, contentLength);
long duration = System.currentTimeMillis() - resource.getTransferStartTime();
if (duration > 0L) {
double bytesPerSecond = contentLength / (duration / 1000.0);
Duration duration =
Duration.between(Instant.ofEpochMilli(resource.getTransferStartTime()), MonotonicClock.now());
if ((duration.getSeconds() | duration.getNano()) > 0) { // duration.isPositive()
long bytesPerSecond = Math.round(contentLength / (double) duration.toSeconds());
message.append(" at ");
format.format(message, (long) bytesPerSecond);
format.format(message, bytesPerSecond);
message.append("/s");
}

View File

@ -20,8 +20,9 @@ package org.apache.maven.cling.utils;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.time.Duration;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Locale;
import java.util.Properties;
@ -105,23 +106,13 @@ public final class CLIReportingUtils {
* @return Readable build info
*/
public static String createMavenVersionString(Properties buildProperties) {
String timestamp = reduce(buildProperties.getProperty("timestamp"));
String version = reduce(buildProperties.getProperty(BUILD_VERSION_PROPERTY));
String rev = reduce(buildProperties.getProperty("buildNumber"));
String distributionName = reduce(buildProperties.getProperty("distributionName"));
String msg = distributionName + " ";
msg += (version != null ? version : "<version unknown>");
if (rev != null || timestamp != null) {
msg += " (";
msg += (rev != null ? rev : "");
if (timestamp != null && !timestamp.isEmpty()) {
String ts = formatTimestamp(Long.parseLong(timestamp));
msg += (rev != null ? "; " : "") + ts;
}
msg += ")";
}
return msg;
return distributionName + " "
+ (version != null ? version : "<version unknown>")
+ (rev != null ? " (" + rev + ")" : "");
}
private static String reduce(String s) {
@ -169,35 +160,25 @@ public final class CLIReportingUtils {
}
}
public static String formatTimestamp(long timestamp) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
return sdf.format(new Date(timestamp));
public static String formatTimestamp(TemporalAccessor instant) {
return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(instant);
}
public static String formatDuration(long duration) {
// CHECKSTYLE_OFF: MagicNumber
long ms = duration % 1000;
long s = (duration / ONE_SECOND) % 60;
long m = (duration / ONE_MINUTE) % 60;
long h = (duration / ONE_HOUR) % 24;
long d = duration / ONE_DAY;
// CHECKSTYLE_ON: MagicNumber
public static String formatDuration(Duration duration) {
long days = duration.toDays();
long hours = duration.toHoursPart();
long minutes = duration.toMinutesPart();
long seconds = duration.toSecondsPart();
long millis = duration.toMillisPart();
String format;
if (d > 0) {
// Length 11+ chars
format = "%d d %02d:%02d h";
} else if (h > 0) {
// Length 7 chars
format = "%2$02d:%3$02d h";
} else if (m > 0) {
// Length 9 chars
format = "%3$02d:%4$02d min";
if (days > 0) {
return String.format("%d d %02d:%02d h", days, hours, minutes);
} else if (hours > 0) {
return String.format("%02d:%02d h", hours, minutes);
} else if (minutes > 0) {
return String.format("%02d:%02d min", minutes, seconds);
} else {
// Length 7-8 chars
format = "%4$d.%5$03d s";
return String.format("%d.%03d s", seconds, millis);
}
return String.format(format, d, h, m, s, ms);
}
}

View File

@ -28,7 +28,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@ -39,6 +38,7 @@ import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
import org.apache.maven.api.MonotonicClock;
import org.apache.maven.api.Session;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.model.Prerequisites;
@ -194,7 +194,7 @@ public class DefaultMaven implements Maven {
//
@SuppressWarnings("checkstyle:methodlength")
private MavenExecutionResult doExecute(MavenExecutionRequest request) {
request.setStartTime(new Date());
request.setStartInstant(MonotonicClock.now());
MavenExecutionResult result = new DefaultMavenExecutionResult();

View File

@ -18,6 +18,8 @@
*/
package org.apache.maven.execution;
import java.time.Duration;
import org.apache.maven.project.MavenProject;
/**
@ -39,6 +41,17 @@ public class BuildFailure extends BuildSummary {
* @param cause The cause of the build failure, may be {@code null}.
*/
public BuildFailure(MavenProject project, long time, Throwable cause) {
this(project, Duration.ofMillis(time), cause);
}
/**
* Creates a new build summary for the specified project.
*
* @param project The project being summarized, must not be {@code null}.
* @param time The build time of the project in milliseconds.
* @param cause The cause of the build failure, may be {@code null}.
*/
public BuildFailure(MavenProject project, Duration time, Throwable cause) {
this(project, time, time, cause);
}
@ -50,7 +63,7 @@ public class BuildFailure extends BuildSummary {
* @param wallTime The wall time of the project in milliseconds.
* @param cause The cause of the build failure, may be {@code null}.
*/
public BuildFailure(MavenProject project, long execTime, long wallTime, Throwable cause) {
public BuildFailure(MavenProject project, Duration execTime, Duration wallTime, Throwable cause) {
super(project, execTime, wallTime);
this.cause = cause;
}

View File

@ -18,6 +18,8 @@
*/
package org.apache.maven.execution;
import java.time.Duration;
import org.apache.maven.project.MavenProject;
/**
@ -33,7 +35,17 @@ public class BuildSuccess extends BuildSummary {
* @param time The build time of the project in milliseconds.
*/
public BuildSuccess(MavenProject project, long time) {
super(project, time, time);
this(project, Duration.ofMillis(time));
}
/**
* Creates a new build summary for the specified project.
*
* @param project The project being summarized, must not be {@code null}.
* @param time The build time of the project in milliseconds.
*/
public BuildSuccess(MavenProject project, Duration time) {
this(project, time, time);
}
/**
@ -43,7 +55,7 @@ public class BuildSuccess extends BuildSummary {
* @param wallTime The wall time of the project in milliseconds.
* @param execTime The exec time of the project in milliseconds.
*/
public BuildSuccess(MavenProject project, long wallTime, long execTime) {
public BuildSuccess(MavenProject project, Duration wallTime, Duration execTime) {
super(project, wallTime, execTime);
}
}

View File

@ -18,6 +18,7 @@
*/
package org.apache.maven.execution;
import java.time.Duration;
import java.util.Objects;
import org.apache.maven.project.MavenProject;
@ -36,12 +37,12 @@ public abstract class BuildSummary {
/**
* The build time of the project in milliseconds.
*/
private final long wallTime;
private final Duration wallTime;
/**
* The total amount of time spent for to run mojos in milliseconds.
*/
private final long execTime;
private final Duration execTime;
/**
* Creates a new build summary for the specified project.
@ -50,7 +51,7 @@ public abstract class BuildSummary {
* @param time The build time of the project in milliseconds.
*/
protected BuildSummary(MavenProject project, long time) {
this(project, time, time);
this(project, Duration.ofMillis(time), Duration.ofMillis(time));
}
/**
@ -60,7 +61,7 @@ public abstract class BuildSummary {
* @param execTime The exec time of the project in milliseconds.
* @param wallTime The wall time of the project in milliseconds.
*/
protected BuildSummary(MavenProject project, long execTime, long wallTime) {
protected BuildSummary(MavenProject project, Duration execTime, Duration wallTime) {
this.project = Objects.requireNonNull(project, "project cannot be null");
// TODO Validate for < 0?
this.execTime = execTime;
@ -82,15 +83,24 @@ public abstract class BuildSummary {
* @return The wall time of the project in milliseconds.
*/
public long getTime() {
return execTime;
return execTime.toMillis();
}
/**
* Gets the exec time of the project in milliseconds.
* Gets the wall time of the project.
*
* @return The exec time of the project in milliseconds.
* @return The wall time of the project.
*/
public long getWallTime() {
public Duration getWallTime() {
return wallTime;
}
/**
* Gets the exec time of the project.
*
* @return The exec time of the project.
*/
public Duration getExecTime() {
return execTime;
}
}

View File

@ -20,6 +20,7 @@ package org.apache.maven.execution;
import java.io.File;
import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@ -28,6 +29,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import org.apache.maven.api.MonotonicClock;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
import org.apache.maven.model.Profile;
@ -135,7 +137,7 @@ public class DefaultMavenExecutionRequest implements MavenExecutionRequest {
private Properties userProperties;
private Date startTime = new Date();
private Instant startTime = MonotonicClock.now();
private boolean showErrors = false;
@ -214,7 +216,7 @@ public class DefaultMavenExecutionRequest implements MavenExecutionRequest {
copy.setExecutionListener(original.getExecutionListener());
copy.setUseLegacyLocalRepository(original.isUseLegacyLocalRepository());
copy.setBuilderId(original.getBuilderId());
copy.setStartTime(original.getStartTime());
copy.setStartInstant(original.getStartInstant());
return copy;
}
@ -299,10 +301,22 @@ public class DefaultMavenExecutionRequest implements MavenExecutionRequest {
}
@Override
@Deprecated
public Date getStartTime() {
return new Date(startTime.toEpochMilli());
}
@Override
public Instant getStartInstant() {
return startTime;
}
@Override
public MavenExecutionRequest setStartInstant(Instant startTime) {
this.startTime = startTime;
return this;
}
@Override
public boolean isShowErrors() {
return showErrors;
@ -423,9 +437,10 @@ public class DefaultMavenExecutionRequest implements MavenExecutionRequest {
return this;
}
@Deprecated
@Override
public MavenExecutionRequest setStartTime(Date startTime) {
this.startTime = startTime;
this.startTime = Instant.ofEpochMilli(startTime.getTime());
return this;
}
@ -981,7 +996,7 @@ public class DefaultMavenExecutionRequest implements MavenExecutionRequest {
projectBuildingRequest.setInactiveProfileIds(getInactiveProfiles());
projectBuildingRequest.setProfiles(getProfiles());
projectBuildingRequest.setProcessPlugins(true);
projectBuildingRequest.setBuildStartTime(getStartTime());
projectBuildingRequest.setBuildStartInstant(getStartInstant());
}
return projectBuildingRequest;

View File

@ -20,6 +20,7 @@ package org.apache.maven.execution;
import java.io.File;
import java.nio.file.Path;
import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -105,10 +106,16 @@ public interface MavenExecutionRequest {
String getBaseDirectory();
// Timing (remove this)
@Deprecated
MavenExecutionRequest setStartTime(Date start);
@Deprecated
Date getStartTime();
MavenExecutionRequest setStartInstant(Instant start);
Instant getStartInstant();
// Goals
MavenExecutionRequest setGoals(List<String> goals);

View File

@ -20,6 +20,7 @@ package org.apache.maven.execution;
import java.io.File;
import java.nio.file.Path;
import java.time.Instant;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@ -245,10 +246,15 @@ public class MavenSession implements Cloneable {
}
}
@Deprecated
public Date getStartTime() {
return request.getStartTime();
}
public Instant getStartInstant() {
return request.getStartInstant();
}
public boolean isParallel() {
return parallel;
}

View File

@ -18,6 +18,7 @@
*/
package org.apache.maven.execution;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -123,6 +124,10 @@ public class ReactorManager {
buildFailuresByProject.put(getProjectKey(project), new BuildFailure(project, time, error));
}
public void registerBuildFailure(MavenProject project, Exception error, String task, Duration time) {
buildFailuresByProject.put(getProjectKey(project), new BuildFailure(project, time, error));
}
public boolean hasBuildFailures() {
return !buildFailuresByProject.isEmpty();
}
@ -147,6 +152,10 @@ public class ReactorManager {
buildSuccessesByProject.put(getProjectKey(project), new BuildSuccess(project, time));
}
public void registerBuildSuccess(MavenProject project, Duration time) {
buildSuccessesByProject.put(getProjectKey(project), new BuildSuccess(project, time));
}
public BuildFailure getBuildFailure(MavenProject project) {
return buildFailuresByProject.get(getProjectKey(project));
}

View File

@ -168,6 +168,7 @@ public class DefaultRepositorySystemSessionFactory implements RepositorySystemSe
configProps.put(ConfigurationProperties.USER_AGENT, getUserAgent());
configProps.put(ConfigurationProperties.INTERACTIVE, request.isInteractiveMode());
configProps.put("maven.startTime", request.getStartTime());
configProps.put(Constants.MAVEN_START_INSTANT, request.getStartInstant());
sessionBuilder.setOffline(request.isOffline());
sessionBuilder.setChecksumPolicy(request.getGlobalChecksumPolicy());

View File

@ -146,7 +146,7 @@ public class DefaultSession extends AbstractSession implements InternalMavenSess
@Nonnull
@Override
public Instant getStartTime() {
return getMavenSession().getRequest().getStartTime().toInstant();
return getMavenSession().getRequest().getStartInstant();
}
@Override

View File

@ -22,9 +22,12 @@ import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.time.Duration;
import java.time.Instant;
import java.util.HashSet;
import java.util.List;
import org.apache.maven.api.MonotonicClock;
import org.apache.maven.execution.BuildSuccess;
import org.apache.maven.execution.ExecutionEvent;
import org.apache.maven.execution.MavenSession;
@ -81,7 +84,7 @@ public class LifecycleModuleBuilder {
TaskSegment taskSegment) {
session.setCurrentProject(currentProject);
long buildStartTime = System.currentTimeMillis();
Instant buildStartTime = MonotonicClock.now();
try {
@ -106,12 +109,14 @@ public class LifecycleModuleBuilder {
new ProjectExecutionEvent(session, currentProject, mojoExecutions));
mojoExecutor.execute(session, mojoExecutions);
long buildEndTime = System.currentTimeMillis();
Instant buildEndTime = MonotonicClock.now();
projectExecutionListener.afterProjectExecutionSuccess(
new ProjectExecutionEvent(session, currentProject, mojoExecutions));
reactorContext.getResult().addBuildSummary(new BuildSuccess(currentProject, buildEndTime - buildStartTime));
reactorContext
.getResult()
.addBuildSummary(new BuildSuccess(currentProject, Duration.between(buildStartTime, buildEndTime)));
eventCatapult.fire(ExecutionEvent.Type.ProjectSucceeded, session, null);
} catch (Throwable t) {

View File

@ -22,9 +22,12 @@ import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Set;
import org.apache.maven.api.MonotonicClock;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.BuildFailure;
import org.apache.maven.execution.ExecutionEvent;
@ -164,11 +167,13 @@ public class BuilderCommon {
final MavenSession currentSession,
final MavenProject mavenProject,
Throwable t,
final long buildStartTime) {
final Instant buildStartTime) {
// record the error and mark the project as failed
long buildEndTime = System.currentTimeMillis();
Instant buildEndTime = MonotonicClock.now();
buildContext.getResult().addException(t);
buildContext.getResult().addBuildSummary(new BuildFailure(mavenProject, buildEndTime - buildStartTime, t));
buildContext
.getResult()
.addBuildSummary(new BuildFailure(mavenProject, Duration.between(buildStartTime, buildEndTime), t));
// notify listeners about "soft" project build failures only
if (t instanceof Exception && !(t instanceof RuntimeException)) {

View File

@ -23,6 +23,8 @@ import javax.inject.Named;
import javax.xml.stream.XMLStreamException;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -34,13 +36,13 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.maven.api.Lifecycle;
import org.apache.maven.api.MonotonicClock;
import org.apache.maven.api.services.LifecycleRegistry;
import org.apache.maven.api.services.MavenException;
import org.apache.maven.api.xml.XmlNode;
@ -905,31 +907,31 @@ public class BuildPlanExecutor {
}
protected static class Clock {
long start;
long end;
long resumed;
long exec;
Instant start;
Instant end;
Instant resumed;
Duration exec = Duration.ZERO;
protected void start() {
if (start == 0) {
start = System.nanoTime();
if (start == null) {
start = MonotonicClock.now();
resumed = start;
} else {
resumed = System.nanoTime();
resumed = MonotonicClock.now();
}
}
protected void stop() {
end = System.nanoTime();
exec += end - resumed;
end = MonotonicClock.now();
exec = exec.plus(Duration.between(resumed, end));
}
protected long wallTime() {
return TimeUnit.NANOSECONDS.toMillis(end - start);
protected Duration wallTime() {
return Duration.between(start, end);
}
protected long execTime() {
return TimeUnit.NANOSECONDS.toMillis(exec);
protected Duration execTime() {
return exec;
}
}
}

View File

@ -18,6 +18,7 @@
*/
package org.apache.maven.project;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -59,7 +60,7 @@ public class DefaultProjectBuildingRequest implements ProjectBuildingRequest {
private Properties userProperties;
private Date buildStartTime;
private Instant buildStartTime;
private boolean resolveDependencies;
@ -261,11 +262,21 @@ public class DefaultProjectBuildingRequest implements ProjectBuildingRequest {
return profiles;
}
@Deprecated
public Date getBuildStartTime() {
return buildStartTime;
return buildStartTime != null ? new Date(buildStartTime.toEpochMilli()) : null;
}
@Deprecated
public void setBuildStartTime(Date buildStartTime) {
setBuildStartInstant(buildStartTime != null ? Instant.ofEpochMilli(buildStartTime.getTime()) : null);
}
public Instant getBuildStartInstant() {
return this.buildStartTime;
}
public void setBuildStartInstant(Instant buildStartTime) {
this.buildStartTime = buildStartTime;
}

View File

@ -18,6 +18,7 @@
*/
package org.apache.maven.project;
import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.Properties;
@ -138,6 +139,7 @@ public interface ProjectBuildingRequest {
*
* @return The start time of the build or {@code null} if unknown.
*/
@Deprecated
Date getBuildStartTime();
/**
@ -145,8 +147,23 @@ public interface ProjectBuildingRequest {
*
* @param buildStartTime The start time of the build, may be {@code null}.
*/
@Deprecated
void setBuildStartTime(Date buildStartTime);
/**
* Gets the start time of the build.
*
* @return The start time of the build or {@code null} if unknown.
*/
Instant getBuildStartInstant();
/**
* Sets the start time of the build.
*
* @param buildStartInstant The start time of the build, may be {@code null}.
*/
void setBuildStartInstant(Instant buildStartInstant);
RepositorySystemSession getRepositorySession();
ProjectBuildingRequest setRepositorySession(RepositorySystemSession repositorySession);

View File

@ -18,15 +18,14 @@
*/
package org.apache.maven.internal.impl.model;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.GregorianCalendar;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Properties;
import java.util.TimeZone;
import org.apache.maven.api.Constants;
import org.apache.maven.api.MonotonicClock;
/**
* MavenBuildTimestamp
@ -35,12 +34,10 @@ public class MavenBuildTimestamp {
// ISO 8601-compliant timestamp for machine readability
public static final String DEFAULT_BUILD_TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ssXXX";
public static final TimeZone DEFAULT_BUILD_TIME_ZONE = TimeZone.getTimeZone("Etc/UTC");
private final String formattedTimestamp;
public MavenBuildTimestamp() {
this(Instant.now());
this(MonotonicClock.now());
}
public MavenBuildTimestamp(Instant time) {
@ -66,12 +63,11 @@ public class MavenBuildTimestamp {
timestampFormat = DEFAULT_BUILD_TIMESTAMP_FORMAT;
}
if (time == null) {
time = Instant.now();
time = MonotonicClock.now();
}
SimpleDateFormat dateFormat = new SimpleDateFormat(timestampFormat);
dateFormat.setCalendar(new GregorianCalendar());
dateFormat.setTimeZone(DEFAULT_BUILD_TIME_ZONE);
formattedTimestamp = dateFormat.format(new Date(time.toEpochMilli()));
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern(timestampFormat).withZone(ZoneId.of("UTC"));
formattedTimestamp = formatter.format(time);
}
public String formattedTimestamp() {

View File

@ -20,9 +20,9 @@ package org.apache.maven.internal.impl.resolver;
import java.io.File;
import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
@ -39,11 +39,11 @@ final class LocalSnapshotMetadata extends MavenMetadata {
private final Collection<Artifact> artifacts = new ArrayList<>();
LocalSnapshotMetadata(Artifact artifact, Date timestamp) {
LocalSnapshotMetadata(Artifact artifact, Instant timestamp) {
super(createMetadata(artifact), (Path) null, timestamp);
}
LocalSnapshotMetadata(Metadata metadata, Path path, Date timestamp) {
LocalSnapshotMetadata(Metadata metadata, Path path, Instant timestamp) {
super(metadata, path, timestamp);
}

View File

@ -18,12 +18,14 @@
*/
package org.apache.maven.internal.impl.resolver;
import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.maven.api.Constants;
import org.apache.maven.api.MonotonicClock;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.impl.MetadataGenerator;
@ -40,10 +42,10 @@ class LocalSnapshotMetadataGenerator implements MetadataGenerator {
private final Map<Object, LocalSnapshotMetadata> snapshots;
private final Date timestamp;
private final Instant timestamp;
LocalSnapshotMetadataGenerator(RepositorySystemSession session, InstallRequest request) {
timestamp = (Date) ConfigUtils.getObject(session, new Date(), "maven.startTime");
timestamp = (Instant) ConfigUtils.getObject(session, MonotonicClock.now(), Constants.MAVEN_START_INSTANT);
snapshots = new LinkedHashMap<>();
}

View File

@ -26,12 +26,11 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import org.apache.maven.api.metadata.Metadata;
import org.apache.maven.metadata.v4.MetadataStaxReader;
@ -46,28 +45,26 @@ abstract class MavenMetadata extends AbstractMetadata implements MergeableMetada
static final String MAVEN_METADATA_XML = "maven-metadata.xml";
static DateFormat fmt;
static DateTimeFormatter fmt;
static {
TimeZone timezone = TimeZone.getTimeZone("UTC");
fmt = new SimpleDateFormat("yyyyMMddHHmmss");
fmt.setTimeZone(timezone);
fmt = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneOffset.UTC);
}
protected Metadata metadata;
private final Path path;
protected final Date timestamp;
protected final Instant timestamp;
private boolean merged;
@Deprecated
protected MavenMetadata(Metadata metadata, File file, Date timestamp) {
protected MavenMetadata(Metadata metadata, File file, Instant timestamp) {
this(metadata, file != null ? file.toPath() : null, timestamp);
}
protected MavenMetadata(Metadata metadata, Path path, Date timestamp) {
protected MavenMetadata(Metadata metadata, Path path, Instant timestamp) {
this.metadata = metadata;
this.path = path;
this.timestamp = timestamp;

View File

@ -19,9 +19,9 @@
package org.apache.maven.internal.impl.resolver;
import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import org.apache.maven.api.metadata.Metadata;
import org.eclipse.aether.artifact.Artifact;
@ -33,7 +33,7 @@ abstract class MavenSnapshotMetadata extends MavenMetadata {
protected final Collection<Artifact> artifacts = new ArrayList<>();
protected MavenSnapshotMetadata(Metadata metadata, Path path, Date timestamp) {
protected MavenSnapshotMetadata(Metadata metadata, Path path, Instant timestamp) {
super(metadata, path, timestamp);
}

View File

@ -20,7 +20,7 @@ package org.apache.maven.internal.impl.resolver;
import java.io.File;
import java.nio.file.Path;
import java.util.Date;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.List;
@ -56,12 +56,12 @@ final class PluginsMetadata extends MavenMetadata {
private final PluginInfo pluginInfo;
PluginsMetadata(PluginInfo pluginInfo, Date timestamp) {
PluginsMetadata(PluginInfo pluginInfo, Instant timestamp) {
super(createRepositoryMetadata(pluginInfo), (Path) null, timestamp);
this.pluginInfo = pluginInfo;
}
PluginsMetadata(PluginInfo pluginInfo, Path path, Date timestamp) {
PluginsMetadata(PluginInfo pluginInfo, Path path, Instant timestamp) {
super(createRepositoryMetadata(pluginInfo), path, timestamp);
this.pluginInfo = pluginInfo;
}

View File

@ -21,9 +21,9 @@ package org.apache.maven.internal.impl.resolver;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
@ -31,6 +31,8 @@ import java.util.Objects;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import org.apache.maven.api.Constants;
import org.apache.maven.api.MonotonicClock;
import org.apache.maven.api.xml.XmlNode;
import org.apache.maven.internal.impl.resolver.PluginsMetadata.PluginInfo;
import org.apache.maven.internal.xml.XmlNodeStaxBuilder;
@ -56,7 +58,7 @@ class PluginsMetadataGenerator implements MetadataGenerator {
private final Map<Object, PluginsMetadata> processedPlugins;
private final Date timestamp;
private final Instant timestamp;
PluginsMetadataGenerator(RepositorySystemSession session, InstallRequest request) {
this(session, request.getMetadata());
@ -68,7 +70,7 @@ class PluginsMetadataGenerator implements MetadataGenerator {
private PluginsMetadataGenerator(RepositorySystemSession session, Collection<? extends Metadata> metadatas) {
this.processedPlugins = new LinkedHashMap<>();
this.timestamp = (Date) ConfigUtils.getObject(session, new Date(), "maven.startTime");
this.timestamp = (Instant) ConfigUtils.getObject(session, MonotonicClock.now(), Constants.MAVEN_START_INSTANT);
/*
* NOTE: This should be considered a quirk to support interop with Maven's legacy ArtifactDeployer which

View File

@ -20,14 +20,12 @@ package org.apache.maven.internal.impl.resolver;
import java.io.File;
import java.nio.file.Path;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TimeZone;
import org.apache.maven.api.metadata.Metadata;
import org.apache.maven.api.metadata.Snapshot;
@ -41,18 +39,16 @@ import org.eclipse.aether.artifact.Artifact;
final class RemoteSnapshotMetadata extends MavenSnapshotMetadata {
public static final String DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT = "yyyyMMdd.HHmmss";
public static final TimeZone DEFAULT_SNAPSHOT_TIME_ZONE = TimeZone.getTimeZone("Etc/UTC");
private final Map<String, SnapshotVersion> versions = new LinkedHashMap<>();
private final Integer buildNumber;
RemoteSnapshotMetadata(Artifact artifact, Date timestamp, Integer buildNumber) {
RemoteSnapshotMetadata(Artifact artifact, Instant timestamp, Integer buildNumber) {
super(createRepositoryMetadata(artifact), null, timestamp);
this.buildNumber = buildNumber;
}
private RemoteSnapshotMetadata(Metadata metadata, Path path, Date timestamp, Integer buildNumber) {
private RemoteSnapshotMetadata(Metadata metadata, Path path, Instant timestamp, Integer buildNumber) {
super(metadata, path, timestamp);
this.buildNumber = buildNumber;
}
@ -79,13 +75,11 @@ final class RemoteSnapshotMetadata extends MavenSnapshotMetadata {
String lastUpdated;
if (metadata.getVersioning() == null) {
DateFormat utcDateFormatter = new SimpleDateFormat(DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT);
utcDateFormatter.setCalendar(new GregorianCalendar());
utcDateFormatter.setTimeZone(DEFAULT_SNAPSHOT_TIME_ZONE);
DateTimeFormatter utcDateFormatter = DateTimeFormatter.ofPattern(DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT);
snapshot = Snapshot.newBuilder()
.buildNumber(buildNumber != null ? buildNumber : getBuildNumber(recessive) + 1)
.timestamp(utcDateFormatter.format(this.timestamp))
.timestamp(utcDateFormatter.format(this.timestamp.atZone(ZoneOffset.UTC)))
.build();
lastUpdated = fmt.format(timestamp);

View File

@ -18,13 +18,14 @@
*/
package org.apache.maven.internal.impl.resolver;
import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.maven.api.Constants;
import org.apache.maven.api.MonotonicClock;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.deployment.DeployRequest;
@ -41,12 +42,12 @@ class RemoteSnapshotMetadataGenerator implements MetadataGenerator {
private final Map<Object, RemoteSnapshotMetadata> snapshots;
private final Date timestamp;
private final Instant timestamp;
private final Integer buildNumber;
RemoteSnapshotMetadataGenerator(RepositorySystemSession session, DeployRequest request) {
timestamp = (Date) ConfigUtils.getObject(session, new Date(), "maven.startTime");
timestamp = (Instant) ConfigUtils.getObject(session, MonotonicClock.now(), Constants.MAVEN_START_INSTANT);
Object bn = ConfigUtils.getObject(session, null, Constants.MAVEN_DEPLOY_SNAPSHOT_BUILD_NUMBER);
if (bn instanceof Integer) {
this.buildNumber = (Integer) bn;

View File

@ -20,9 +20,9 @@ package org.apache.maven.internal.impl.resolver;
import java.io.File;
import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
@ -38,12 +38,12 @@ final class VersionsMetadata extends MavenMetadata {
private final Artifact artifact;
VersionsMetadata(Artifact artifact, Date timestamp) {
VersionsMetadata(Artifact artifact, Instant timestamp) {
super(createRepositoryMetadata(artifact), (Path) null, timestamp);
this.artifact = artifact;
}
VersionsMetadata(Artifact artifact, Path path, Date timestamp) {
VersionsMetadata(Artifact artifact, Path path, Instant timestamp) {
super(createRepositoryMetadata(artifact), path, timestamp);
this.artifact = artifact;
}

View File

@ -18,13 +18,15 @@
*/
package org.apache.maven.internal.impl.resolver;
import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.maven.api.Constants;
import org.apache.maven.api.MonotonicClock;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.deployment.DeployRequest;
@ -44,7 +46,7 @@ class VersionsMetadataGenerator implements MetadataGenerator {
private final Map<Object, VersionsMetadata> processedVersions;
private final Date timestamp;
private final Instant timestamp;
VersionsMetadataGenerator(RepositorySystemSession session, InstallRequest request) {
this(session, request.getMetadata());
@ -57,7 +59,7 @@ class VersionsMetadataGenerator implements MetadataGenerator {
private VersionsMetadataGenerator(RepositorySystemSession session, Collection<? extends Metadata> metadatas) {
versions = new LinkedHashMap<>();
processedVersions = new LinkedHashMap<>();
timestamp = (Date) ConfigUtils.getObject(session, new Date(), "maven.startTime");
timestamp = (Instant) ConfigUtils.getObject(session, MonotonicClock.now(), Constants.MAVEN_START_INSTANT);
/*
* NOTE: This should be considered a quirk to support interop with Maven's legacy ArtifactDeployer which

View File

@ -21,10 +21,11 @@ package org.apache.maven.internal.impl.model;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@ -108,7 +109,7 @@ class DefaultModelInterpolatorTest {
@Test
public void testDefaultBuildTimestampFormatShouldFormatTimeIn24HourFormat() {
Calendar cal = Calendar.getInstance();
cal.setTimeZone(MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE);
cal.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
cal.set(Calendar.HOUR, 12);
cal.set(Calendar.AM_PM, Calendar.AM);
@ -120,7 +121,7 @@ class DefaultModelInterpolatorTest {
cal.set(Calendar.MONTH, Calendar.NOVEMBER);
cal.set(Calendar.DATE, 11);
Date firstTestDate = cal.getTime();
Instant firstTestDate = Instant.ofEpochMilli(cal.getTime().getTime());
cal.set(Calendar.HOUR, 11);
cal.set(Calendar.AM_PM, Calendar.PM);
@ -128,10 +129,11 @@ class DefaultModelInterpolatorTest {
// just to make sure all the bases are covered...
cal.set(Calendar.HOUR_OF_DAY, 23);
Date secondTestDate = cal.getTime();
Instant secondTestDate = Instant.ofEpochMilli(cal.getTime().getTime());
DateTimeFormatter format = DateTimeFormatter.ofPattern(MavenBuildTimestamp.DEFAULT_BUILD_TIMESTAMP_FORMAT)
.withZone(ZoneId.of("UTC"));
SimpleDateFormat format = new SimpleDateFormat(MavenBuildTimestamp.DEFAULT_BUILD_TIMESTAMP_FORMAT);
format.setTimeZone(MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE);
assertEquals("1976-11-11T00:16:00Z", format.format(firstTestDate));
assertEquals("1976-11-11T23:16:00Z", format.format(secondTestDate));
}
@ -148,14 +150,14 @@ class DefaultModelInterpolatorTest {
cal.set(Calendar.MONTH, Calendar.JUNE);
cal.set(Calendar.DATE, 16);
Date firstTestDate = cal.getTime();
Instant firstTestDate = Instant.ofEpochMilli(cal.getTime().getTime());
cal.set(Calendar.MONTH, Calendar.NOVEMBER);
Date secondTestDate = cal.getTime();
Instant secondTestDate = Instant.ofEpochMilli(cal.getTime().getTime());
SimpleDateFormat format = new SimpleDateFormat(MavenBuildTimestamp.DEFAULT_BUILD_TIMESTAMP_FORMAT);
format.setTimeZone(MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE);
DateTimeFormatter format = DateTimeFormatter.ofPattern(MavenBuildTimestamp.DEFAULT_BUILD_TIMESTAMP_FORMAT)
.withZone(ZoneId.of("UTC"));
assertEquals("2014-06-15T23:16:00Z", format.format(firstTestDate));
assertEquals("2014-11-16T00:16:00Z", format.format(secondTestDate));
}

View File

@ -18,10 +18,10 @@
*/
package org.apache.maven.internal.impl.model;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import org.apache.maven.api.MonotonicClock;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ -31,7 +31,7 @@ class MavenBuildTimestampTest {
void testMavenBuildTimestampUsesUTC() {
Map<String, String> interpolationProperties = new HashMap<>();
interpolationProperties.put("maven.build.timestamp.format", "yyyyMMdd'T'HHmm'Z'");
MavenBuildTimestamp timestamp = new MavenBuildTimestamp(Instant.now(), interpolationProperties);
MavenBuildTimestamp timestamp = new MavenBuildTimestamp(MonotonicClock.now(), interpolationProperties);
String formattedTimestamp = timestamp.formattedTimestamp();
assertTrue(formattedTimestamp.endsWith("Z"), "We expect the UTC marker at the end of the timestamp.");
}

View File

@ -34,6 +34,7 @@ import java.util.stream.Collectors;
import org.apache.maven.api.Artifact;
import org.apache.maven.api.Lifecycle;
import org.apache.maven.api.MonotonicClock;
import org.apache.maven.api.Packaging;
import org.apache.maven.api.ProducedArtifact;
import org.apache.maven.api.Project;
@ -101,7 +102,7 @@ public class ApiRunner {
static class DefaultSession extends AbstractSession {
private final Map<String, String> systemProperties;
private final Instant startTime = Instant.now();
private final Instant startTime = MonotonicClock.now();
DefaultSession(RepositorySystemSession session, RepositorySystem repositorySystem, Lookup lookup) {
this(session, repositorySystem, Collections.emptyList(), null, lookup);

View File

@ -19,10 +19,13 @@
package org.apache.maven.slf4j;
import java.io.PrintStream;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.maven.api.MonotonicClock;
import org.slf4j.Logger;
import org.slf4j.Marker;
import org.slf4j.event.Level;
@ -145,7 +148,8 @@ public class MavenBaseLogger extends LegacyAbstractLogger {
private static final long serialVersionUID = -632788891211436180L;
private static final long START_TIME = System.currentTimeMillis();
private static final Clock MONOTONIC_CLOCK = Clock.tick(Clock.systemUTC(), Duration.ofMillis(1));
private static final Instant START_TIME = MonotonicClock.now();
protected static final int LOG_LEVEL_TRACE = LocationAwareLogger.TRACE_INT;
protected static final int LOG_LEVEL_DEBUG = LocationAwareLogger.DEBUG_INT;
@ -265,7 +269,7 @@ public class MavenBaseLogger extends LegacyAbstractLogger {
}
protected String getFormattedDate() {
Date now = new Date();
Instant now = MonotonicClock.now();
String dateText;
synchronized (CONFIG_PARAMS.dateFormatter) {
dateText = CONFIG_PARAMS.dateFormatter.format(now);
@ -382,7 +386,7 @@ public class MavenBaseLogger extends LegacyAbstractLogger {
buf.append(getFormattedDate());
buf.append(SP);
} else {
buf.append(System.currentTimeMillis() - START_TIME);
buf.append(Duration.between(START_TIME, MonotonicClock.now()).toMillis());
buf.append(SP);
}
}

View File

@ -22,8 +22,7 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.PrintStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.Properties;
import org.apache.maven.slf4j.OutputChoice.OutputChoiceType;
@ -56,7 +55,7 @@ public class SimpleLoggerConfiguration {
private static final String DATE_TIME_FORMAT_STR_DEFAULT = null;
private static String dateTimeFormatStr = DATE_TIME_FORMAT_STR_DEFAULT;
DateFormat dateFormatter = null;
DateTimeFormatter dateFormatter = null;
private static final boolean SHOW_THREAD_NAME_DEFAULT = true;
boolean showThreadName = SHOW_THREAD_NAME_DEFAULT;
@ -116,7 +115,7 @@ public class SimpleLoggerConfiguration {
if (dateTimeFormatStr != null) {
try {
dateFormatter = new SimpleDateFormat(dateTimeFormatStr);
dateFormatter = DateTimeFormatter.ofPattern(dateTimeFormatStr);
} catch (IllegalArgumentException e) {
Reporter.error("Bad date format in " + CONFIGURATION_FILE + "; will output relative time", e);
}

View File

@ -16,7 +16,7 @@
# specific language governing permissions and limitations
# under the License.
#
props.count = 43
props.count = 44
props.1.key = maven.build.timestamp.format
props.1.configurationType = String
props.1.description = Build timestamp format.
@ -171,105 +171,111 @@ props.26.configurationType = String
props.26.description =
props.26.defaultValue = ${maven.user.conf}/settings-security4.xml
props.26.configurationSource = User properties
props.27.key = maven.style.color
props.27.key = maven.startInstant
props.27.configurationType = String
props.27.description = Maven output color mode. Allowed values are <code>auto</code>, <code>always</code>, <code>never</code>.
props.27.defaultValue = auto
props.27.since = 4.0.0
props.27.description = User property used to store the build timestamp.
props.27.defaultValue =
props.27.since = 4.1.0
props.27.configurationSource = User properties
props.28.key = maven.style.debug
props.28.key = maven.style.color
props.28.configurationType = String
props.28.description = Color style for debug messages.
props.28.defaultValue = bold,f:cyan
props.28.description = Maven output color mode. Allowed values are <code>auto</code>, <code>always</code>, <code>never</code>.
props.28.defaultValue = auto
props.28.since = 4.0.0
props.28.configurationSource = User properties
props.29.key = maven.style.error
props.29.key = maven.style.debug
props.29.configurationType = String
props.29.description = Color style for error messages.
props.29.defaultValue = bold,f:red
props.29.description = Color style for debug messages.
props.29.defaultValue = bold,f:cyan
props.29.since = 4.0.0
props.29.configurationSource = User properties
props.30.key = maven.style.failure
props.30.key = maven.style.error
props.30.configurationType = String
props.30.description = Color style for failure messages.
props.30.description = Color style for error messages.
props.30.defaultValue = bold,f:red
props.30.since = 4.0.0
props.30.configurationSource = User properties
props.31.key = maven.style.info
props.31.key = maven.style.failure
props.31.configurationType = String
props.31.description = Color style for info messages.
props.31.defaultValue = bold,f:blue
props.31.description = Color style for failure messages.
props.31.defaultValue = bold,f:red
props.31.since = 4.0.0
props.31.configurationSource = User properties
props.32.key = maven.style.mojo
props.32.key = maven.style.info
props.32.configurationType = String
props.32.description = Color style for mojo messages.
props.32.defaultValue = f:green
props.32.description = Color style for info messages.
props.32.defaultValue = bold,f:blue
props.32.since = 4.0.0
props.32.configurationSource = User properties
props.33.key = maven.style.project
props.33.key = maven.style.mojo
props.33.configurationType = String
props.33.description = Color style for project messages.
props.33.defaultValue = f:cyan
props.33.description = Color style for mojo messages.
props.33.defaultValue = f:green
props.33.since = 4.0.0
props.33.configurationSource = User properties
props.34.key = maven.style.strong
props.34.key = maven.style.project
props.34.configurationType = String
props.34.description = Color style for strong messages.
props.34.defaultValue = bold
props.34.description = Color style for project messages.
props.34.defaultValue = f:cyan
props.34.since = 4.0.0
props.34.configurationSource = User properties
props.35.key = maven.style.success
props.35.key = maven.style.strong
props.35.configurationType = String
props.35.description = Color style for success messages.
props.35.defaultValue = bold,f:green
props.35.description = Color style for strong messages.
props.35.defaultValue = bold
props.35.since = 4.0.0
props.35.configurationSource = User properties
props.36.key = maven.style.trace
props.36.key = maven.style.success
props.36.configurationType = String
props.36.description = Color style for trace messages.
props.36.defaultValue = bold,f:magenta
props.36.description = Color style for success messages.
props.36.defaultValue = bold,f:green
props.36.since = 4.0.0
props.36.configurationSource = User properties
props.37.key = maven.style.transfer
props.37.key = maven.style.trace
props.37.configurationType = String
props.37.description = Color style for transfer messages.
props.37.defaultValue = f:bright-black
props.37.description = Color style for trace messages.
props.37.defaultValue = bold,f:magenta
props.37.since = 4.0.0
props.37.configurationSource = User properties
props.38.key = maven.style.warning
props.38.key = maven.style.transfer
props.38.configurationType = String
props.38.description = Color style for warning messages.
props.38.defaultValue = bold,f:yellow
props.38.description = Color style for transfer messages.
props.38.defaultValue = f:bright-black
props.38.since = 4.0.0
props.38.configurationSource = User properties
props.39.key = maven.user.conf
props.39.key = maven.style.warning
props.39.configurationType = String
props.39.description = Maven user configuration directory.
props.39.defaultValue = ${user.home}/.m2
props.39.description = Color style for warning messages.
props.39.defaultValue = bold,f:yellow
props.39.since = 4.0.0
props.39.configurationSource = User properties
props.40.key = maven.user.extensions
props.40.key = maven.user.conf
props.40.configurationType = String
props.40.description = Maven user extensions.
props.40.defaultValue = ${maven.user.conf}/extensions.xml
props.40.description = Maven user configuration directory.
props.40.defaultValue = ${user.home}/.m2
props.40.since = 4.0.0
props.40.configurationSource = User properties
props.41.key = maven.user.settings
props.41.key = maven.user.extensions
props.41.configurationType = String
props.41.description = Maven user settings.
props.41.defaultValue = ${maven.user.conf}/settings.xml
props.41.description = Maven user extensions.
props.41.defaultValue = ${maven.user.conf}/extensions.xml
props.41.since = 4.0.0
props.41.configurationSource = User properties
props.42.key = maven.user.toolchains
props.42.key = maven.user.settings
props.42.configurationType = String
props.42.description = Maven user toolchains.
props.42.defaultValue = ${maven.user.conf}/toolchains.xml
props.42.description = Maven user settings.
props.42.defaultValue = ${maven.user.conf}/settings.xml
props.42.since = 4.0.0
props.42.configurationSource = User properties
props.43.key = maven.versionResolver.noCache
props.43.configurationType = Boolean
props.43.description = User property for disabling version resolver cache.
props.43.defaultValue = false
props.43.since = 3.0.0
props.43.key = maven.user.toolchains
props.43.configurationType = String
props.43.description = Maven user toolchains.
props.43.defaultValue = ${maven.user.conf}/toolchains.xml
props.43.since = 4.0.0
props.43.configurationSource = User properties
props.44.key = maven.versionResolver.noCache
props.44.configurationType = Boolean
props.44.description = User property for disabling version resolver cache.
props.44.defaultValue = false
props.44.since = 3.0.0
props.44.configurationSource = User properties

View File

@ -171,6 +171,12 @@ props:
description: ""
defaultValue: ${maven.user.conf}/settings-security4.xml
configurationSource: User properties
- key: maven.startInstant
configurationType: String
description: "User property used to store the build timestamp."
defaultValue:
since: 4.1.0
configurationSource: User properties
- key: maven.style.color
configurationType: String
description: "Maven output color mode. Allowed values are <code>auto</code>, <code>always</code>, <code>never</code>."

View File

@ -51,21 +51,22 @@ under the License.
| 24. | `maven.resolver.transport` | `String` | Resolver transport to use. Can be <code>default</code>, <code>wagon</code>, <code>apache</code>, <code>jdk</code> or <code>auto</code>. | `default` | 4.0.0 | User properties |
| 25. | `maven.session.versionFilter` | `String` | User property for version filter expression used in session, applied to resolving ranges: a semicolon separated list of filters to apply. By default, no version filter is applied (like in Maven 3). <br/> Supported filters: <ul> <li>"h" or "h(num)" - highest version or top list of highest ones filter</li> <li>"l" or "l(num)" - lowest version or bottom list of lowest ones filter</li> <li>"s" - contextual snapshot filter</li> <li>"e(G:A:V)" - predicate filter (leaves out G:A:V from range, if hit, V can be range)</li> </ul> Example filter expression: <code>"h(5);s;e(org.foo:bar:1)</code> will cause: ranges are filtered for "top 5" (instead full range), snapshots are banned if root project is not a snapshot, and if range for <code>org.foo:bar</code> is being processed, version 1 is omitted. Value in this property builds <code>org.eclipse.aether.collection.VersionFilter</code> instance. | - | 4.0.0 | User properties |
| 26. | `maven.settings.security` | `String` | | `${maven.user.conf}/settings-security4.xml` | | User properties |
| 27. | `maven.style.color` | `String` | Maven output color mode. Allowed values are <code>auto</code>, <code>always</code>, <code>never</code>. | `auto` | 4.0.0 | User properties |
| 28. | `maven.style.debug` | `String` | Color style for debug messages. | `bold,f:cyan` | 4.0.0 | User properties |
| 29. | `maven.style.error` | `String` | Color style for error messages. | `bold,f:red` | 4.0.0 | User properties |
| 30. | `maven.style.failure` | `String` | Color style for failure messages. | `bold,f:red` | 4.0.0 | User properties |
| 31. | `maven.style.info` | `String` | Color style for info messages. | `bold,f:blue` | 4.0.0 | User properties |
| 32. | `maven.style.mojo` | `String` | Color style for mojo messages. | `f:green` | 4.0.0 | User properties |
| 33. | `maven.style.project` | `String` | Color style for project messages. | `f:cyan` | 4.0.0 | User properties |
| 34. | `maven.style.strong` | `String` | Color style for strong messages. | `bold` | 4.0.0 | User properties |
| 35. | `maven.style.success` | `String` | Color style for success messages. | `bold,f:green` | 4.0.0 | User properties |
| 36. | `maven.style.trace` | `String` | Color style for trace messages. | `bold,f:magenta` | 4.0.0 | User properties |
| 37. | `maven.style.transfer` | `String` | Color style for transfer messages. | `f:bright-black` | 4.0.0 | User properties |
| 38. | `maven.style.warning` | `String` | Color style for warning messages. | `bold,f:yellow` | 4.0.0 | User properties |
| 39. | `maven.user.conf` | `String` | Maven user configuration directory. | `${user.home}/.m2` | 4.0.0 | User properties |
| 40. | `maven.user.extensions` | `String` | Maven user extensions. | `${maven.user.conf}/extensions.xml` | 4.0.0 | User properties |
| 41. | `maven.user.settings` | `String` | Maven user settings. | `${maven.user.conf}/settings.xml` | 4.0.0 | User properties |
| 42. | `maven.user.toolchains` | `String` | Maven user toolchains. | `${maven.user.conf}/toolchains.xml` | 4.0.0 | User properties |
| 43. | `maven.versionResolver.noCache` | `Boolean` | User property for disabling version resolver cache. | `false` | 3.0.0 | User properties |
| 27. | `maven.startInstant` | `String` | User property used to store the build timestamp. | - | 4.1.0 | User properties |
| 28. | `maven.style.color` | `String` | Maven output color mode. Allowed values are <code>auto</code>, <code>always</code>, <code>never</code>. | `auto` | 4.0.0 | User properties |
| 29. | `maven.style.debug` | `String` | Color style for debug messages. | `bold,f:cyan` | 4.0.0 | User properties |
| 30. | `maven.style.error` | `String` | Color style for error messages. | `bold,f:red` | 4.0.0 | User properties |
| 31. | `maven.style.failure` | `String` | Color style for failure messages. | `bold,f:red` | 4.0.0 | User properties |
| 32. | `maven.style.info` | `String` | Color style for info messages. | `bold,f:blue` | 4.0.0 | User properties |
| 33. | `maven.style.mojo` | `String` | Color style for mojo messages. | `f:green` | 4.0.0 | User properties |
| 34. | `maven.style.project` | `String` | Color style for project messages. | `f:cyan` | 4.0.0 | User properties |
| 35. | `maven.style.strong` | `String` | Color style for strong messages. | `bold` | 4.0.0 | User properties |
| 36. | `maven.style.success` | `String` | Color style for success messages. | `bold,f:green` | 4.0.0 | User properties |
| 37. | `maven.style.trace` | `String` | Color style for trace messages. | `bold,f:magenta` | 4.0.0 | User properties |
| 38. | `maven.style.transfer` | `String` | Color style for transfer messages. | `f:bright-black` | 4.0.0 | User properties |
| 39. | `maven.style.warning` | `String` | Color style for warning messages. | `bold,f:yellow` | 4.0.0 | User properties |
| 40. | `maven.user.conf` | `String` | Maven user configuration directory. | `${user.home}/.m2` | 4.0.0 | User properties |
| 41. | `maven.user.extensions` | `String` | Maven user extensions. | `${maven.user.conf}/extensions.xml` | 4.0.0 | User properties |
| 42. | `maven.user.settings` | `String` | Maven user settings. | `${maven.user.conf}/settings.xml` | 4.0.0 | User properties |
| 43. | `maven.user.toolchains` | `String` | Maven user toolchains. | `${maven.user.conf}/toolchains.xml` | 4.0.0 | User properties |
| 44. | `maven.versionResolver.noCache` | `Boolean` | User property for disabling version resolver cache. | `false` | 3.0.0 | User properties |