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.utils.VersionComparator;
23 import org.apache.archiva.common.utils.VersionUtil;
24 import org.apache.archiva.configuration.ArchivaConfiguration;
25 import org.apache.archiva.configuration.Configuration;
26 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
27 import org.apache.archiva.maven2.metadata.MavenMetadataReader;
28 import org.apache.archiva.metadata.model.ArtifactMetadata;
29 import org.apache.archiva.metadata.repository.MetadataRepository;
30 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
31 import org.apache.archiva.metadata.repository.filter.Filter;
32 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
33 import org.apache.archiva.model.ArchivaRepositoryMetadata;
34 import org.apache.archiva.repository.RepositoryException;
35 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
36 import org.apache.archiva.repository.metadata.RepositoryMetadataWriter;
37 import org.apache.archiva.xml.XMLException;
38 import org.apache.commons.io.FileUtils;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.springframework.stereotype.Service;
43 import javax.inject.Inject;
44 import javax.inject.Named;
46 import java.io.IOException;
47 import java.text.DateFormat;
48 import java.text.SimpleDateFormat;
49 import java.util.ArrayList;
50 import java.util.Calendar;
51 import java.util.Collections;
52 import java.util.Date;
53 import java.util.List;
54 import java.util.TimeZone;
55 import java.util.regex.Pattern;
60 @Service ("repositoryMerger#maven2")
61 public class Maven2RepositoryMerger
62 implements RepositoryMerger
65 private Logger log = LoggerFactory.getLogger( getClass() );
70 private ArchivaConfiguration configuration;
75 private RepositoryPathTranslator pathTranslator;
77 private static final String METADATA_FILENAME = "maven-metadata.xml";
80 public Maven2RepositoryMerger(
81 @Named (value = "archivaConfiguration#default") ArchivaConfiguration archivaConfiguration,
82 @Named (value = "repositoryPathTranslator#maven2") RepositoryPathTranslator repositoryPathTranslator )
84 this.configuration = archivaConfiguration;
85 this.pathTranslator = repositoryPathTranslator;
88 public void setConfiguration( ArchivaConfiguration configuration )
90 this.configuration = configuration;
94 public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId )
95 throws RepositoryMergerException
100 List<ArtifactMetadata> artifactsInSourceRepo = metadataRepository.getArtifacts( sourceRepoId );
101 for ( ArtifactMetadata artifactMetadata : artifactsInSourceRepo )
103 artifactMetadata.setRepositoryId( targetRepoId );
104 createFolderStructure( sourceRepoId, targetRepoId, artifactMetadata );
107 catch ( MetadataRepositoryException e )
109 throw new RepositoryMergerException( e.getMessage(), e );
111 catch ( IOException e )
113 throw new RepositoryMergerException( e.getMessage(), e );
115 catch ( RepositoryException e )
117 throw new RepositoryMergerException( e.getMessage(), e );
121 // TODO when UI needs a subset to merge
123 public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId,
124 Filter<ArtifactMetadata> filter )
125 throws RepositoryMergerException
129 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( sourceRepoId );
130 for ( ArtifactMetadata metadata : sourceArtifacts )
132 if ( filter.accept( metadata ) )
134 createFolderStructure( sourceRepoId, targetRepoId, metadata );
138 catch ( MetadataRepositoryException e )
140 throw new RepositoryMergerException( e.getMessage(), e );
142 catch ( IOException e )
144 throw new RepositoryMergerException( e.getMessage(), e );
146 catch ( RepositoryException e )
148 throw new RepositoryMergerException( e.getMessage(), e );
152 private void createFolderStructure( String sourceRepoId, String targetRepoId, ArtifactMetadata artifactMetadata )
153 throws IOException, RepositoryException
155 Configuration config = configuration.getConfiguration();
157 ManagedRepositoryConfiguration targetRepoConfig = config.findManagedRepositoryById( targetRepoId );
159 ManagedRepositoryConfiguration sourceRepoConfig = config.findManagedRepositoryById( sourceRepoId );
161 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
163 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
165 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
167 fmt.setTimeZone( timezone );
169 String timestamp = fmt.format( lastUpdatedTimestamp );
171 String targetRepoPath = targetRepoConfig.getLocation();
173 String sourceRepoPath = sourceRepoConfig.getLocation();
175 String artifactPath = pathTranslator.toPath( artifactMetadata.getNamespace(), artifactMetadata.getProject(),
176 artifactMetadata.getProjectVersion(), artifactMetadata.getId() );
178 File sourceArtifactFile = new File( sourceRepoPath, artifactPath );
180 File targetArtifactFile = new File( targetRepoPath, artifactPath );
182 log.debug( "artifactPath {}", artifactPath );
184 int lastIndex = artifactPath.lastIndexOf( RepositoryPathTranslator.PATH_SEPARATOR );
186 File targetFile = new File( targetRepoPath, artifactPath.substring( 0, lastIndex ) );
188 if ( !targetFile.exists() )
190 // create the folder structure when it does not exist
194 copyFile( sourceArtifactFile, targetArtifactFile );
197 // TODO need to use path translator to get the pom file path
198 // String fileName = artifactMetadata.getProject() + "-" + artifactMetadata.getVersion() + ".pom";
200 // File sourcePomFile =
201 // pathTranslator.toFile( new File( sourceRepoPath ), artifactMetadata.getId(), artifactMetadata.getProject(),
202 // artifactMetadata.getVersion(), fileName );
204 // String relativePathToPomFile = sourcePomFile.getAbsolutePath().split( sourceRepoPath )[1];
205 // File targetPomFile = new File( targetRepoPath, relativePathToPomFile );
207 //pom file copying (file path is taken with out using path translator)
209 String index = artifactPath.substring( lastIndex + 1 );
210 int last = index.lastIndexOf( '.' );
211 File sourcePomFile = new File( sourceRepoPath,
212 artifactPath.substring( 0, lastIndex ) + "/" + artifactPath.substring(
213 lastIndex + 1 ).substring( 0, last ) + ".pom" );
214 File targetPomFile = new File( targetRepoPath,
215 artifactPath.substring( 0, lastIndex ) + "/" + artifactPath.substring(
216 lastIndex + 1 ).substring( 0, last ) + ".pom" );
218 if ( !targetPomFile.exists() && sourcePomFile.exists() )
220 copyFile( sourcePomFile, targetPomFile );
223 // explicitly update only if metadata-updater consumer is not enabled!
224 if ( !config.getRepositoryScanning().getKnownContentConsumers().contains( "metadata-updater" ) )
227 // updating version metadata files
228 File versionMetaDataFileInSourceRepo =
229 pathTranslator.toFile( new File( sourceRepoPath ), artifactMetadata.getNamespace(),
230 artifactMetadata.getProject(), artifactMetadata.getVersion(),
233 if ( versionMetaDataFileInSourceRepo.exists() )
234 {//Pattern quote for windows path
235 String relativePathToVersionMetadataFile =
236 versionMetaDataFileInSourceRepo.getAbsolutePath().split( Pattern.quote( sourceRepoPath ) )[1];
237 File versionMetaDataFileInTargetRepo = new File( targetRepoPath, relativePathToVersionMetadataFile );
239 if ( !versionMetaDataFileInTargetRepo.exists() )
241 copyFile( versionMetaDataFileInSourceRepo, versionMetaDataFileInTargetRepo );
245 updateVersionMetadata( versionMetaDataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp );
250 // updating project meta data file
251 String projectDirectoryInSourceRepo = new File( versionMetaDataFileInSourceRepo.getParent() ).getParent();
252 File projectMetadataFileInSourceRepo = new File( projectDirectoryInSourceRepo, METADATA_FILENAME );
254 if ( projectMetadataFileInSourceRepo.exists() )
256 String relativePathToProjectMetadataFile =
257 projectMetadataFileInSourceRepo.getAbsolutePath().split( Pattern.quote( sourceRepoPath ) )[1];
258 File projectMetadataFileInTargetRepo = new File( targetRepoPath, relativePathToProjectMetadataFile );
260 if ( !projectMetadataFileInTargetRepo.exists() )
263 copyFile( projectMetadataFileInSourceRepo, projectMetadataFileInTargetRepo );
267 updateProjectMetadata( projectMetadataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp,
275 private void copyFile( File sourceFile, File targetFile )
279 FileUtils.copyFile( sourceFile, targetFile );
283 private void updateProjectMetadata( File projectMetaDataFileIntargetRepo, ArtifactMetadata artifactMetadata,
284 Date lastUpdatedTimestamp, String timestamp )
285 throws RepositoryMetadataException
287 ArrayList<String> availableVersions = new ArrayList<>();
288 String latestVersion = artifactMetadata.getProjectVersion();
290 ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetaDataFileIntargetRepo );
292 if ( projectMetaDataFileIntargetRepo.exists() )
294 availableVersions = (ArrayList<String>) projectMetadata.getAvailableVersions();
296 Collections.sort( availableVersions, VersionComparator.getInstance() );
298 if ( !availableVersions.contains( artifactMetadata.getVersion() ) )
300 availableVersions.add( artifactMetadata.getVersion() );
303 latestVersion = availableVersions.get( availableVersions.size() - 1 );
307 availableVersions.add( artifactMetadata.getProjectVersion() );
308 projectMetadata.setGroupId( artifactMetadata.getNamespace() );
309 projectMetadata.setArtifactId( artifactMetadata.getProject() );
312 if ( projectMetadata.getGroupId() == null )
314 projectMetadata.setGroupId( artifactMetadata.getNamespace() );
317 if ( projectMetadata.getArtifactId() == null )
319 projectMetadata.setArtifactId( artifactMetadata.getProject() );
322 projectMetadata.setLatestVersion( latestVersion );
323 projectMetadata.setAvailableVersions( availableVersions );
324 projectMetadata.setLastUpdated( timestamp );
325 projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
327 if ( !VersionUtil.isSnapshot( artifactMetadata.getVersion() ) )
329 projectMetadata.setReleasedVersion( latestVersion );
332 RepositoryMetadataWriter.write( projectMetadata, projectMetaDataFileIntargetRepo.toPath() );
336 private void updateVersionMetadata( File versionMetaDataFileInTargetRepo, ArtifactMetadata artifactMetadata,
337 Date lastUpdatedTimestamp )
338 throws RepositoryMetadataException
340 ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetaDataFileInTargetRepo );
341 if ( !versionMetaDataFileInTargetRepo.exists() )
343 versionMetadata.setGroupId( artifactMetadata.getNamespace() );
344 versionMetadata.setArtifactId( artifactMetadata.getProject() );
345 versionMetadata.setVersion( artifactMetadata.getProjectVersion() );
348 versionMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
349 RepositoryMetadataWriter.write( versionMetadata, versionMetaDataFileInTargetRepo.toPath() );
352 private ArchivaRepositoryMetadata getMetadata( File metadataFile )
353 throws RepositoryMetadataException
355 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
356 if ( metadataFile.exists() )
360 metadata = MavenMetadataReader.read( metadataFile );
362 catch ( XMLException e )
364 throw new RepositoryMetadataException( e.getMessage(), e );
371 public List<ArtifactMetadata> getConflictingArtifacts( MetadataRepository metadataRepository, String sourceRepo,
373 throws RepositoryMergerException
377 List<ArtifactMetadata> targetArtifacts = metadataRepository.getArtifacts( targetRepo );
378 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( sourceRepo );
379 List<ArtifactMetadata> conflictsArtifacts = new ArrayList<>();
381 for ( ArtifactMetadata targetArtifact : targetArtifacts )
383 for ( ArtifactMetadata sourceArtifact : sourceArtifacts )
385 if ( isEquals( targetArtifact, sourceArtifact ) )
387 if ( !conflictsArtifacts.contains( sourceArtifact ) )
389 conflictsArtifacts.add( sourceArtifact );
395 sourceArtifacts.removeAll( conflictsArtifacts );
397 return conflictsArtifacts;
399 catch ( MetadataRepositoryException e )
401 throw new RepositoryMergerException( e.getMessage(), e );
405 private boolean isEquals( ArtifactMetadata sourceArtifact, ArtifactMetadata targetArtifact )
407 boolean isSame = false;
409 if ( ( sourceArtifact.getNamespace().equals( targetArtifact.getNamespace() ) )
410 && ( sourceArtifact.getProject().equals( targetArtifact.getProject() ) ) && ( sourceArtifact.getId().equals(
411 targetArtifact.getId() ) ) && ( sourceArtifact.getProjectVersion().equals(
412 targetArtifact.getProjectVersion() ) ) )