You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by hb...@apache.org on 2020/03/28 10:14:56 UTC
[maven-studies] branch maven-buildinfo-plugin updated: refactoring:
extracted ReferenceBuildinfoUtil
This is an automated email from the ASF dual-hosted git repository.
hboutemy pushed a commit to branch maven-buildinfo-plugin
in repository https://gitbox.apache.org/repos/asf/maven-studies.git
The following commit(s) were added to refs/heads/maven-buildinfo-plugin by this push:
new 80d90e1 refactoring: extracted ReferenceBuildinfoUtil
80d90e1 is described below
commit 80d90e1ae0455d5b0f7c33ff122be9eb65ac6299
Author: Hervé Boutemy <hb...@apache.org>
AuthorDate: Sat Mar 28 11:14:52 2020 +0100
refactoring: extracted ReferenceBuildinfoUtil
---
.../maven/plugins/buildinfo/BuildInfoWriter.java | 32 +++
.../maven/plugins/buildinfo/BuildinfoMojo.java | 243 ++++++---------------
.../plugins/buildinfo/ReferenceBuildinfoUtil.java | 212 ++++++++++++++++++
3 files changed, 307 insertions(+), 180 deletions(-)
diff --git a/src/main/java/org/apache/maven/plugins/buildinfo/BuildInfoWriter.java b/src/main/java/org/apache/maven/plugins/buildinfo/BuildInfoWriter.java
index 61b45d3..0942172 100644
--- a/src/main/java/org/apache/maven/plugins/buildinfo/BuildInfoWriter.java
+++ b/src/main/java/org/apache/maven/plugins/buildinfo/BuildInfoWriter.java
@@ -20,14 +20,17 @@ package org.apache.maven.plugins.buildinfo;
*/
import java.io.File;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
+import java.util.Properties;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.PropertyUtils;
/**
* Buildinfo content writer.
@@ -169,4 +172,33 @@ public class BuildInfoWriter
{
return artifacts;
}
+
+ /**
+ * Load buildinfo file and extracts properties on output files.
+ *
+ * @param buildinfo the build info file
+ * @return output properties
+ * @throws MojoExecutionException
+ */
+ public static Properties loadOutputProperties( File buildinfo )
+ throws MojoExecutionException
+ {
+ try
+ {
+ Properties prop = PropertyUtils.loadProperties( buildinfo );
+ for ( String name : prop.stringPropertyNames() )
+ {
+ if ( !name.startsWith( "outputs." ) || name.endsWith( ".coordinates" ) )
+ {
+ prop.remove( name );
+ }
+ }
+ return prop;
+ }
+ catch ( IOException ioe )
+ {
+ throw new MojoExecutionException( "Error reading buildinfo file " + buildinfo, ioe );
+ }
+ }
+
}
diff --git a/src/main/java/org/apache/maven/plugins/buildinfo/BuildinfoMojo.java b/src/main/java/org/apache/maven/plugins/buildinfo/BuildinfoMojo.java
index 1732f00..8240435 100644
--- a/src/main/java/org/apache/maven/plugins/buildinfo/BuildinfoMojo.java
+++ b/src/main/java/org/apache/maven/plugins/buildinfo/BuildinfoMojo.java
@@ -22,7 +22,6 @@ package org.apache.maven.plugins.buildinfo;
import org.apache.commons.codec.Charsets;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
-import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
@@ -33,16 +32,9 @@ import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.shared.utils.logging.MessageUtils;
-import org.codehaus.plexus.util.FileUtils;
-import org.codehaus.plexus.util.PropertyUtils;
-import org.eclipse.aether.AbstractForwardingRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
-import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.repository.RemoteRepository;
-import org.eclipse.aether.repository.WorkspaceReader;
-import org.eclipse.aether.resolution.ArtifactRequest;
-import org.eclipse.aether.resolution.ArtifactResult;
import java.io.BufferedWriter;
import java.io.File;
@@ -50,7 +42,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -110,11 +101,6 @@ public class BuildinfoMojo
private String referenceRepo;
/**
- * Directory of the downloaded reference files.
- */
- private File referenceDir;
-
- /**
* Used for attaching the buildinfo file in the project.
*/
@Component
@@ -149,17 +135,19 @@ public class BuildinfoMojo
if ( !mono )
{
// if multi-module build, generate (aggregate) buildinfo only in last module
- MavenProject aggregate = reactorProjects.get( reactorProjects.size() - 1 );
- if ( project != aggregate )
+ MavenProject last = reactorProjects.get( reactorProjects.size() - 1 );
+ if ( project != last )
{
- getLog().info( "Skip intermediate buildinfo, aggregate will be " + aggregate.getArtifactId() );
+ getLog().info( "Skipping intermediate buildinfo, aggregate will be " + last.getArtifactId() );
return;
}
}
+ // generate buildinfo
Map<Artifact, String> artifacts = generateBuildinfo( mono );
getLog().info( "Saved " + ( mono ? "" : "aggregate " ) + "info on build to " + buildinfoFile );
+ // eventually attach
if ( attach )
{
projectHelper.attachArtifact( project, "buildinfo", buildinfoFile );
@@ -169,6 +157,7 @@ public class BuildinfoMojo
getLog().info( "NOT adding buildinfo to the list of attached artifacts." );
}
+ // eventually check against reference
if ( referenceRepo != null )
{
getLog().info( "Checking against reference build from " + referenceRepo + "..." );
@@ -176,6 +165,14 @@ public class BuildinfoMojo
}
}
+ /**
+ * Generate buildinfo file.
+ *
+ * @param mono is it a mono-module build?
+ * @return a Map of artifacts added to the build info with their associated property key prefix
+ * (<code>outputs.[#module.].#artifact</code>)
+ * @throws MojoExecutionException
+ */
private Map<Artifact, String> generateBuildinfo( boolean mono )
throws MojoExecutionException
{
@@ -183,8 +180,6 @@ public class BuildinfoMojo
buildinfoFile.getParentFile().mkdirs();
- referenceDir = new File( root.getBuild().getDirectory(), "reference" );
-
try ( PrintWriter p = new PrintWriter( new BufferedWriter(
new OutputStreamWriter( new FileOutputStream( buildinfoFile ), Charsets.ISO_8859_1 ) ) ) )
{
@@ -204,6 +199,7 @@ public class BuildinfoMojo
bi.printArtifacts( project );
}
}
+
return bi.getArtifacts();
}
catch ( IOException e )
@@ -212,81 +208,61 @@ public class BuildinfoMojo
}
}
- private MavenProject getExecutionRoot()
- {
- for ( MavenProject p : reactorProjects )
- {
- if ( p.isExecutionRoot() )
- {
- return p;
- }
- }
- return null;
- }
-
+ /**
+ * Check current build result with reference.
+ *
+ * @param mono is it a mono-module build?
+ * @artifacts a Map of artifacts added to the build info with their associated property key prefix
+ * (<code>outputs.[#module.].#artifact</code>)
+ * @throws MojoExecutionException
+ */
private void checkAgainstReference( boolean mono, Map<Artifact, String> artifacts )
throws MojoExecutionException
{
- RemoteRepository repo = createReferenceRepo();
+ MavenProject root = mono ? project : getExecutionRoot();
+ File referenceDir = new File( root.getBuild().getDirectory(), "reference" );
referenceDir.mkdirs();
- File referenceBuildinfo = downloadReferenceBuildinfo( repo );
+ // download or create reference buildinfo
+ File referenceBuildinfo = downloadOrCreateReferenceBuildinfo( mono, artifacts, referenceDir );
- if ( referenceBuildinfo == null )
- {
- // download reference artifacts
- for ( Artifact artifact : artifacts.keySet() )
- {
- try
- {
- downloadReference( repo, artifact );
- }
- catch ( ArtifactNotFoundException e )
- {
- getLog().warn( "Reference artifact not found " + artifact );
- }
- }
+ // compare outputs from reference buildinfo vs actual
+ compareWithReference( artifacts, referenceBuildinfo );
+ }
- // generate buildinfo from reference artifacts
- referenceBuildinfo = getReference( buildinfoFile );
- try ( PrintWriter p =
- new PrintWriter( new BufferedWriter( new OutputStreamWriter( new FileOutputStream( referenceBuildinfo ),
- Charsets.ISO_8859_1 ) ) ) )
- {
- BuildInfoWriter bi = new BuildInfoWriter( getLog(), p, mono );
+ private File downloadOrCreateReferenceBuildinfo( boolean mono, Map<Artifact, String> artifacts, File referenceDir )
+ throws MojoExecutionException
+ {
+ RemoteRepository repo = createReferenceRepo();
- for ( Map.Entry<Artifact, String> entry : artifacts.entrySet() )
- {
- Artifact artifact = entry.getKey();
- String prefix = entry.getValue();
- bi.printFile( prefix, getReference( artifact.getFile() ) );
- }
+ ReferenceBuildinfoUtil rmb = new ReferenceBuildinfoUtil( getLog(), referenceDir, artifacts,
+ artifactFactory, repoSystem, repoSession );
- getLog().info( "Minimal buildinfo generated from downloaded artifacts: " + referenceBuildinfo );
- }
- catch ( IOException e )
- {
- throw new MojoExecutionException( "Error creating file " + referenceBuildinfo, e );
- }
- }
+ return rmb.downloadOrCreateReferenceBuildinfo( repo, project, buildinfoFile, mono );
+ }
+
+ private void compareWithReference( Map<Artifact, String> artifacts, File referenceBuildinfo )
+ throws MojoExecutionException
+ {
+ Properties actual = BuildInfoWriter.loadOutputProperties( buildinfoFile );
+ Properties reference = BuildInfoWriter.loadOutputProperties( referenceBuildinfo );
- // compare outputs from reference buildinfo vs actual
- Properties actual = loadOutputProperties( buildinfoFile );
- Properties reference = loadOutputProperties( referenceBuildinfo );
int ok = 0;
+ File referenceDir = referenceBuildinfo.getParentFile();
for ( Map.Entry<Artifact, String> entry : artifacts.entrySet() )
{
Artifact artifact = entry.getKey();
String prefix = entry.getValue();
- if ( checkArtifact( artifact, prefix, reference, actual ) )
+ if ( checkArtifact( artifact, prefix, reference, actual, referenceDir ) )
{
ok++;
}
}
int ko = artifacts.size() - ok;
- int missing = reference.size() / 3;
+ int missing = reference.size() / 3 /* 3 property keys par file: filename, length and checksums.sha512 */;
+
if ( ko + missing > 0 )
{
getLog().warn( "Reproducible Build output summary: " + ok + " files ok, " + ko + " different, " + missing
@@ -299,7 +275,8 @@ public class BuildinfoMojo
}
}
- private boolean checkArtifact( Artifact artifact, String prefix, Properties reference, Properties actual )
+ private boolean checkArtifact( Artifact artifact, String prefix, Properties reference, Properties actual,
+ File referenceDir )
{
String actualFilename = (String) actual.remove( prefix + ".filename" );
String actualLength = (String) actual.remove( prefix + ".length" );
@@ -311,22 +288,23 @@ public class BuildinfoMojo
if ( !actualLength.equals( referenceLength ) )
{
- getLog().warn( "size mismatch " + MessageUtils.buffer().strong( actualFilename ) + diffoscope( artifact ) );
+ getLog().warn( "size mismatch " + MessageUtils.buffer().strong( actualFilename )
+ + diffoscope( artifact, referenceDir ) );
return false;
}
else if ( !actualSha512.equals( referenceSha512 ) )
{
getLog().warn( "sha512 mismatch " + MessageUtils.buffer().strong( actualFilename )
- + diffoscope( artifact ) );
+ + diffoscope( artifact, referenceDir ) );
return false;
}
return true;
}
- private String diffoscope( Artifact a )
+ private String diffoscope( Artifact a, File referenceDir )
{
File actual = a.getFile();
- File reference = getReference( actual );
+ File reference = new File( referenceDir, actual.getName() );
return ": diffoscope " + relative( reference ) + " " + relative( actual );
}
@@ -348,90 +326,6 @@ public class BuildinfoMojo
return null;
}
- private Properties loadOutputProperties( File buildinfo )
- throws MojoExecutionException
- {
- try
- {
- Properties prop = PropertyUtils.loadProperties( buildinfo );
- for ( String name : prop.stringPropertyNames() )
- {
- if ( ! name.startsWith( "outputs." ) || name.endsWith( ".coordinates" ) )
- {
- prop.remove( name );
- }
- }
- return prop;
- }
- catch ( IOException ioe )
- {
- throw new MojoExecutionException( "Error reading buildinfo file " + buildinfo, ioe );
- }
- }
-
- private File downloadReferenceBuildinfo( RemoteRepository repo )
- throws MojoExecutionException
- {
- Artifact buildinfo =
- artifactFactory.createArtifactWithClassifier( project.getGroupId(), project.getArtifactId(),
- project.getVersion(), "buildinfo", "" );
- try
- {
- File file = downloadReference( repo, buildinfo );
-
- getLog().info( "Reference buildinfo file found, copied to " + file );
-
- return file;
- }
- catch ( ArtifactNotFoundException e )
- {
- getLog().warn( "Reference buildinfo file not found: "
- + "it will be generated from downloaded reference artifacts" );
- }
-
- return null;
- }
-
- private File downloadReference( RemoteRepository repo, Artifact artifact )
- throws MojoExecutionException, ArtifactNotFoundException
- {
- try
- {
- ArtifactRequest request = new ArtifactRequest();
- request.setArtifact( new DefaultArtifact( artifact.getGroupId(), artifact.getArtifactId(),
- artifact.getClassifier(),
- artifact.getArtifactHandler().getExtension(),
- artifact.getVersion() ) );
- request.setRepositories( Collections.singletonList( repo ) );
-
- ArtifactResult result =
- repoSystem.resolveArtifact( new NoWorkspaceRepositorySystemSession( repoSession ), request );
- File resultFile = result.getArtifact().getFile();
- File destFile = getReference( resultFile );
-
- FileUtils.copyFile( resultFile, destFile );
-
- return destFile;
- }
- catch ( org.eclipse.aether.resolution.ArtifactResolutionException are )
- {
- if ( are.getResult().isMissing() )
- {
- throw new ArtifactNotFoundException( "Artifact not found " + artifact, artifact );
- }
- throw new MojoExecutionException( "Error resolving reference artifact " + artifact, are );
- }
- catch ( IOException ioe )
- {
- throw new MojoExecutionException( "Error copying reference artifact " + artifact, ioe );
- }
- }
-
- private File getReference( File file )
- {
- return new File( referenceDir, file.getName() );
- }
-
private RemoteRepository createReferenceRepo()
throws MojoExecutionException
{
@@ -460,31 +354,20 @@ public class BuildinfoMojo
throw new MojoExecutionException( "Could not find repository with id = " + referenceRepo );
}
- protected RemoteRepository createDeploymentArtifactRepository( String id, String url )
+ private RemoteRepository createDeploymentArtifactRepository( String id, String url )
{
return new RemoteRepository.Builder( id, "default", url ).build();
}
- private static class NoWorkspaceRepositorySystemSession
- extends AbstractForwardingRepositorySystemSession
+ private MavenProject getExecutionRoot()
{
- private final RepositorySystemSession rss;
-
- NoWorkspaceRepositorySystemSession( RepositorySystemSession rss )
- {
- this.rss = rss;
- }
-
- @Override
- protected RepositorySystemSession getSession()
- {
- return rss;
- }
-
- @Override
- public WorkspaceReader getWorkspaceReader()
+ for ( MavenProject p : reactorProjects )
{
- return null;
+ if ( p.isExecutionRoot() )
+ {
+ return p;
+ }
}
+ return null;
}
}
diff --git a/src/main/java/org/apache/maven/plugins/buildinfo/ReferenceBuildinfoUtil.java b/src/main/java/org/apache/maven/plugins/buildinfo/ReferenceBuildinfoUtil.java
new file mode 100644
index 0000000..c4dc37b
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/buildinfo/ReferenceBuildinfoUtil.java
@@ -0,0 +1,212 @@
+package org.apache.maven.plugins.buildinfo;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.codec.Charsets;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.FileUtils;
+import org.eclipse.aether.AbstractForwardingRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.repository.WorkspaceReader;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResult;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Utility to download or generate reference buildinfo.
+ */
+public class ReferenceBuildinfoUtil
+{
+ private final Log log;
+
+ /**
+ * Directory of the downloaded reference files.
+ */
+ private final File referenceDir;
+
+ private final Map<Artifact, String> artifacts;
+
+ private final ArtifactFactory artifactFactory;
+
+ private final RepositorySystem repoSystem;
+
+ private final RepositorySystemSession repoSession;
+
+ public ReferenceBuildinfoUtil( Log log, File referenceDir, Map<Artifact, String> artifacts,
+ ArtifactFactory artifactFactory, RepositorySystem repoSystem,
+ RepositorySystemSession repoSession )
+ {
+ this.log = log;
+ this.referenceDir = referenceDir;
+ this.artifacts = artifacts;
+ this.artifactFactory = artifactFactory;
+ this.repoSystem = repoSystem;
+ this.repoSession = repoSession;
+ }
+
+ public File downloadOrCreateReferenceBuildinfo( RemoteRepository repo, MavenProject project, File buildinfoFile,
+ boolean mono )
+ throws MojoExecutionException
+ {
+ File referenceBuildinfo = downloadReferenceBuildinfo( repo, project );
+
+ if ( referenceBuildinfo == null )
+ {
+ // download reference artifacts
+ for ( Artifact artifact : artifacts.keySet() )
+ {
+ try
+ {
+ downloadReference( repo, artifact );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ log.warn( "Reference artifact not found " + artifact );
+ }
+ }
+
+ // generate buildinfo from reference artifacts
+ referenceBuildinfo = getReference( buildinfoFile );
+ try ( PrintWriter p =
+ new PrintWriter( new BufferedWriter( new OutputStreamWriter( new FileOutputStream( referenceBuildinfo ),
+ Charsets.ISO_8859_1 ) ) ) )
+ {
+ BuildInfoWriter bi = new BuildInfoWriter( log, p, mono );
+
+ for ( Map.Entry<Artifact, String> entry : artifacts.entrySet() )
+ {
+ Artifact artifact = entry.getKey();
+ String prefix = entry.getValue();
+ bi.printFile( prefix, getReference( artifact.getFile() ) );
+ }
+
+ log.info( "Minimal buildinfo generated from downloaded artifacts: " + referenceBuildinfo );
+ }
+ catch ( IOException e )
+ {
+ throw new MojoExecutionException( "Error creating file " + referenceBuildinfo, e );
+ }
+ }
+
+ return referenceBuildinfo;
+ }
+
+ private File downloadReferenceBuildinfo( RemoteRepository repo, MavenProject project )
+ throws MojoExecutionException
+ {
+ Artifact buildinfo =
+ artifactFactory.createArtifactWithClassifier( project.getGroupId(), project.getArtifactId(),
+ project.getVersion(), "buildinfo", "" );
+ try
+ {
+ File file = downloadReference( repo, buildinfo );
+
+ log.info( "Reference buildinfo file found, copied to " + file );
+
+ return file;
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ log.warn( "Reference buildinfo file not found: "
+ + "it will be generated from downloaded reference artifacts" );
+ }
+
+ return null;
+ }
+
+ private File downloadReference( RemoteRepository repo, Artifact artifact )
+ throws MojoExecutionException, ArtifactNotFoundException
+ {
+ try
+ {
+ ArtifactRequest request = new ArtifactRequest();
+ request.setArtifact( new DefaultArtifact( artifact.getGroupId(), artifact.getArtifactId(),
+ artifact.getClassifier(),
+ artifact.getArtifactHandler().getExtension(),
+ artifact.getVersion() ) );
+ request.setRepositories( Collections.singletonList( repo ) );
+
+ ArtifactResult result =
+ repoSystem.resolveArtifact( new NoWorkspaceRepositorySystemSession( repoSession ), request );
+ File resultFile = result.getArtifact().getFile();
+ File destFile = getReference( resultFile );
+
+ FileUtils.copyFile( resultFile, destFile );
+
+ return destFile;
+ }
+ catch ( org.eclipse.aether.resolution.ArtifactResolutionException are )
+ {
+ if ( are.getResult().isMissing() )
+ {
+ throw new ArtifactNotFoundException( "Artifact not found " + artifact, artifact );
+ }
+ throw new MojoExecutionException( "Error resolving reference artifact " + artifact, are );
+ }
+ catch ( IOException ioe )
+ {
+ throw new MojoExecutionException( "Error copying reference artifact " + artifact, ioe );
+ }
+ }
+
+ private File getReference( File file )
+ {
+ return new File( referenceDir, file.getName() );
+ }
+
+ private static class NoWorkspaceRepositorySystemSession
+ extends AbstractForwardingRepositorySystemSession
+ {
+ private final RepositorySystemSession rss;
+
+ NoWorkspaceRepositorySystemSession( RepositorySystemSession rss )
+ {
+ this.rss = rss;
+ }
+
+ @Override
+ protected RepositorySystemSession getSession()
+ {
+ return rss;
+ }
+
+ @Override
+ public WorkspaceReader getWorkspaceReader()
+ {
+ return null;
+ }
+ }
+}