]> source.dussan.org Git - archiva.git/blob
fa7608a75761310ea8fcbe530366ccb94515599d
[archiva.git] /
1 package org.apache.maven.repository.converter;
2
3 /*
4  * Copyright 2005-2006 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 import org.apache.maven.artifact.Artifact;
20 import org.apache.maven.artifact.factory.ArtifactFactory;
21 import org.apache.maven.artifact.repository.ArtifactRepository;
22 import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
23 import org.apache.maven.artifact.repository.metadata.Metadata;
24 import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
25 import org.apache.maven.artifact.repository.metadata.Snapshot;
26 import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
27 import org.apache.maven.artifact.repository.metadata.Versioning;
28 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
29 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
30 import org.apache.maven.model.converter.ArtifactPomRewriter;
31 import org.apache.maven.repository.converter.transaction.FileTransaction;
32 import org.apache.maven.repository.digest.Digester;
33 import org.apache.maven.repository.reporting.ArtifactReporter;
34 import org.codehaus.plexus.i18n.I18N;
35 import org.codehaus.plexus.util.FileUtils;
36 import org.codehaus.plexus.util.IOUtil;
37 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
38
39 import java.io.File;
40 import java.io.FileReader;
41 import java.io.IOException;
42 import java.io.StringReader;
43 import java.io.StringWriter;
44 import java.security.NoSuchAlgorithmException;
45 import java.util.Iterator;
46 import java.util.List;
47 import java.util.Locale;
48 import java.util.regex.Matcher;
49
50 /**
51  * Implementation of repository conversion class.
52  *
53  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
54  * @plexus.component role="org.apache.maven.repository.converter.RepositoryConverter" role-hint="default"
55  */
56 public class DefaultRepositoryConverter
57     implements RepositoryConverter
58 {
59     /**
60      * @plexus.requirement
61      */
62     private Digester digester;
63
64     /**
65      * @plexus.requirement
66      */
67     private ArtifactFactory artifactFactory;
68
69     /**
70      * @plexus.requirement
71      */
72     private ArtifactPomRewriter rewriter;
73
74     /**
75      * @plexus.configuration default-value="false"
76      */
77     private boolean force;
78
79     /**
80      * @plexus.configuration default-value="false"
81      */
82     private boolean dryrun;
83
84     /**
85      * @plexus.requirement
86      */
87     private I18N i18n;
88
89     public void convert( Artifact artifact, ArtifactRepository targetRepository, ArtifactReporter reporter )
90         throws RepositoryConversionException
91     {
92         if ( artifact.getRepository().getUrl().equals( targetRepository.getUrl() ) )
93         {
94             throw new RepositoryConversionException( getI18NString( "exception.repositories.match" ) );
95         }
96
97         if ( validateMetadata( artifact, reporter ) )
98         {
99             FileTransaction transaction = new FileTransaction();
100
101             if ( copyArtifact( artifact, targetRepository, reporter, transaction ) )
102             {
103                 if ( copyPom( artifact, targetRepository, reporter, transaction ) )
104                 {
105                     Metadata metadata = createBaseMetadata( artifact );
106                     Versioning versioning = new Versioning();
107                     versioning.addVersion( artifact.getBaseVersion() );
108                     metadata.setVersioning( versioning );
109                     updateMetadata( new ArtifactRepositoryMetadata( artifact ), targetRepository, metadata,
110                                     transaction );
111
112                     metadata = createBaseMetadata( artifact );
113                     metadata.setVersion( artifact.getBaseVersion() );
114                     versioning = new Versioning();
115
116                     Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() );
117                     if ( matcher.matches() )
118                     {
119                         Snapshot snapshot = new Snapshot();
120                         snapshot.setBuildNumber( Integer.valueOf( matcher.group( 3 ) ).intValue() );
121                         snapshot.setTimestamp( matcher.group( 2 ) );
122                         versioning.setSnapshot( snapshot );
123                     }
124
125                     // TODO: merge latest/release/snapshot from source instead
126                     metadata.setVersioning( versioning );
127                     updateMetadata( new SnapshotArtifactRepositoryMetadata( artifact ), targetRepository, metadata,
128                                     transaction );
129
130                     if ( !dryrun )
131                     {
132                         transaction.commit();
133                     }
134                     reporter.addSuccess( artifact );
135                 }
136             }
137         }
138     }
139
140     private static Metadata createBaseMetadata( Artifact artifact )
141     {
142         Metadata metadata = new Metadata();
143         metadata.setArtifactId( artifact.getArtifactId() );
144         metadata.setGroupId( artifact.getGroupId() );
145         return metadata;
146     }
147
148     private void updateMetadata( RepositoryMetadata artifactMetadata, ArtifactRepository targetRepository,
149                                  Metadata newMetadata, FileTransaction transaction )
150         throws RepositoryConversionException
151     {
152         File file = new File( targetRepository.getBasedir(),
153                               targetRepository.pathOfRemoteRepositoryMetadata( artifactMetadata ) );
154
155         Metadata metadata;
156         boolean changed;
157
158         if ( file.exists() )
159         {
160             metadata = readMetadata( file );
161             changed = metadata.merge( newMetadata );
162         }
163         else
164         {
165             changed = true;
166             metadata = newMetadata;
167         }
168
169         if ( changed )
170         {
171             StringWriter writer = null;
172             try
173             {
174                 writer = new StringWriter();
175
176                 MetadataXpp3Writer mappingWriter = new MetadataXpp3Writer();
177
178                 mappingWriter.write( writer, metadata );
179
180                 transaction.createFile( writer.toString(), file );
181             }
182             catch ( IOException e )
183             {
184                 throw new RepositoryConversionException( "Error writing target metadata", e );
185             }
186             finally
187             {
188                 IOUtil.close( writer );
189             }
190         }
191     }
192
193     private Metadata readMetadata( File file )
194         throws RepositoryConversionException
195     {
196         Metadata metadata;
197         MetadataXpp3Reader reader = new MetadataXpp3Reader();
198         FileReader fileReader = null;
199         try
200         {
201             fileReader = new FileReader( file );
202             metadata = reader.read( fileReader );
203         }
204         catch ( IOException e )
205         {
206             throw new RepositoryConversionException( "Error reading target metadata", e );
207         }
208         catch ( XmlPullParserException e )
209         {
210             throw new RepositoryConversionException( "Error reading target metadata", e );
211         }
212         finally
213         {
214             IOUtil.close( fileReader );
215         }
216         return metadata;
217     }
218
219     private boolean validateMetadata( Artifact artifact, ArtifactReporter reporter )
220         throws RepositoryConversionException
221     {
222         ArtifactRepository repository = artifact.getRepository();
223
224         boolean result = true;
225
226         RepositoryMetadata repositoryMetadata = new ArtifactRepositoryMetadata( artifact );
227         File file =
228             new File( repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata( repositoryMetadata ) );
229         if ( file.exists() )
230         {
231             Metadata metadata = readMetadata( file );
232             result = validateMetadata( metadata, repositoryMetadata, artifact, reporter );
233         }
234
235         repositoryMetadata = new SnapshotArtifactRepositoryMetadata( artifact );
236         file = new File( repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata( repositoryMetadata ) );
237         if ( file.exists() )
238         {
239             Metadata metadata = readMetadata( file );
240             result = result && validateMetadata( metadata, repositoryMetadata, artifact, reporter );
241         }
242
243         return result;
244     }
245
246     private boolean validateMetadata( Metadata metadata, RepositoryMetadata repositoryMetadata, Artifact artifact,
247                                       ArtifactReporter reporter )
248     {
249         String key = "failure.incorrect.";
250
251         if ( repositoryMetadata.storedInGroupDirectory() )
252         {
253             key += "groupMetadata.";
254         }
255         else if ( repositoryMetadata.storedInArtifactVersionDirectory() )
256         {
257             key += "snapshotMetadata.";
258         }
259         else
260         {
261             key += "artifactMetadata.";
262         }
263
264         boolean result = true;
265
266         if ( !metadata.getGroupId().equals( artifact.getGroupId() ) )
267         {
268             reporter.addFailure( artifact, getI18NString( key + "groupId" ) );
269             result = false;
270         }
271         if ( !repositoryMetadata.storedInGroupDirectory() )
272         {
273             if ( !metadata.getArtifactId().equals( artifact.getArtifactId() ) )
274             {
275                 reporter.addFailure( artifact, getI18NString( key + "artifactId" ) );
276                 result = false;
277             }
278             if ( !repositoryMetadata.storedInArtifactVersionDirectory() )
279             {
280                 // artifact metadata
281
282                 boolean foundVersion = false;
283                 if ( metadata.getVersioning() != null )
284                 {
285                     for ( Iterator i = metadata.getVersioning().getVersions().iterator();
286                           i.hasNext() && !foundVersion; )
287                     {
288                         String version = (String) i.next();
289                         if ( version.equals( artifact.getBaseVersion() ) )
290                         {
291                             foundVersion = true;
292                         }
293                     }
294                 }
295
296                 if ( !foundVersion )
297                 {
298                     reporter.addFailure( artifact, getI18NString( key + "versions" ) );
299                     result = false;
300                 }
301             }
302             else
303             {
304                 // snapshot metadata
305                 if ( !artifact.getBaseVersion().equals( metadata.getVersion() ) )
306                 {
307                     reporter.addFailure( artifact, getI18NString( key + "version" ) );
308                     result = false;
309                 }
310
311                 if ( artifact.isSnapshot() )
312                 {
313                     Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() );
314                     if ( matcher.matches() )
315                     {
316                         boolean correct = false;
317                         if ( metadata.getVersioning() != null && metadata.getVersioning().getSnapshot() != null )
318                         {
319                             Snapshot snapshot = metadata.getVersioning().getSnapshot();
320                             int build = Integer.valueOf( matcher.group( 3 ) ).intValue();
321                             String ts = matcher.group( 2 );
322                             if ( build == snapshot.getBuildNumber() && ts.equals( snapshot.getTimestamp() ) )
323                             {
324                                 correct = true;
325                             }
326                         }
327
328                         if ( !correct )
329                         {
330                             reporter.addFailure( artifact, getI18NString( key + "snapshot" ) );
331                             result = false;
332                         }
333                     }
334                 }
335             }
336         }
337         return result;
338     }
339
340     private boolean copyPom( Artifact artifact, ArtifactRepository targetRepository, ArtifactReporter reporter,
341                              FileTransaction transaction )
342         throws RepositoryConversionException
343     {
344         Artifact pom = artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
345                                                               artifact.getVersion() );
346         pom.setBaseVersion( artifact.getBaseVersion() );
347         ArtifactRepository repository = artifact.getRepository();
348         File file = new File( repository.getBasedir(), repository.pathOf( pom ) );
349
350         boolean result = true;
351         if ( file.exists() )
352         {
353             // TODO: utility methods in the model converter
354             File targetFile = new File( targetRepository.getBasedir(), targetRepository.pathOf( pom ) );
355
356             String contents = null;
357             boolean checksumsValid = false;
358             try
359             {
360                 if ( testChecksums( artifact, file, reporter ) )
361                 {
362                     checksumsValid = true;
363                     contents = FileUtils.fileRead( file );
364                 }
365             }
366             catch ( IOException e )
367             {
368                 throw new RepositoryConversionException( "Unable to read source POM: " + e.getMessage(), e );
369             }
370
371             if ( checksumsValid && contents.indexOf( "modelVersion" ) >= 0 )
372             {
373                 // v4 POM
374                 try
375                 {
376                     boolean matching = false;
377                     if ( !force && targetFile.exists() )
378                     {
379                         String targetContents = FileUtils.fileRead( targetFile );
380                         matching = targetContents.equals( contents );
381                     }
382                     if ( force || !matching )
383                     {
384                         transaction.createFile( contents, targetFile );
385                     }
386                 }
387                 catch ( IOException e )
388                 {
389                     throw new RepositoryConversionException( "Unable to write target POM: " + e.getMessage(), e );
390                 }
391             }
392             else
393             {
394                 // v3 POM
395                 StringReader stringReader = new StringReader( contents );
396                 StringWriter writer = null;
397                 try
398                 {
399                     writer = new StringWriter();
400
401                     // TODO: this api could be improved - is it worth having or go back to modelConverter?
402                     rewriter.rewrite( stringReader, writer, false, artifact.getGroupId(), artifact.getArtifactId(),
403                                       artifact.getVersion(), artifact.getType() );
404
405                     transaction.createFile( writer.toString(), targetFile );
406
407                     List warnings = rewriter.getWarnings();
408
409                     for ( Iterator i = warnings.iterator(); i.hasNext(); )
410                     {
411                         String message = (String) i.next();
412                         reporter.addWarning( artifact, message );
413                     }
414                 }
415                 catch ( XmlPullParserException e )
416                 {
417                     reporter.addFailure( artifact, getI18NString( "failure.invalid.source.pom", e.getMessage() ) );
418                     result = false;
419                 }
420                 catch ( Exception e )
421                 {
422                     throw new RepositoryConversionException( "Unable to write converted POM", e );
423                 }
424                 finally
425                 {
426                     IOUtil.close( writer );
427                 }
428             }
429         }
430         else
431         {
432             reporter.addWarning( artifact, getI18NString( "warning.missing.pom" ) );
433         }
434         return result;
435     }
436
437     private String getI18NString( String key, String arg0 )
438     {
439         return i18n.format( getClass().getName(), Locale.getDefault(), key, arg0 );
440     }
441
442     private String getI18NString( String key )
443     {
444         return i18n.getString( getClass().getName(), Locale.getDefault(), key );
445     }
446
447     private boolean testChecksums( Artifact artifact, File file, ArtifactReporter reporter )
448         throws IOException, RepositoryConversionException
449     {
450         boolean result = true;
451
452         try
453         {
454             File md5 = new File( file.getParentFile(), file.getName() + ".md5" );
455             if ( md5.exists() )
456             {
457                 String checksum = FileUtils.fileRead( md5 );
458                 if ( !digester.verifyChecksum( file, checksum, Digester.MD5 ) )
459                 {
460                     reporter.addFailure( artifact, getI18NString( "failure.incorrect.md5" ) );
461                     result = false;
462                 }
463             }
464
465             File sha1 = new File( file.getParentFile(), file.getName() + ".sha1" );
466             if ( sha1.exists() )
467             {
468                 String checksum = FileUtils.fileRead( sha1 );
469                 if ( !digester.verifyChecksum( file, checksum, Digester.SHA1 ) )
470                 {
471                     reporter.addFailure( artifact, getI18NString( "failure.incorrect.sha1" ) );
472                     result = false;
473                 }
474             }
475         }
476         catch ( NoSuchAlgorithmException e )
477         {
478             throw new RepositoryConversionException( "Error copying artifact: " + e.getMessage(), e );
479         }
480         return result;
481     }
482
483     private boolean copyArtifact( Artifact artifact, ArtifactRepository targetRepository, ArtifactReporter reporter,
484                                   FileTransaction transaction )
485         throws RepositoryConversionException
486     {
487         File sourceFile = artifact.getFile();
488
489         File targetFile = new File( targetRepository.getBasedir(), targetRepository.pathOf( artifact ) );
490
491         boolean result = true;
492         try
493         {
494             boolean matching = false;
495             if ( !force && targetFile.exists() )
496             {
497                 matching = FileUtils.contentEquals( sourceFile, targetFile );
498                 if ( !matching )
499                 {
500                     reporter.addFailure( artifact, getI18NString( "failure.target.already.exists" ) );
501                     result = false;
502                 }
503             }
504             if ( result )
505             {
506                 if ( force || !matching )
507                 {
508                     if ( testChecksums( artifact, sourceFile, reporter ) )
509                     {
510                         transaction.copyFile( sourceFile, targetFile );
511                     }
512                     else
513                     {
514                         result = false;
515                     }
516                 }
517             }
518         }
519         catch ( IOException e )
520         {
521             throw new RepositoryConversionException( "Error copying artifact", e );
522         }
523         return result;
524     }
525
526     public void convert( List artifacts, ArtifactRepository targetRepository, ArtifactReporter reporter )
527         throws RepositoryConversionException
528     {
529         for ( Iterator i = artifacts.iterator(); i.hasNext(); )
530         {
531             Artifact artifact = (Artifact) i.next();
532             convert( artifact, targetRepository, reporter );
533         }
534     }
535 }