]> source.dussan.org Git - archiva.git/blob
ee96ccd0068135e9fedfda6b9fc229b5a047a210
[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.DistributionManagement;
31 import org.apache.maven.model.Model;
32 import org.apache.maven.model.Relocation;
33 import org.apache.maven.model.converter.ArtifactPomRewriter;
34 import org.apache.maven.model.converter.ModelConverter;
35 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
36 import org.apache.maven.model.v3_0_0.io.xpp3.MavenXpp3Reader;
37 import org.apache.maven.repository.converter.transaction.FileTransaction;
38 import org.apache.maven.repository.digest.Digester;
39 import org.apache.maven.repository.reporting.ArtifactReporter;
40 import org.codehaus.plexus.i18n.I18N;
41 import org.codehaus.plexus.util.FileUtils;
42 import org.codehaus.plexus.util.IOUtil;
43 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
44
45 import java.io.File;
46 import java.io.FileReader;
47 import java.io.IOException;
48 import java.io.StringReader;
49 import java.io.StringWriter;
50 import java.security.NoSuchAlgorithmException;
51 import java.util.Iterator;
52 import java.util.List;
53 import java.util.Locale;
54 import java.util.Properties;
55 import java.util.regex.Matcher;
56
57 /**
58  * Implementation of repository conversion class.
59  *
60  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
61  * @plexus.component role="org.apache.maven.repository.converter.RepositoryConverter" role-hint="default"
62  */
63 public class DefaultRepositoryConverter
64     implements RepositoryConverter
65 {
66     /**
67      * @plexus.requirement
68      */
69     private Digester digester;
70
71     /**
72      * @plexus.requirement
73      */
74     private ArtifactFactory artifactFactory;
75
76     /**
77      * @plexus.requirement
78      */
79     private ArtifactPomRewriter rewriter;
80
81     /**
82      * @plexus.requirement
83      */
84     private ModelConverter translator;
85
86     /**
87      * @plexus.configuration default-value="false"
88      */
89     private boolean force;
90
91     /**
92      * @plexus.configuration default-value="false"
93      */
94     private boolean dryrun;
95
96     /**
97      * @plexus.requirement
98      */
99     private I18N i18n;
100
101     public void convert( Artifact artifact, ArtifactRepository targetRepository, ArtifactReporter reporter )
102         throws RepositoryConversionException
103     {
104         if ( artifact.getRepository().getUrl().equals( targetRepository.getUrl() ) )
105         {
106             throw new RepositoryConversionException( getI18NString( "exception.repositories.match" ) );
107         }
108
109         if ( validateMetadata( artifact, reporter ) )
110         {
111             FileTransaction transaction = new FileTransaction();
112
113             if ( copyPom( artifact, targetRepository, reporter, transaction ) )
114             {
115                 if ( copyArtifact( artifact, targetRepository, reporter, transaction ) )
116                 {
117                     Metadata metadata = createBaseMetadata( artifact );
118                     Versioning versioning = new Versioning();
119                     versioning.addVersion( artifact.getBaseVersion() );
120                     metadata.setVersioning( versioning );
121                     updateMetadata( new ArtifactRepositoryMetadata( artifact ), targetRepository, metadata,
122                                     transaction );
123
124                     metadata = createBaseMetadata( artifact );
125                     metadata.setVersion( artifact.getBaseVersion() );
126                     versioning = new Versioning();
127
128                     Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() );
129                     if ( matcher.matches() )
130                     {
131                         Snapshot snapshot = new Snapshot();
132                         snapshot.setBuildNumber( Integer.valueOf( matcher.group( 3 ) ).intValue() );
133                         snapshot.setTimestamp( matcher.group( 2 ) );
134                         versioning.setSnapshot( snapshot );
135                     }
136
137                     // TODO: merge latest/release/snapshot from source instead
138                     metadata.setVersioning( versioning );
139                     updateMetadata( new SnapshotArtifactRepositoryMetadata( artifact ), targetRepository, metadata,
140                                     transaction );
141
142                     if ( !dryrun )
143                     {
144                         transaction.commit();
145                     }
146                     reporter.addSuccess( artifact );
147                 }
148             }
149         }
150     }
151
152     private static Metadata createBaseMetadata( Artifact artifact )
153     {
154         Metadata metadata = new Metadata();
155         metadata.setArtifactId( artifact.getArtifactId() );
156         metadata.setGroupId( artifact.getGroupId() );
157         return metadata;
158     }
159
160     private void updateMetadata( RepositoryMetadata artifactMetadata, ArtifactRepository targetRepository,
161                                  Metadata newMetadata, FileTransaction transaction )
162         throws RepositoryConversionException
163     {
164         File file = new File( targetRepository.getBasedir(),
165                               targetRepository.pathOfRemoteRepositoryMetadata( artifactMetadata ) );
166
167         Metadata metadata;
168         boolean changed;
169
170         if ( file.exists() )
171         {
172             metadata = readMetadata( file );
173             changed = metadata.merge( newMetadata );
174         }
175         else
176         {
177             changed = true;
178             metadata = newMetadata;
179         }
180
181         if ( changed )
182         {
183             StringWriter writer = null;
184             try
185             {
186                 writer = new StringWriter();
187
188                 MetadataXpp3Writer mappingWriter = new MetadataXpp3Writer();
189
190                 mappingWriter.write( writer, metadata );
191
192                 transaction.createFile( writer.toString(), file );
193             }
194             catch ( IOException e )
195             {
196                 throw new RepositoryConversionException( "Error writing target metadata", e );
197             }
198             finally
199             {
200                 IOUtil.close( writer );
201             }
202         }
203     }
204
205     private Metadata readMetadata( File file )
206         throws RepositoryConversionException
207     {
208         Metadata metadata;
209         MetadataXpp3Reader reader = new MetadataXpp3Reader();
210         FileReader fileReader = null;
211         try
212         {
213             fileReader = new FileReader( file );
214             metadata = reader.read( fileReader );
215         }
216         catch ( IOException e )
217         {
218             throw new RepositoryConversionException( "Error reading target metadata", e );
219         }
220         catch ( XmlPullParserException e )
221         {
222             throw new RepositoryConversionException( "Error reading target metadata", e );
223         }
224         finally
225         {
226             IOUtil.close( fileReader );
227         }
228         return metadata;
229     }
230
231     private boolean validateMetadata( Artifact artifact, ArtifactReporter reporter )
232         throws RepositoryConversionException
233     {
234         ArtifactRepository repository = artifact.getRepository();
235
236         boolean result = true;
237
238         RepositoryMetadata repositoryMetadata = new ArtifactRepositoryMetadata( artifact );
239         File file =
240             new File( repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata( repositoryMetadata ) );
241         if ( file.exists() )
242         {
243             Metadata metadata = readMetadata( file );
244             result = validateMetadata( metadata, repositoryMetadata, artifact, reporter );
245         }
246
247         repositoryMetadata = new SnapshotArtifactRepositoryMetadata( artifact );
248         file = new File( repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata( repositoryMetadata ) );
249         if ( file.exists() )
250         {
251             Metadata metadata = readMetadata( file );
252             result = result && validateMetadata( metadata, repositoryMetadata, artifact, reporter );
253         }
254
255         return result;
256     }
257
258     private boolean validateMetadata( Metadata metadata, RepositoryMetadata repositoryMetadata, Artifact artifact,
259                                       ArtifactReporter reporter )
260     {
261         String key = "failure.incorrect.";
262
263         if ( repositoryMetadata.storedInGroupDirectory() )
264         {
265             key += "groupMetadata.";
266         }
267         else if ( repositoryMetadata.storedInArtifactVersionDirectory() )
268         {
269             key += "snapshotMetadata.";
270         }
271         else
272         {
273             key += "artifactMetadata.";
274         }
275
276         boolean result = true;
277
278         if ( !metadata.getGroupId().equals( artifact.getGroupId() ) )
279         {
280             reporter.addFailure( artifact, getI18NString( key + "groupId" ) );
281             result = false;
282         }
283         if ( !repositoryMetadata.storedInGroupDirectory() )
284         {
285             if ( !metadata.getArtifactId().equals( artifact.getArtifactId() ) )
286             {
287                 reporter.addFailure( artifact, getI18NString( key + "artifactId" ) );
288                 result = false;
289             }
290             if ( !repositoryMetadata.storedInArtifactVersionDirectory() )
291             {
292                 // artifact metadata
293
294                 boolean foundVersion = false;
295                 if ( metadata.getVersioning() != null )
296                 {
297                     for ( Iterator i = metadata.getVersioning().getVersions().iterator();
298                           i.hasNext() && !foundVersion; )
299                     {
300                         String version = (String) i.next();
301                         if ( version.equals( artifact.getBaseVersion() ) )
302                         {
303                             foundVersion = true;
304                         }
305                     }
306                 }
307
308                 if ( !foundVersion )
309                 {
310                     reporter.addFailure( artifact, getI18NString( key + "versions" ) );
311                     result = false;
312                 }
313             }
314             else
315             {
316                 // snapshot metadata
317                 if ( !artifact.getBaseVersion().equals( metadata.getVersion() ) )
318                 {
319                     reporter.addFailure( artifact, getI18NString( key + "version" ) );
320                     result = false;
321                 }
322
323                 if ( artifact.isSnapshot() )
324                 {
325                     Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() );
326                     if ( matcher.matches() )
327                     {
328                         boolean correct = false;
329                         if ( metadata.getVersioning() != null && metadata.getVersioning().getSnapshot() != null )
330                         {
331                             Snapshot snapshot = metadata.getVersioning().getSnapshot();
332                             int build = Integer.valueOf( matcher.group( 3 ) ).intValue();
333                             String ts = matcher.group( 2 );
334                             if ( build == snapshot.getBuildNumber() && ts.equals( snapshot.getTimestamp() ) )
335                             {
336                                 correct = true;
337                             }
338                         }
339
340                         if ( !correct )
341                         {
342                             reporter.addFailure( artifact, getI18NString( key + "snapshot" ) );
343                             result = false;
344                         }
345                     }
346                 }
347             }
348         }
349         return result;
350     }
351
352     private boolean copyPom( Artifact artifact, ArtifactRepository targetRepository, ArtifactReporter reporter,
353                              FileTransaction transaction )
354         throws RepositoryConversionException
355     {
356         Artifact pom = artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
357                                                               artifact.getVersion() );
358         pom.setBaseVersion( artifact.getBaseVersion() );
359         ArtifactRepository repository = artifact.getRepository();
360         File file = new File( repository.getBasedir(), repository.pathOf( pom ) );
361
362         boolean result = true;
363         if ( file.exists() )
364         {
365             // TODO: utility methods in the model converter
366             File targetFile = new File( targetRepository.getBasedir(), targetRepository.pathOf( pom ) );
367
368             String contents = null;
369             boolean checksumsValid = false;
370             try
371             {
372                 if ( testChecksums( artifact, file, reporter ) )
373                 {
374                     checksumsValid = true;
375                     contents = FileUtils.fileRead( file );
376                 }
377             }
378             catch ( IOException e )
379             {
380                 throw new RepositoryConversionException( "Unable to read source POM: " + e.getMessage(), e );
381             }
382
383             if ( checksumsValid && contents.indexOf( "modelVersion" ) >= 0 )
384             {
385                 // v4 POM
386                 try
387                 {
388                     boolean matching = false;
389                     if ( !force && targetFile.exists() )
390                     {
391                         String targetContents = FileUtils.fileRead( targetFile );
392                         matching = targetContents.equals( contents );
393                     }
394                     if ( force || !matching )
395                     {
396                         transaction.createFile( contents, targetFile );
397                     }
398                 }
399                 catch ( IOException e )
400                 {
401                     throw new RepositoryConversionException( "Unable to write target POM: " + e.getMessage(), e );
402                 }
403             }
404             else
405             {
406                 // v3 POM
407                 StringReader stringReader = new StringReader( contents );
408                 StringWriter writer = null;
409                 try
410                 {
411                     MavenXpp3Reader v3Reader = new MavenXpp3Reader();
412                     org.apache.maven.model.v3_0_0.Model v3Model = v3Reader.read( stringReader );
413
414                     if ( doRelocation( artifact, v3Model, targetRepository, transaction ) )
415                     {
416                         Artifact relocatedPom = artifactFactory.createProjectArtifact( artifact.getGroupId(),
417                                                                                        artifact.getArtifactId(),
418                                                                                        artifact.getVersion() );
419                         targetFile = new File( targetRepository.getBasedir(), targetRepository.pathOf( relocatedPom ) );
420                     }
421
422                     Model v4Model = translator.translate( v3Model );
423
424                     translator.validateV4Basics( v4Model, v3Model.getGroupId(), v3Model.getArtifactId(),
425                                                  v3Model.getVersion(), v3Model.getPackage() );
426
427                     writer = new StringWriter();
428                     MavenXpp3Writer Xpp3Writer = new MavenXpp3Writer();
429                     Xpp3Writer.write( writer, v4Model );
430
431                     transaction.createFile( writer.toString(), targetFile );
432
433                     List warnings = translator.getWarnings();
434
435                     for ( Iterator i = warnings.iterator(); i.hasNext(); )
436                     {
437                         String message = (String) i.next();
438                         reporter.addWarning( artifact, message );
439                     }
440                 }
441                 catch ( XmlPullParserException e )
442                 {
443                     reporter.addFailure( artifact, getI18NString( "failure.invalid.source.pom", e.getMessage() ) );
444                     result = false;
445                 }
446                 catch ( Exception e )
447                 {
448                     throw new RepositoryConversionException( "Unable to write converted POM", e );
449                 }
450                 finally
451                 {
452                     IOUtil.close( writer );
453                 }
454             }
455         }
456         else
457         {
458             reporter.addWarning( artifact, getI18NString( "warning.missing.pom" ) );
459         }
460         return result;
461     }
462
463     private boolean doRelocation( Artifact artifact, org.apache.maven.model.v3_0_0.Model v3Model,
464                                   ArtifactRepository repository, FileTransaction transaction )
465         throws IOException
466     {
467         Properties properties = v3Model.getProperties();
468         if ( properties.containsKey( "relocated.groupId" ) || properties.containsKey( "relocated.artifactId" ) ||
469             properties.containsKey( "relocated.version" ) )
470         {
471             String newGroupId = v3Model.getGroupId();
472             if ( properties.containsKey( "relocated.groupId" ) )
473             {
474                 newGroupId = properties.getProperty( "relocated.groupId" );
475                 properties.remove( "relocated.groupId" );
476             }
477
478             String newArtifactId = v3Model.getArtifactId();
479             if ( properties.containsKey( "relocated.artifactId" ) )
480             {
481                 newArtifactId = properties.getProperty( "relocated.artifactId" );
482                 properties.remove( "relocated.artifactId" );
483             }
484
485             String newVersion = v3Model.getVersion();
486             if ( properties.containsKey( "relocated.version" ) )
487             {
488                 newVersion = properties.getProperty( "relocated.version" );
489                 properties.remove( "relocated.version" );
490             }
491
492             String message = "";
493             if ( properties.containsKey( "relocated.message" ) )
494             {
495                 message = properties.getProperty( "relocated.message" );
496                 properties.remove( "relocated.message" );
497             }
498
499             if ( properties.isEmpty() )
500             {
501                 v3Model.setProperties( null );
502             }
503
504             writeRelocationPom( v3Model.getGroupId(), v3Model.getArtifactId(), v3Model.getVersion(), newGroupId,
505                                 newArtifactId, newVersion, message, repository, transaction );
506
507             v3Model.setGroupId( newGroupId );
508             v3Model.setArtifactId( newArtifactId );
509             v3Model.setVersion( newVersion );
510
511             artifact.setGroupId( newGroupId );
512             artifact.setArtifactId( newArtifactId );
513             artifact.setVersion( newVersion );
514
515             return true;
516         }
517         else
518         {
519             return false;
520         }
521     }
522
523     private void writeRelocationPom( String groupId, String artifactId, String version, String newGroupId,
524                                      String newArtifactId, String newVersion, String message,
525                                      ArtifactRepository repository, FileTransaction transaction )
526         throws IOException
527     {
528         Model pom = new Model();
529         pom.setGroupId( groupId );
530         pom.setArtifactId( artifactId );
531         pom.setVersion( version );
532
533         DistributionManagement dMngt = new DistributionManagement();
534
535         Relocation relocation = new Relocation();
536         relocation.setGroupId( newGroupId );
537         relocation.setArtifactId( newArtifactId );
538         relocation.setVersion( newVersion );
539         if ( message != null && message.length() > 0 )
540         {
541             relocation.setMessage( message );
542         }
543
544         dMngt.setRelocation( relocation );
545
546         pom.setDistributionManagement( dMngt );
547
548         Artifact artifact = artifactFactory.createBuildArtifact( groupId, artifactId, version, "pom" );
549         File pomFile = new File( repository.getBasedir(), repository.pathOf( artifact ) );
550
551         StringWriter strWriter = new StringWriter();
552         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
553         pomWriter.write( strWriter, pom );
554
555         transaction.createFile( strWriter.toString(), pomFile );
556     }
557
558     private String getI18NString( String key, String arg0 )
559     {
560         return i18n.format( getClass().getName(), Locale.getDefault(), key, arg0 );
561     }
562
563     private String getI18NString( String key )
564     {
565         return i18n.getString( getClass().getName(), Locale.getDefault(), key );
566     }
567
568     private boolean testChecksums( Artifact artifact, File file, ArtifactReporter reporter )
569         throws IOException, RepositoryConversionException
570     {
571         boolean result = true;
572
573         try
574         {
575             File md5 = new File( file.getParentFile(), file.getName() + ".md5" );
576             if ( md5.exists() )
577             {
578                 String checksum = FileUtils.fileRead( md5 );
579                 if ( !digester.verifyChecksum( file, checksum, Digester.MD5 ) )
580                 {
581                     reporter.addFailure( artifact, getI18NString( "failure.incorrect.md5" ) );
582                     result = false;
583                 }
584             }
585
586             File sha1 = new File( file.getParentFile(), file.getName() + ".sha1" );
587             if ( sha1.exists() )
588             {
589                 String checksum = FileUtils.fileRead( sha1 );
590                 if ( !digester.verifyChecksum( file, checksum, Digester.SHA1 ) )
591                 {
592                     reporter.addFailure( artifact, getI18NString( "failure.incorrect.sha1" ) );
593                     result = false;
594                 }
595             }
596         }
597         catch ( NoSuchAlgorithmException e )
598         {
599             throw new RepositoryConversionException( "Error copying artifact: " + e.getMessage(), e );
600         }
601         return result;
602     }
603
604     private boolean copyArtifact( Artifact artifact, ArtifactRepository targetRepository, ArtifactReporter reporter,
605                                   FileTransaction transaction )
606         throws RepositoryConversionException
607     {
608         File sourceFile = artifact.getFile();
609
610         File targetFile = new File( targetRepository.getBasedir(), targetRepository.pathOf( artifact ) );
611
612         boolean result = true;
613         try
614         {
615             boolean matching = false;
616             if ( !force && targetFile.exists() )
617             {
618                 matching = FileUtils.contentEquals( sourceFile, targetFile );
619                 if ( !matching )
620                 {
621                     reporter.addFailure( artifact, getI18NString( "failure.target.already.exists" ) );
622                     result = false;
623                 }
624             }
625             if ( result )
626             {
627                 if ( force || !matching )
628                 {
629                     if ( testChecksums( artifact, sourceFile, reporter ) )
630                     {
631                         transaction.copyFile( sourceFile, targetFile );
632                     }
633                     else
634                     {
635                         result = false;
636                     }
637                 }
638             }
639         }
640         catch ( IOException e )
641         {
642             throw new RepositoryConversionException( "Error copying artifact", e );
643         }
644         return result;
645     }
646
647     public void convert( List artifacts, ArtifactRepository targetRepository, ArtifactReporter reporter )
648         throws RepositoryConversionException
649     {
650         for ( Iterator i = artifacts.iterator(); i.hasNext(); )
651         {
652             Artifact artifact = (Artifact) i.next();
653             convert( artifact, targetRepository, reporter );
654         }
655     }
656 }