Skip to content

Commit

Permalink
Use reproducible version qualifiers when project.build.outputTimestam…
Browse files Browse the repository at this point in the history
…p property is set
  • Loading branch information
Zlika authored and laeubi committed Jan 1, 2025
1 parent eeffad6 commit 4ca8978
Show file tree
Hide file tree
Showing 23 changed files with 78 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>reproducible.archive.timestamps</groupId>
<artifactId>reproducible.archive.timestamps.parent</artifactId>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>

<modules>
<module>reproducible.buildqualifier</module>
<module>reproducible.bundle</module>
<module>reproducible.bundle.feature</module>
<module>reproducible.iu</module>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Reproducible-buildqualifier
Bundle-SymbolicName: reproducible.buildqualifier
Bundle-Version: 1.0.0.qualifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
</parent>

<artifactId>reproducible.buildqualifier</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package reproducible.buildqualifier;

public class PublicClass
{

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>reproducible.archive.timestamps</groupId>
<artifactId>reproducible.archive.timestamps.parent</artifactId>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
</parent>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>reproducible.archive.timestamps</groupId>
<artifactId>reproducible.archive.timestamps.parent</artifactId>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>reproducible.archive.timestamps</groupId>
<artifactId>reproducible.archive.timestamps.parent</artifactId>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>reproducible.archive.timestamps</groupId>
<artifactId>reproducible.archive.timestamps.parent</artifactId>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
package org.eclipse.tycho.test.reproducible;

import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
Expand All @@ -21,7 +25,7 @@
import org.junit.Assert;
import org.junit.Test;

public class ReproducibleArchiveTimestampsTest extends AbstractTychoIntegrationTest {
public class ReproducibleBuildTest extends AbstractTychoIntegrationTest {
// The ZipEntry.getLastModifiedTime() method uses the default timezone to
// convert date and time fields to Instant, so we also use the default timezone
// for the expected timestamp here.
Expand All @@ -30,17 +34,17 @@ public class ReproducibleArchiveTimestampsTest extends AbstractTychoIntegrationT
.toInstant(OffsetDateTime.now().getOffset());

/**
* Check that the timestamp of the files inside the produced archives is equal
* to the one specified in the "project.build.outputTimestamp" property of the
* pom file.
* Check that the build is reproducible.
*/
@Test
public void test() throws Exception {
Verifier verifier = getVerifier("reproducible-archive-timestamps");
Verifier verifier = getVerifier("reproducible-build");
verifier.executeGoals(List.of("clean", "verify"));
verifier.verifyErrorFreeLog();

// Check timestamps of files in archives
// Check that the timestamp of the files inside the produced archives is equal
// to the one specified in the "project.build.outputTimestamp" property of the
// pom file.
checkTimestamps(verifier.getBasedir() + "/reproducible.bundle/target/reproducible.bundle-1.0.0.jar");
checkTimestamps(verifier.getBasedir() + "/reproducible.bundle/target/reproducible.bundle-1.0.0-attached.jar");
checkTimestamps(verifier.getBasedir() + "/reproducible.bundle/target/reproducible.bundle-1.0.0-sources.jar");
Expand All @@ -51,6 +55,11 @@ public void test() throws Exception {
checkTimestamps(verifier.getBasedir() + "/reproducible.iu/target/reproducible.iu-1.0.0.zip");
checkTimestamps(verifier.getBasedir() + "/reproducible.repository/target/reproducible.repository-1.0.0.zip");
checkTimestamps(verifier.getBasedir() + "/reproducible.repository/target/p2-site.zip");

// Check that the build qualifier uses the timestamp specified in the
// "project.build.outputTimestamp" property of the pom file.
checkBuildQualifier(verifier.getBasedir()
+ "/reproducible.buildqualifier/target/reproducible.buildqualifier-1.0.0-SNAPSHOT.jar");
}

private void checkTimestamps(String file) throws IOException {
Expand All @@ -62,4 +71,12 @@ private void checkTimestamps(String file) throws IOException {
}
}
}

private void checkBuildQualifier(String file) throws IOException {
try (FileSystem fileSystem = FileSystems.newFileSystem(Path.of(file))) {
Path manifest = fileSystem.getPath("META-INF/MANIFEST.MF");
List<String> lines = Files.readAllLines(manifest);
Assert.assertTrue(lines.stream().anyMatch(l -> l.equals("Bundle-Version: 1.0.0.202301010000")));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,22 @@
*******************************************************************************/
package org.eclipse.tycho.buildversion;

import java.time.Instant;
import java.util.Date;
import java.util.Optional;

import org.apache.maven.archiver.MavenArchiver;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.annotations.Component;
import org.eclipse.tycho.build.BuildTimestampProvider;

/**
* Build timestamp provider that returns the same timestamp for all projects, the
* ${maven.build.timestamp}.
* Build timestamp provider that returns the same timestamp for all projects. If
* the standard Maven property ${project.build.outputTimestamp} exists, its
* value is used for the timestamp. If it does not exist (or cannot be parsed),
* the ${maven.build.timestamp} timestamp is used instead.
*/
@Component(role = BuildTimestampProvider.class, hint = DefaultBuildTimestampProvider.ROLE_HINT)
public class DefaultBuildTimestampProvider implements BuildTimestampProvider {
Expand All @@ -31,7 +36,14 @@ public class DefaultBuildTimestampProvider implements BuildTimestampProvider {

@Override
public Date getTimestamp(MavenSession session, MavenProject project, MojoExecution execution) {
return session.getStartTime();
// Use the outputTimestamp property value if available for reproducible builds
final String outputTimestamp = (String) project.getProperties().get("project.build.outputTimestamp");
Optional<Instant> reproducibleTimestamp = MavenArchiver.parseBuildOutputTimestamp(outputTimestamp);
if (reproducibleTimestamp.isPresent()) {
return Date.from(reproducibleTimestamp.get());
} else {
return session.getStartTime();
}
}

@Override
Expand Down

0 comments on commit 4ca8978

Please sign in to comment.