1 package org.apache.archiva.stagerepository.merge;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
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;
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;
63 @Service ("repositoryMerger#maven2")
64 public class Maven2RepositoryMerger
65 implements RepositoryMerger
69 @Named("metadataReader#maven")
70 private MavenMetadataReader metadataReader;
72 private static final Logger log = LoggerFactory.getLogger( Maven2RepositoryMerger.class );
74 private static final Comparator<ArtifactMetadata> META_COMPARATOR = Comparator.comparing(ArtifactMetadata::getNamespace)
75 .thenComparing(ArtifactMetadata::getProject)
76 .thenComparing(ArtifactMetadata::getId)
77 .thenComparing(ArtifactMetadata::getVersion);
82 private ArchivaConfiguration configuration;
87 private RepositoryPathTranslator pathTranslator;
89 private static final String METADATA_FILENAME = "maven-metadata.xml";
92 private RepositorySessionFactory repositorySessionFactory;
95 public Maven2RepositoryMerger(
96 @Named (value = "archivaConfiguration#default") ArchivaConfiguration archivaConfiguration,
97 @Named (value = "repositoryPathTranslator#maven2") RepositoryPathTranslator repositoryPathTranslator )
99 this.configuration = archivaConfiguration;
100 this.pathTranslator = repositoryPathTranslator;
103 public void setConfiguration( ArchivaConfiguration configuration )
105 this.configuration = configuration;
109 public boolean supportsRepository( RepositoryType type )
111 return RepositoryType.MAVEN.equals( type );
115 public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId )
116 throws RepositoryMergerException
119 try(RepositorySession session = repositorySessionFactory.createSession())
121 List<ArtifactMetadata> artifactsInSourceRepo = metadataRepository.getArtifacts(session , sourceRepoId );
122 for ( ArtifactMetadata artifactMetadata : artifactsInSourceRepo )
124 artifactMetadata.setRepositoryId( targetRepoId );
125 createFolderStructure( sourceRepoId, targetRepoId, artifactMetadata );
128 catch ( MetadataRepositoryException e )
130 throw new RepositoryMergerException( e.getMessage(), e );
132 catch ( IOException e )
134 throw new RepositoryMergerException( e.getMessage(), e );
136 catch ( RepositoryException e )
138 throw new RepositoryMergerException( e.getMessage(), e );
142 // TODO when UI needs a subset to merge
144 public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId,
145 Filter<ArtifactMetadata> filter )
146 throws RepositoryMergerException
148 try(RepositorySession session = repositorySessionFactory.createSession())
150 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts(session , sourceRepoId );
151 for ( ArtifactMetadata metadata : sourceArtifacts )
153 if ( filter.accept( metadata ) )
155 createFolderStructure( sourceRepoId, targetRepoId, metadata );
159 catch ( MetadataRepositoryException e )
161 throw new RepositoryMergerException( e.getMessage(), e );
163 catch ( IOException e )
165 throw new RepositoryMergerException( e.getMessage(), e );
167 catch ( RepositoryException e )
169 throw new RepositoryMergerException( e.getMessage(), e );
173 private void createFolderStructure( String sourceRepoId, String targetRepoId, ArtifactMetadata artifactMetadata )
174 throws IOException, RepositoryException
176 Configuration config = configuration.getConfiguration();
178 ManagedRepositoryConfiguration targetRepoConfig = config.findManagedRepositoryById( targetRepoId );
180 ManagedRepositoryConfiguration sourceRepoConfig = config.findManagedRepositoryById( sourceRepoId );
182 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
184 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
186 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
188 fmt.setTimeZone( timezone );
190 String timestamp = fmt.format( lastUpdatedTimestamp );
192 String targetRepoPath = targetRepoConfig.getLocation();
194 String sourceRepoPath = sourceRepoConfig.getLocation();
196 String artifactPath = pathTranslator.toPath( artifactMetadata.getNamespace(), artifactMetadata.getProject(),
197 artifactMetadata.getProjectVersion(), artifactMetadata.getId() );
199 Path sourceArtifactFile = Paths.get( sourceRepoPath, artifactPath );
201 Path targetArtifactFile = Paths.get( targetRepoPath, artifactPath );
203 log.debug( "artifactPath {}", artifactPath );
205 int lastIndex = artifactPath.lastIndexOf( RepositoryPathTranslator.PATH_SEPARATOR );
207 Path targetFile = Paths.get( targetRepoPath, artifactPath.substring( 0, lastIndex ) );
209 if ( !Files.exists(targetFile) )
211 // create the folder structure when it does not exist
212 Files.createDirectories(targetFile);
215 copyFile( sourceArtifactFile, targetArtifactFile );
218 // TODO need to use path translator to get the pom file path
219 // String fileName = artifactMetadata.getProject() + "-" + artifactMetadata.getVersion() + ".pom";
221 // File sourcePomFile =
222 // pathTranslator.toFile( new File( sourceRepoPath ), artifactMetadata.getId(), artifactMetadata.getProject(),
223 // artifactMetadata.getVersion(), fileName );
225 // String relativePathToPomFile = sourcePomFile.getAbsolutePath().split( sourceRepoPath )[1];
226 // File targetPomFile = new File( targetRepoPath, relativePathToPomFile );
228 //pom file copying (file path is taken with out using path translator)
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" );
239 if ( !Files.exists(targetPomFile) && Files.exists(sourcePomFile) )
241 copyFile( sourcePomFile, targetPomFile );
244 // explicitly update only if metadata-updater consumer is not enabled!
245 if ( !config.getRepositoryScanning().getKnownContentConsumers().contains( "metadata-updater" ) )
248 // updating version metadata files
249 FilesystemStorage fsStorage = new FilesystemStorage(Paths.get(sourceRepoPath), new DefaultFileLockManager());
251 StorageAsset versionMetaDataFileInSourceRepo =
252 pathTranslator.toFile( new FilesystemAsset(fsStorage, "", Paths.get(sourceRepoPath)), artifactMetadata.getNamespace(),
253 artifactMetadata.getProject(), artifactMetadata.getVersion(),
256 if ( versionMetaDataFileInSourceRepo.exists() )
257 {//Pattern quote for windows path
258 String relativePathToVersionMetadataFile =
259 getRelativeAssetPath(versionMetaDataFileInSourceRepo);
260 Path versionMetaDataFileInTargetRepo = Paths.get( targetRepoPath, relativePathToVersionMetadataFile );
262 if ( !Files.exists(versionMetaDataFileInTargetRepo) )
264 copyFile( versionMetaDataFileInSourceRepo.getFilePath(), versionMetaDataFileInTargetRepo );
268 updateVersionMetadata( versionMetaDataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp );
273 // updating project meta data file
274 StorageAsset projectDirectoryInSourceRepo = versionMetaDataFileInSourceRepo.getParent().getParent();
275 StorageAsset projectMetadataFileInSourceRepo = projectDirectoryInSourceRepo.resolve(METADATA_FILENAME );
277 if ( projectMetadataFileInSourceRepo.exists() )
279 String relativePathToProjectMetadataFile =
280 getRelativeAssetPath(projectMetadataFileInSourceRepo);
281 Path projectMetadataFileInTargetRepo = Paths.get( targetRepoPath, relativePathToProjectMetadataFile );
283 if ( !Files.exists(projectMetadataFileInTargetRepo) )
286 copyFile( projectMetadataFileInSourceRepo.getFilePath(), projectMetadataFileInTargetRepo );
290 updateProjectMetadata( projectMetadataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp,
298 private String getRelativeAssetPath(final StorageAsset asset) {
299 String relPath = asset.getPath();
300 while(relPath.startsWith("/")) {
301 relPath = relPath.substring(1);
306 private void copyFile( Path sourceFile, Path targetFile )
310 FileUtils.copyFile( sourceFile.toFile(), targetFile.toFile() );
314 private void updateProjectMetadata( Path projectMetaDataFileIntargetRepo, ArtifactMetadata artifactMetadata,
315 Date lastUpdatedTimestamp, String timestamp )
316 throws RepositoryMetadataException
318 ArrayList<String> availableVersions = new ArrayList<>();
319 String latestVersion = artifactMetadata.getProjectVersion();
321 ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetaDataFileIntargetRepo );
323 if ( Files.exists(projectMetaDataFileIntargetRepo) )
325 availableVersions = (ArrayList<String>) projectMetadata.getAvailableVersions();
327 Collections.sort( availableVersions, VersionComparator.getInstance() );
329 if ( !availableVersions.contains( artifactMetadata.getVersion() ) )
331 availableVersions.add( artifactMetadata.getVersion() );
334 latestVersion = availableVersions.get( availableVersions.size() - 1 );
338 availableVersions.add( artifactMetadata.getProjectVersion() );
339 projectMetadata.setGroupId( artifactMetadata.getNamespace() );
340 projectMetadata.setArtifactId( artifactMetadata.getProject() );
343 if ( projectMetadata.getGroupId() == null )
345 projectMetadata.setGroupId( artifactMetadata.getNamespace() );
348 if ( projectMetadata.getArtifactId() == null )
350 projectMetadata.setArtifactId( artifactMetadata.getProject() );
353 projectMetadata.setLatestVersion( latestVersion );
354 projectMetadata.setAvailableVersions( availableVersions );
355 projectMetadata.setLastUpdated( timestamp );
356 projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
358 if ( !VersionUtil.isSnapshot( artifactMetadata.getVersion() ) )
360 projectMetadata.setReleasedVersion( latestVersion );
363 try(BufferedWriter writer = Files.newBufferedWriter(projectMetaDataFileIntargetRepo)) {
364 RepositoryMetadataWriter.write( projectMetadata, writer );
365 } catch (IOException e) {
366 throw new RepositoryMetadataException(e);
371 private void updateVersionMetadata( Path versionMetaDataFileInTargetRepo, ArtifactMetadata artifactMetadata,
372 Date lastUpdatedTimestamp )
373 throws RepositoryMetadataException
375 ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetaDataFileInTargetRepo );
376 if ( !Files.exists(versionMetaDataFileInTargetRepo) )
378 versionMetadata.setGroupId( artifactMetadata.getNamespace() );
379 versionMetadata.setArtifactId( artifactMetadata.getProject() );
380 versionMetadata.setVersion( artifactMetadata.getProjectVersion() );
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);
391 private ArchivaRepositoryMetadata getMetadata( Path metadataFile )
392 throws RepositoryMetadataException
394 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
395 if ( Files.exists(metadataFile) )
397 metadata = metadataReader.read( metadataFile );
403 public List<ArtifactMetadata> getConflictingArtifacts( MetadataRepository metadataRepository, String sourceRepo,
405 throws RepositoryMergerException
407 try(RepositorySession session = repositorySessionFactory.createSession())
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);
415 return new ArrayList<>(sourceArtifacts);
417 catch ( MetadataRepositoryException e )
419 throw new RepositoryMergerException( e.getMessage(), e );
423 public RepositorySessionFactory getRepositorySessionFactory( )
425 return repositorySessionFactory;
428 public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
430 this.repositorySessionFactory = repositorySessionFactory;