]> source.dussan.org Git - archiva.git/blob
a37ced0f5ccbab098317ed9c4523669f94952685
[archiva.git] /
1 package org.apache.archiva.stagerepository.merge;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  *  http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied.  See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21
22 import org.apache.archiva.common.filelock.DefaultFileLockManager;
23 import org.apache.archiva.common.utils.VersionComparator;
24 import org.apache.archiva.common.utils.VersionUtil;
25 import org.apache.archiva.configuration.ArchivaConfiguration;
26 import org.apache.archiva.configuration.Configuration;
27 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
28 import org.apache.archiva.maven2.metadata.MavenMetadataReader;
29 import org.apache.archiva.metadata.model.ArtifactMetadata;
30 import org.apache.archiva.metadata.repository.MetadataRepository;
31 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
32 import org.apache.archiva.filter.Filter;
33 import org.apache.archiva.metadata.repository.RepositorySession;
34 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
35 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
36 import org.apache.archiva.model.ArchivaRepositoryMetadata;
37 import org.apache.archiva.repository.RepositoryException;
38 import org.apache.archiva.repository.RepositoryType;
39 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
40 import org.apache.archiva.repository.metadata.base.RepositoryMetadataWriter;
41 import org.apache.archiva.repository.storage.FilesystemAsset;
42 import org.apache.archiva.repository.storage.FilesystemStorage;
43 import org.apache.archiva.repository.storage.StorageAsset;
44 import org.apache.commons.io.FileUtils;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.springframework.stereotype.Service;
48
49 import javax.inject.Inject;
50 import javax.inject.Named;
51 import java.io.BufferedWriter;
52 import java.io.IOException;
53 import java.nio.file.Files;
54 import java.nio.file.Path;
55 import java.nio.file.Paths;
56 import java.text.DateFormat;
57 import java.text.SimpleDateFormat;
58 import java.util.*;
59
60 /**
61  *
62  */
63 @Service ("repositoryMerger#maven2")
64 public class Maven2RepositoryMerger
65     implements RepositoryMerger
66 {
67
68     @Inject
69     @Named("metadataReader#maven")
70     private MavenMetadataReader metadataReader;
71
72     private static final Logger log = LoggerFactory.getLogger( Maven2RepositoryMerger.class );
73
74     private static final Comparator<ArtifactMetadata> META_COMPARATOR = Comparator.comparing(ArtifactMetadata::getNamespace)
75             .thenComparing(ArtifactMetadata::getProject)
76             .thenComparing(ArtifactMetadata::getId)
77             .thenComparing(ArtifactMetadata::getVersion);
78
79     /**
80      *
81      */
82     private ArchivaConfiguration configuration;
83
84     /**
85      *
86      */
87     private RepositoryPathTranslator pathTranslator;
88
89     private static final String METADATA_FILENAME = "maven-metadata.xml";
90
91     @Inject
92     private RepositorySessionFactory repositorySessionFactory;
93
94     @Inject
95     public Maven2RepositoryMerger(
96         @Named (value = "archivaConfiguration#default") ArchivaConfiguration archivaConfiguration,
97         @Named (value = "repositoryPathTranslator#maven2") RepositoryPathTranslator repositoryPathTranslator )
98     {
99         this.configuration = archivaConfiguration;
100         this.pathTranslator = repositoryPathTranslator;
101     }
102
103     public void setConfiguration( ArchivaConfiguration configuration )
104     {
105         this.configuration = configuration;
106     }
107
108     @Override
109     public boolean supportsRepository( RepositoryType type )
110     {
111         return RepositoryType.MAVEN.equals( type );
112     }
113
114     @Override
115     public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId )
116         throws RepositoryMergerException
117     {
118
119         try(RepositorySession session = repositorySessionFactory.createSession())
120         {
121             List<ArtifactMetadata> artifactsInSourceRepo = metadataRepository.getArtifacts(session , sourceRepoId );
122             for ( ArtifactMetadata artifactMetadata : artifactsInSourceRepo )
123             {
124                 artifactMetadata.setRepositoryId( targetRepoId );
125                 createFolderStructure( sourceRepoId, targetRepoId, artifactMetadata );
126             }
127         }
128         catch ( MetadataRepositoryException e )
129         {
130             throw new RepositoryMergerException( e.getMessage(), e );
131         }
132         catch ( IOException e )
133         {
134             throw new RepositoryMergerException( e.getMessage(), e );
135         }
136         catch ( RepositoryException e )
137         {
138             throw new RepositoryMergerException( e.getMessage(), e );
139         }
140     }
141
142     // TODO when UI needs a subset to merge
143     @Override
144     public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId,
145                        Filter<ArtifactMetadata> filter )
146         throws RepositoryMergerException
147     {
148         try(RepositorySession session = repositorySessionFactory.createSession())
149         {
150             List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts(session , sourceRepoId );
151             for ( ArtifactMetadata metadata : sourceArtifacts )
152             {
153                 if ( filter.accept( metadata ) )
154                 {
155                     createFolderStructure( sourceRepoId, targetRepoId, metadata );
156                 }
157             }
158         }
159         catch ( MetadataRepositoryException e )
160         {
161             throw new RepositoryMergerException( e.getMessage(), e );
162         }
163         catch ( IOException e )
164         {
165             throw new RepositoryMergerException( e.getMessage(), e );
166         }
167         catch ( RepositoryException e )
168         {
169             throw new RepositoryMergerException( e.getMessage(), e );
170         }
171     }
172
173     private void createFolderStructure( String sourceRepoId, String targetRepoId, ArtifactMetadata artifactMetadata )
174         throws IOException, RepositoryException
175     {
176         Configuration config = configuration.getConfiguration();
177
178         ManagedRepositoryConfiguration targetRepoConfig = config.findManagedRepositoryById( targetRepoId );
179
180         ManagedRepositoryConfiguration sourceRepoConfig = config.findManagedRepositoryById( sourceRepoId );
181
182         Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
183
184         TimeZone timezone = TimeZone.getTimeZone( "UTC" );
185
186         DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
187
188         fmt.setTimeZone( timezone );
189
190         String timestamp = fmt.format( lastUpdatedTimestamp );
191
192         String targetRepoPath = targetRepoConfig.getLocation();
193
194         String sourceRepoPath = sourceRepoConfig.getLocation();
195
196         String artifactPath = pathTranslator.toPath( artifactMetadata.getNamespace(), artifactMetadata.getProject(),
197                                                      artifactMetadata.getProjectVersion(), artifactMetadata.getId() );
198
199         Path sourceArtifactFile = Paths.get( sourceRepoPath, artifactPath );
200
201         Path targetArtifactFile = Paths.get( targetRepoPath, artifactPath );
202
203         log.debug( "artifactPath {}", artifactPath );
204
205         int lastIndex = artifactPath.lastIndexOf( RepositoryPathTranslator.PATH_SEPARATOR );
206
207         Path targetFile = Paths.get( targetRepoPath, artifactPath.substring( 0, lastIndex ) );
208
209         if ( !Files.exists(targetFile) )
210         {
211             // create the folder structure when it does not exist
212             Files.createDirectories(targetFile);
213         }
214         // artifact copying
215         copyFile( sourceArtifactFile, targetArtifactFile );
216
217         // pom file copying
218         // TODO need to use path translator to get the pom file path
219 //        String fileName = artifactMetadata.getProject() + "-" + artifactMetadata.getVersion() + ".pom";
220 //
221 //        File sourcePomFile =
222 //            pathTranslator.toFile( new File( sourceRepoPath ), artifactMetadata.getId(), artifactMetadata.getProject(),
223 //                                   artifactMetadata.getVersion(), fileName );
224 //
225 //        String relativePathToPomFile = sourcePomFile.getAbsolutePath().split( sourceRepoPath )[1];
226 //        File targetPomFile = new File( targetRepoPath, relativePathToPomFile );
227
228         //pom file copying  (file path is taken with out using path translator)
229
230         String index = artifactPath.substring( lastIndex + 1 );
231         int last = index.lastIndexOf( '.' );
232         Path sourcePomFile = Paths.get( sourceRepoPath,
233                                        artifactPath.substring( 0, lastIndex ) + "/" + artifactPath.substring(
234                                            lastIndex + 1 ).substring( 0, last ) + ".pom" );
235         Path targetPomFile = Paths.get( targetRepoPath,
236                                        artifactPath.substring( 0, lastIndex ) + "/" + artifactPath.substring(
237                                            lastIndex + 1 ).substring( 0, last ) + ".pom" );
238
239         if ( !Files.exists(targetPomFile) && Files.exists(sourcePomFile) )
240         {
241             copyFile( sourcePomFile, targetPomFile );
242         }
243
244         // explicitly update only if metadata-updater consumer is not enabled!
245         if ( !config.getRepositoryScanning().getKnownContentConsumers().contains( "metadata-updater" ) )
246         {
247
248             // updating version metadata files
249             FilesystemStorage fsStorage = new FilesystemStorage(Paths.get(sourceRepoPath), new DefaultFileLockManager());
250
251             StorageAsset versionMetaDataFileInSourceRepo =
252                 pathTranslator.toFile( new FilesystemAsset(fsStorage, "", Paths.get(sourceRepoPath)), artifactMetadata.getNamespace(),
253                                        artifactMetadata.getProject(), artifactMetadata.getVersion(),
254                                        METADATA_FILENAME );
255
256             if ( versionMetaDataFileInSourceRepo.exists() )
257             {//Pattern quote for windows path
258                 String relativePathToVersionMetadataFile =
259                         getRelativeAssetPath(versionMetaDataFileInSourceRepo);
260                 Path versionMetaDataFileInTargetRepo = Paths.get( targetRepoPath, relativePathToVersionMetadataFile );
261
262                 if ( !Files.exists(versionMetaDataFileInTargetRepo) )
263                 {
264                     copyFile( versionMetaDataFileInSourceRepo.getFilePath(), versionMetaDataFileInTargetRepo );
265                 }
266                 else
267                 {
268                     updateVersionMetadata( versionMetaDataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp );
269
270                 }
271             }
272
273             // updating project meta data file
274             StorageAsset projectDirectoryInSourceRepo = versionMetaDataFileInSourceRepo.getParent().getParent();
275             StorageAsset projectMetadataFileInSourceRepo = projectDirectoryInSourceRepo.resolve(METADATA_FILENAME );
276
277             if ( projectMetadataFileInSourceRepo.exists() )
278             {
279                 String relativePathToProjectMetadataFile =
280                         getRelativeAssetPath(projectMetadataFileInSourceRepo);
281                 Path projectMetadataFileInTargetRepo = Paths.get( targetRepoPath, relativePathToProjectMetadataFile );
282
283                 if ( !Files.exists(projectMetadataFileInTargetRepo) )
284                 {
285
286                     copyFile( projectMetadataFileInSourceRepo.getFilePath(), projectMetadataFileInTargetRepo );
287                 }
288                 else
289                 {
290                     updateProjectMetadata( projectMetadataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp,
291                                            timestamp );
292                 }
293             }
294         }
295
296     }
297
298     private String getRelativeAssetPath(final StorageAsset asset) {
299         String relPath = asset.getPath();
300         while(relPath.startsWith("/")) {
301             relPath = relPath.substring(1);
302         }
303         return relPath;
304     }
305
306     private void copyFile( Path sourceFile, Path targetFile )
307         throws IOException
308     {
309
310         FileUtils.copyFile( sourceFile.toFile(), targetFile.toFile() );
311
312     }
313
314     private void updateProjectMetadata( Path projectMetaDataFileIntargetRepo, ArtifactMetadata artifactMetadata,
315                                         Date lastUpdatedTimestamp, String timestamp )
316         throws RepositoryMetadataException
317     {
318         ArrayList<String> availableVersions = new ArrayList<>();
319         String latestVersion = artifactMetadata.getProjectVersion();
320
321         ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetaDataFileIntargetRepo );
322
323         if ( Files.exists(projectMetaDataFileIntargetRepo) )
324         {
325             availableVersions = (ArrayList<String>) projectMetadata.getAvailableVersions();
326
327             Collections.sort( availableVersions, VersionComparator.getInstance() );
328
329             if ( !availableVersions.contains( artifactMetadata.getVersion() ) )
330             {
331                 availableVersions.add( artifactMetadata.getVersion() );
332             }
333
334             latestVersion = availableVersions.get( availableVersions.size() - 1 );
335         }
336         else
337         {
338             availableVersions.add( artifactMetadata.getProjectVersion() );
339             projectMetadata.setGroupId( artifactMetadata.getNamespace() );
340             projectMetadata.setArtifactId( artifactMetadata.getProject() );
341         }
342
343         if ( projectMetadata.getGroupId() == null )
344         {
345             projectMetadata.setGroupId( artifactMetadata.getNamespace() );
346         }
347
348         if ( projectMetadata.getArtifactId() == null )
349         {
350             projectMetadata.setArtifactId( artifactMetadata.getProject() );
351         }
352
353         projectMetadata.setLatestVersion( latestVersion );
354         projectMetadata.setAvailableVersions( availableVersions );
355         projectMetadata.setLastUpdated( timestamp );
356         projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
357
358         if ( !VersionUtil.isSnapshot( artifactMetadata.getVersion() ) )
359         {
360             projectMetadata.setReleasedVersion( latestVersion );
361         }
362
363         try(BufferedWriter writer = Files.newBufferedWriter(projectMetaDataFileIntargetRepo)) {
364             RepositoryMetadataWriter.write( projectMetadata, writer );
365         } catch (IOException e) {
366             throw new RepositoryMetadataException(e);
367         }
368
369     }
370
371     private void updateVersionMetadata( Path versionMetaDataFileInTargetRepo, ArtifactMetadata artifactMetadata,
372                                         Date lastUpdatedTimestamp )
373         throws RepositoryMetadataException
374     {
375         ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetaDataFileInTargetRepo );
376         if ( !Files.exists(versionMetaDataFileInTargetRepo) )
377         {
378             versionMetadata.setGroupId( artifactMetadata.getNamespace() );
379             versionMetadata.setArtifactId( artifactMetadata.getProject() );
380             versionMetadata.setVersion( artifactMetadata.getProjectVersion() );
381         }
382
383         versionMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
384         try(BufferedWriter writer = Files.newBufferedWriter(versionMetaDataFileInTargetRepo) ) {
385             RepositoryMetadataWriter.write( versionMetadata, writer);
386         } catch (IOException e) {
387             throw new RepositoryMetadataException(e);
388         }
389     }
390
391     private ArchivaRepositoryMetadata getMetadata( Path metadataFile )
392         throws RepositoryMetadataException
393     {
394         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
395         if ( Files.exists(metadataFile) )
396         {
397             metadata = metadataReader.read( metadataFile );
398         }
399         return metadata;
400     }
401
402     @Override
403     public List<ArtifactMetadata> getConflictingArtifacts( MetadataRepository metadataRepository, String sourceRepo,
404                                                            String targetRepo )
405         throws RepositoryMergerException
406     {
407         try(RepositorySession session = repositorySessionFactory.createSession())
408         {
409             TreeSet<ArtifactMetadata> targetArtifacts = new TreeSet<>(META_COMPARATOR);
410             targetArtifacts.addAll(metadataRepository.getArtifacts(session , targetRepo ));
411             TreeSet<ArtifactMetadata> sourceArtifacts = new TreeSet<>(META_COMPARATOR);
412             sourceArtifacts.addAll(metadataRepository.getArtifacts(session , sourceRepo ));
413             sourceArtifacts.retainAll(targetArtifacts);
414
415             return new ArrayList<>(sourceArtifacts);
416         }
417         catch ( MetadataRepositoryException e )
418         {
419             throw new RepositoryMergerException( e.getMessage(), e );
420         }
421     }
422
423     public RepositorySessionFactory getRepositorySessionFactory( )
424     {
425         return repositorySessionFactory;
426     }
427
428     public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
429     {
430         this.repositorySessionFactory = repositorySessionFactory;
431     }
432 }