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;
+        }
+    }
+}