88import org .apache .maven .plugins .annotations .Component ;
99import org .apache .maven .plugins .annotations .Parameter ;
1010import org .apache .maven .project .MavenProjectHelper ;
11+ import org .codehaus .plexus .util .FileUtils ;
1112import org .eclipse .aether .RepositorySystemSession ;
12- import org .eclipse .aether .artifact .Artifact ;
1313import org .eclipse .aether .artifact .DefaultArtifact ;
1414import org .eclipse .aether .impl .ArtifactResolver ;
1515import org .eclipse .aether .repository .LocalRepository ;
1818import org .eclipse .aether .resolution .ArtifactResolutionException ;
1919import org .eclipse .aether .resolution .ArtifactResult ;
2020
21+ import java .io .BufferedReader ;
2122import java .io .File ;
23+ import java .io .FileInputStream ;
24+ import java .io .FileOutputStream ;
25+ import java .io .IOException ;
26+ import java .io .InputStreamReader ;
27+ import java .io .OutputStreamWriter ;
28+ import java .io .PrintWriter ;
2229import java .lang .reflect .Field ;
30+ import java .nio .charset .Charset ;
2331import java .nio .file .Files ;
2432import java .util .ArrayList ;
2533import java .util .Arrays ;
@@ -44,9 +52,12 @@ public abstract class AbstractGitflowBasedRepositoryMojo extends AbstractGitflow
4452 @ Parameter (property = "snapshotDeploymentRepository" , required = true )
4553 protected String snapshotDeploymentRepository ;
4654
47- @ Parameter (defaultValue = "${repositorySystemSession}" )
55+ @ Parameter (defaultValue = "${repositorySystemSession}" , required = true )
4856 private RepositorySystemSession session ;
4957
58+ @ Parameter (defaultValue = "${project.build.directory}" , required = true )
59+ protected File buildDirectory ;
60+
5061 @ Component
5162 protected ArtifactRepositoryFactory repositoryFactory ;
5263
@@ -62,6 +73,7 @@ public abstract class AbstractGitflowBasedRepositoryMojo extends AbstractGitflow
6273 /**
6374 * Builds an ArtifactRepository for targeting deployments
6475 * .
76+ *
6577 * @param altRepository
6678 * @return
6779 * @throws MojoExecutionException
@@ -109,10 +121,99 @@ private RemoteRepository getRepository(final String altRepository) throws MojoEx
109121 return new RemoteRepository .Builder (id , layout , url ).build ();
110122 }
111123
124+ private String getCoordinates (ArtifactResult result ) {
125+ StringBuilder buffer = new StringBuilder ( 128 );
126+ buffer .append ( result .getArtifact ().getGroupId () );
127+ buffer .append ( ':' ).append ( result .getArtifact ().getArtifactId () );
128+ buffer .append ( ':' ).append ( result .getArtifact ().getExtension () );
129+ if ( result .getArtifact ().getClassifier ().length () > 0 )
130+ {
131+ buffer .append ( ':' ).append ( result .getArtifact ().getClassifier () );
132+ }
133+ buffer .append ( ':' ).append ( result .getArtifact ().getBaseVersion () );
134+ return buffer .toString ();
135+ }
136+
137+ private String getCoordinates (org .apache .maven .artifact .Artifact artifact ) {
138+ StringBuilder result = new StringBuilder ();
139+
140+ getLog ().debug (" Encoding Coordinates For: " + artifact );
141+
142+ // Get the extension according to the artifact type.
143+ String extension = session .getArtifactTypeRegistry ().get (artifact .getType ()).getExtension ();
144+
145+ // assert that the file extension matches the artifact packaging extension type, if there is an artifact file.
146+ if (artifact .getFile () != null && !artifact .getFile ().getName ().toLowerCase ().endsWith (extension .toLowerCase ())) {
147+ String fileExtension = artifact .getFile ().getName ().substring (artifact .getFile ().getName ().lastIndexOf ('.' ) + 1 );
148+ getLog ().warn (" Artifact file name: " + artifact .getFile ().getName () + " of type " +
149+ artifact .getType () + " does not match the extension for the ArtifactType: " + extension + ". " +
150+ "This is likely an issue with the packaging definition for '" + artifact .getType () + "' artifacts, which may be missing an extension definition. " +
151+ "The gitflow helper catalog will use the actual file extension: " + fileExtension );
152+ extension = fileExtension ;
153+ }
154+
155+ // group:artifact:extension
156+ result .append (project .getGroupId ()).append (":" ).append (project .getArtifactId ()).append (":" ).append (extension );
157+ if (artifact .hasClassifier ()) {
158+ // :classifier
159+ result .append (":" ).append (artifact .getClassifier ());
160+ }
161+ result .append (":" ).append (project .getVersion ());
162+
163+ return result .toString ().trim ();
164+ }
112165
113166 /**
114- * Resolves artifacts from the given sourceRepository, and attaches them to the current
115- * build future downloading.
167+ * Creates and attaches an artifact containing a list of attached artifacts, each line in the file contains
168+ * group:artifact:type:classifier:version
169+ */
170+ protected void attachArtifactCatalog () throws MojoExecutionException {
171+ getLog ().info ("Cataloging Artifacts for promotion & reattachment: " + project .getBuild ().getDirectory ());
172+
173+ File catalog = new File (buildDirectory , project .getArtifact ().getArtifactId () + ".txt" );
174+
175+ PrintWriter writer = null ;
176+
177+ try {
178+ catalog .delete ();
179+ buildDirectory .mkdirs ();
180+ writer = new PrintWriter (new OutputStreamWriter (new FileOutputStream (catalog ), Charset .forName ("UTF-8" )));
181+
182+ if (project .getArtifact () != null && project .getArtifact ().getFile () != null &&
183+ project .getArtifact ().getFile ().exists () && !project .getArtifact ().getFile ().isDirectory ())
184+ {
185+ String coords = getCoordinates (project .getArtifact ());
186+ if (!coords .isEmpty ()){
187+ getLog ().info ("Cataloging: " + coords );
188+ writer .println (coords );
189+ }
190+ } else {
191+ getLog ().info ("No primary artifact to catalog, cataloging attached artifacts instead." );
192+ }
193+
194+ // Iterate the attached artifacts.
195+ for (org .apache .maven .artifact .Artifact artifact : project .getAttachedArtifacts ()) {
196+ String coords = getCoordinates (artifact );
197+ if (!coords .isEmpty ()) {
198+ getLog ().info ("Cataloging: " + coords );
199+ writer .println (coords );
200+ }
201+ }
202+
203+ getLog ().info ("Attaching catalog artifact: " + catalog );
204+ projectHelper .attachArtifact (project , "txt" , "catalog" , catalog );
205+ } catch (IOException ioe ) {
206+ throw new MojoExecutionException ("Failed to create catalog of artifacts" , ioe );
207+ } finally {
208+ if (writer != null ) {
209+ writer .close ();
210+ }
211+ }
212+ }
213+
214+ /**
215+ * Resolves artifacts from the given sourceRepository by first resolving and processing the artifact catalog
216+ * created by the promote-master mojo.
116217 *
117218 * @param sourceRepository
118219 * @throws MojoExecutionException
@@ -125,7 +226,7 @@ protected void attachExistingArtifacts(final String sourceRepository, final bool
125226 if (disableLocal == true ) {
126227 throw new MojoExecutionException ("Cannot resolve artifacts from 'null' repository if the local repository is also disabled." );
127228 }
128- getLog ().debug ("Attaching existing artifacts from local repository only." );
229+ getLog ().debug ("Resolving existing artifacts from local repository only." );
129230 } else {
130231 // Add the remote repository.
131232 remoteRepositories .addAll (Arrays .asList (getRepository (sourceRepository )));
@@ -134,25 +235,20 @@ protected void attachExistingArtifacts(final String sourceRepository, final bool
134235 // A place to store our resolved files...
135236 List <ArtifactResult > resolvedArtifacts = new ArrayList <ArtifactResult >();
136237
137-
138- // Build up a set of ArtifactRequests, for the pom, the current packaging layout, the -sources.jar and the -javadoc.jar and the
139- List <ArtifactRequest > requiredArtifacts = new ArrayList <ArtifactRequest >();
140-
141-
142238 // Keep track of the original base directory.
143239 Field localBaseDir = null ;
144240 File originalBaseDir = session .getLocalRepositoryManager ().getRepository ().getBasedir ();
145241
146- // Disable the local repository.
242+ // Disable the local repository - using a bit of reflection that I wish we didn't need to use.
243+ File tempRepo = null ;
147244 if (disableLocal ) {
148245 getLog ().info ("Disabling local repository @ " + session .getLocalRepository ().getBasedir ());
149246 try {
150247 localBaseDir = LocalRepository .class .getDeclaredField ("basedir" );
151248 localBaseDir .setAccessible (true );
152249
153250 // Generate a new temp directory.
154- File tempRepo = Files .createTempDirectory ("gitflow-helper-maven-plugin-repo" ).toFile ();
155- tempRepo .deleteOnExit ();
251+ tempRepo = Files .createTempDirectory ("gitflow-helper-maven-plugin-repo" ).toFile ();
156252
157253 getLog ().info ("Using temporary local repository @ " + tempRepo .getAbsolutePath ());
158254 localBaseDir .set (session .getLocalRepositoryManager ().getRepository (), tempRepo );
@@ -161,59 +257,89 @@ protected void attachExistingArtifacts(final String sourceRepository, final bool
161257 }
162258 }
163259
164- // Adjust for archetypes...
165- String packaging = project .getPackaging ();
166- if (project .getPackaging ().equalsIgnoreCase ("maven-archetype" )) {
167- packaging = "jar" ;
260+
261+ List <ArtifactRequest > requiredArtifacts = new ArrayList <ArtifactRequest >();
262+
263+ // Locate our text catalog classifier file. :-)
264+ BufferedReader reader = null ;
265+ try {
266+ ArtifactResult catalogResult = artifactResolver .resolveArtifact (session , new ArtifactRequest (new DefaultArtifact (project .getGroupId (), project .getArtifactId (), "catalog" , "txt" , project .getVersion ()), remoteRepositories , null ));
267+ resolvedArtifacts .add (catalogResult );
268+
269+ if (catalogResult .isResolved ()) {
270+ // Read the file line by line...
271+ reader = new BufferedReader (new InputStreamReader (new FileInputStream (catalogResult .getArtifact ().getFile ()), Charset .forName ("UTF-8" )));
272+
273+ String coords = null ;
274+ while ((coords = reader .readLine ()) != null ) {
275+ if (!coords .trim ().isEmpty ()) {
276+ // And add a new ArtifactRequest
277+ requiredArtifacts .add (new ArtifactRequest (new DefaultArtifact (coords .trim ()), remoteRepositories , null ));
278+ }
279+ }
280+ }
281+ } catch (ArtifactResolutionException are ) {
282+ throw new MojoExecutionException ("Could not locate artifact catalog in remote repository." , are );
283+ } catch (IOException ioe ) {
284+ throw new MojoExecutionException ("Could not read artifact catalog" , ioe );
285+ } finally {
286+ if (reader != null ) {
287+ try {
288+ reader .close ();
289+ } catch (IOException ioe ) {}
290+ }
168291 }
169292
170- // This artifact is required!
171- requiredArtifacts . add ( new ArtifactRequest ( new DefaultArtifact ( project . getGroupId (), project . getArtifactId (), packaging , project . getVersion ()), remoteRepositories , null ));
293+
294+ // Resolve the artifacts from the catalog (if there are any)
172295 try {
173296 resolvedArtifacts .addAll (artifactResolver .resolveArtifacts (session , requiredArtifacts ));
174297 } catch (ArtifactResolutionException are ) {
175298 throw new MojoExecutionException ("Failed to resolve the required project files from: " + sourceRepository , are );
176299 }
177300
178- // Optional Artifacts... We do these one at a time so we don't fail the build....
179- List <ArtifactRequest > optionalArtifacts = new ArrayList <ArtifactRequest >();
180- optionalArtifacts .add (new ArtifactRequest (new DefaultArtifact (project .getGroupId (), project .getArtifactId (), "javadoc" , "jar" , project .getVersion ()), remoteRepositories , null ));
181- optionalArtifacts .add (new ArtifactRequest (new DefaultArtifact (project .getGroupId (), project .getArtifactId (), "sources" , "jar" , project .getVersion ()), remoteRepositories , null ));
182- optionalArtifacts .add (new ArtifactRequest (new DefaultArtifact (project .getGroupId (), project .getArtifactId (), "tests" , "jar" , project .getVersion ()), remoteRepositories , null ));
301+ // Get the current build artifact coordindates, so that we replace rather than re-attach.
302+ String projectArtifactCoordinates = getCoordinates (project .getArtifact ());
303+ getLog ().debug ("Current Project Coordinates: " + projectArtifactCoordinates );
183304
184- for (int i = 0 ; i < optionalArtifacts .size (); i ++) {
305+ // For each artifactResult, copy it to the build directory,
306+ // update the resolved artifact data to point to the new file.
307+ // Then either set the project artifact to point to the file in the build directory, or attach the artifact.
308+ for (ArtifactResult artifactResult : resolvedArtifacts ) {
185309 try {
186- resolvedArtifacts .add (artifactResolver .resolveArtifact (session , optionalArtifacts .get (i )));
187- } catch (ArtifactResolutionException are ) {
188- if (getLog ().isDebugEnabled ()) {
189- getLog ().debug ("Optional Artifact not found: " + optionalArtifacts .get (i ).getArtifact ());
310+ FileUtils .copyFileToDirectory (artifactResult .getArtifact ().getFile (), buildDirectory );
311+ artifactResult .setArtifact (artifactResult .getArtifact ().setFile (new File (buildDirectory , artifactResult .getArtifact ().getFile ().getName ())));
312+
313+ if (getCoordinates (artifactResult ).equals (projectArtifactCoordinates )) {
314+ getLog ().debug (" Setting primary artifact: " + artifactResult .getArtifact ().getFile ());
315+ project .getArtifact ().setFile (artifactResult .getArtifact ().getFile ());
316+ } else {
317+ getLog ().debug (" Attaching artifact: " + getCoordinates (artifactResult ) + " " + artifactResult .getArtifact ().getFile ());
318+ projectHelper .attachArtifact (project , artifactResult .getArtifact ().getExtension (), artifactResult .getArtifact ().getClassifier (), artifactResult .getArtifact ().getFile ());
190319 }
320+ } catch (IOException ioe ) {
321+ throw new MojoExecutionException ("Failed to copy resolved artifact to target directory." , ioe );
191322 }
192323 }
193324
194- getLog ().info ("Attached " + resolvedArtifacts .size () + " previously built artifacts." );
195-
196- for (int i = 0 ; i < resolvedArtifacts .size (); i ++) {
197- Artifact artifact = resolvedArtifacts .get (i ).getArtifact ();
198- if (i == 0 ) {
199- project .getArtifact ().setFile (artifact .getFile ());
200- } else {
201- projectHelper .attachArtifact (project , artifact .getFile (), artifact .getClassifier ());
202- }
203- }
204-
205- // Restore the local repository.
325+ // Restore the local repository, again using reflection.
206326 if (disableLocal ) {
207327 try {
208328 localBaseDir .set (session .getLocalRepositoryManager ().getRepository (), originalBaseDir );
209329 localBaseDir .setAccessible (false );
210330 } catch (Exception ex ) {
211331 getLog ().warn ("Failed to restore original local repository path." , ex );
212332 }
333+ if (tempRepo != null ) {
334+ try {
335+ FileUtils .deleteDirectory (tempRepo );
336+ } catch (IOException e ) {
337+ getLog ().warn ("Failed to cleanup temporary repository directory: " + tempRepo );
338+ }
339+ }
213340 }
214341 }
215342
216-
217343 private ArtifactRepositoryLayout getLayout (final String id ) throws MojoExecutionException {
218344 ArtifactRepositoryLayout layout = repositoryLayouts .get (id );
219345 if (layout == null ) {
0 commit comments