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;
45 import java.io.IOException;
46 import java.nio.file.Files;
47 import java.nio.file.Path;
48 import java.nio.file.Paths;
49 import java.text.DateFormat;
50 import java.text.SimpleDateFormat;
51 import java.util.ArrayList;
52 import java.util.Calendar;
53 import java.util.Collections;
54 import java.util.Date;
55 import java.util.List;
56 import java.util.TimeZone;
57 import java.util.regex.Pattern;
62 @Service ("repositoryMerger#maven2")
63 public class Maven2RepositoryMerger
64 implements RepositoryMerger
67 private Logger log = LoggerFactory.getLogger( getClass() );
72 private ArchivaConfiguration configuration;
77 private RepositoryPathTranslator pathTranslator;
79 private static final String METADATA_FILENAME = "maven-metadata.xml";
82 public Maven2RepositoryMerger(
83 @Named (value = "archivaConfiguration#default") ArchivaConfiguration archivaConfiguration,
84 @Named (value = "repositoryPathTranslator#maven2") RepositoryPathTranslator repositoryPathTranslator )
86 this.configuration = archivaConfiguration;
87 this.pathTranslator = repositoryPathTranslator;
90 public void setConfiguration( ArchivaConfiguration configuration )
92 this.configuration = configuration;
96 public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId )
97 throws RepositoryMergerException
102 List<ArtifactMetadata> artifactsInSourceRepo = metadataRepository.getArtifacts( sourceRepoId );
103 for ( ArtifactMetadata artifactMetadata : artifactsInSourceRepo )
105 artifactMetadata.setRepositoryId( targetRepoId );
106 createFolderStructure( sourceRepoId, targetRepoId, artifactMetadata );
109 catch ( MetadataRepositoryException e )
111 throw new RepositoryMergerException( e.getMessage(), e );
113 catch ( IOException e )
115 throw new RepositoryMergerException( e.getMessage(), e );
117 catch ( RepositoryException e )
119 throw new RepositoryMergerException( e.getMessage(), e );
123 // TODO when UI needs a subset to merge
125 public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId,
126 Filter<ArtifactMetadata> filter )
127 throws RepositoryMergerException
131 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( sourceRepoId );
132 for ( ArtifactMetadata metadata : sourceArtifacts )
134 if ( filter.accept( metadata ) )
136 createFolderStructure( sourceRepoId, targetRepoId, metadata );
140 catch ( MetadataRepositoryException e )
142 throw new RepositoryMergerException( e.getMessage(), e );
144 catch ( IOException e )
146 throw new RepositoryMergerException( e.getMessage(), e );
148 catch ( RepositoryException e )
150 throw new RepositoryMergerException( e.getMessage(), e );
154 private void createFolderStructure( String sourceRepoId, String targetRepoId, ArtifactMetadata artifactMetadata )
155 throws IOException, RepositoryException
157 Configuration config = configuration.getConfiguration();
159 ManagedRepositoryConfiguration targetRepoConfig = config.findManagedRepositoryById( targetRepoId );
161 ManagedRepositoryConfiguration sourceRepoConfig = config.findManagedRepositoryById( sourceRepoId );
163 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
165 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
167 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
169 fmt.setTimeZone( timezone );
171 String timestamp = fmt.format( lastUpdatedTimestamp );
173 String targetRepoPath = targetRepoConfig.getLocation();
175 String sourceRepoPath = sourceRepoConfig.getLocation();
177 String artifactPath = pathTranslator.toPath( artifactMetadata.getNamespace(), artifactMetadata.getProject(),
178 artifactMetadata.getProjectVersion(), artifactMetadata.getId() );
180 Path sourceArtifactFile = Paths.get( sourceRepoPath, artifactPath );
182 Path targetArtifactFile = Paths.get( targetRepoPath, artifactPath );
184 log.debug( "artifactPath {}", artifactPath );
186 int lastIndex = artifactPath.lastIndexOf( RepositoryPathTranslator.PATH_SEPARATOR );
188 Path targetFile = Paths.get( targetRepoPath, artifactPath.substring( 0, lastIndex ) );
190 if ( !Files.exists(targetFile) )
192 // create the folder structure when it does not exist
193 Files.createDirectories(targetFile);
196 copyFile( sourceArtifactFile, targetArtifactFile );
199 // TODO need to use path translator to get the pom file path
200 // String fileName = artifactMetadata.getProject() + "-" + artifactMetadata.getVersion() + ".pom";
202 // File sourcePomFile =
203 // pathTranslator.toFile( new File( sourceRepoPath ), artifactMetadata.getId(), artifactMetadata.getProject(),
204 // artifactMetadata.getVersion(), fileName );
206 // String relativePathToPomFile = sourcePomFile.getAbsolutePath().split( sourceRepoPath )[1];
207 // File targetPomFile = new File( targetRepoPath, relativePathToPomFile );
209 //pom file copying (file path is taken with out using path translator)
211 String index = artifactPath.substring( lastIndex + 1 );
212 int last = index.lastIndexOf( '.' );
213 Path sourcePomFile = Paths.get( sourceRepoPath,
214 artifactPath.substring( 0, lastIndex ) + "/" + artifactPath.substring(
215 lastIndex + 1 ).substring( 0, last ) + ".pom" );
216 Path targetPomFile = Paths.get( targetRepoPath,
217 artifactPath.substring( 0, lastIndex ) + "/" + artifactPath.substring(
218 lastIndex + 1 ).substring( 0, last ) + ".pom" );
220 if ( !Files.exists(targetPomFile) && Files.exists(sourcePomFile) )
222 copyFile( sourcePomFile, targetPomFile );
225 // explicitly update only if metadata-updater consumer is not enabled!
226 if ( !config.getRepositoryScanning().getKnownContentConsumers().contains( "metadata-updater" ) )
229 // updating version metadata files
230 Path versionMetaDataFileInSourceRepo =
231 pathTranslator.toFile( Paths.get( sourceRepoPath ), artifactMetadata.getNamespace(),
232 artifactMetadata.getProject(), artifactMetadata.getVersion(),
235 if ( Files.exists(versionMetaDataFileInSourceRepo) )
236 {//Pattern quote for windows path
237 String relativePathToVersionMetadataFile =
238 versionMetaDataFileInSourceRepo.toAbsolutePath().toString().split( Pattern.quote( sourceRepoPath ) )[1];
239 Path versionMetaDataFileInTargetRepo = Paths.get( targetRepoPath, relativePathToVersionMetadataFile );
241 if ( !Files.exists(versionMetaDataFileInTargetRepo) )
243 copyFile( versionMetaDataFileInSourceRepo, versionMetaDataFileInTargetRepo );
247 updateVersionMetadata( versionMetaDataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp );
252 // updating project meta data file
253 Path projectDirectoryInSourceRepo = versionMetaDataFileInSourceRepo.getParent().getParent();
254 Path projectMetadataFileInSourceRepo = projectDirectoryInSourceRepo.resolve(METADATA_FILENAME );
256 if ( Files.exists(projectMetadataFileInSourceRepo) )
258 String relativePathToProjectMetadataFile =
259 projectMetadataFileInSourceRepo.toAbsolutePath().toString().split( Pattern.quote( sourceRepoPath ) )[1];
260 Path projectMetadataFileInTargetRepo = Paths.get( targetRepoPath, relativePathToProjectMetadataFile );
262 if ( !Files.exists(projectMetadataFileInTargetRepo) )
265 copyFile( projectMetadataFileInSourceRepo, projectMetadataFileInTargetRepo );
269 updateProjectMetadata( projectMetadataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp,
277 private void copyFile( Path sourceFile, Path targetFile )
281 FileUtils.copyFile( sourceFile.toFile(), targetFile.toFile() );
285 private void updateProjectMetadata( Path projectMetaDataFileIntargetRepo, ArtifactMetadata artifactMetadata,
286 Date lastUpdatedTimestamp, String timestamp )
287 throws RepositoryMetadataException
289 ArrayList<String> availableVersions = new ArrayList<>();
290 String latestVersion = artifactMetadata.getProjectVersion();
292 ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetaDataFileIntargetRepo );
294 if ( Files.exists(projectMetaDataFileIntargetRepo) )
296 availableVersions = (ArrayList<String>) projectMetadata.getAvailableVersions();
298 Collections.sort( availableVersions, VersionComparator.getInstance() );
300 if ( !availableVersions.contains( artifactMetadata.getVersion() ) )
302 availableVersions.add( artifactMetadata.getVersion() );
305 latestVersion = availableVersions.get( availableVersions.size() - 1 );
309 availableVersions.add( artifactMetadata.getProjectVersion() );
310 projectMetadata.setGroupId( artifactMetadata.getNamespace() );
311 projectMetadata.setArtifactId( artifactMetadata.getProject() );
314 if ( projectMetadata.getGroupId() == null )
316 projectMetadata.setGroupId( artifactMetadata.getNamespace() );
319 if ( projectMetadata.getArtifactId() == null )
321 projectMetadata.setArtifactId( artifactMetadata.getProject() );
324 projectMetadata.setLatestVersion( latestVersion );
325 projectMetadata.setAvailableVersions( availableVersions );
326 projectMetadata.setLastUpdated( timestamp );
327 projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
329 if ( !VersionUtil.isSnapshot( artifactMetadata.getVersion() ) )
331 projectMetadata.setReleasedVersion( latestVersion );
334 RepositoryMetadataWriter.write( projectMetadata, projectMetaDataFileIntargetRepo );
338 private void updateVersionMetadata( Path versionMetaDataFileInTargetRepo, ArtifactMetadata artifactMetadata,
339 Date lastUpdatedTimestamp )
340 throws RepositoryMetadataException
342 ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetaDataFileInTargetRepo );
343 if ( !Files.exists(versionMetaDataFileInTargetRepo) )
345 versionMetadata.setGroupId( artifactMetadata.getNamespace() );
346 versionMetadata.setArtifactId( artifactMetadata.getProject() );
347 versionMetadata.setVersion( artifactMetadata.getProjectVersion() );
350 versionMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
351 RepositoryMetadataWriter.write( versionMetadata, versionMetaDataFileInTargetRepo );
354 private ArchivaRepositoryMetadata getMetadata( Path metadataFile )
355 throws RepositoryMetadataException
357 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
358 if ( Files.exists(metadataFile) )
362 metadata = MavenMetadataReader.read( metadataFile );
364 catch ( XMLException e )
366 throw new RepositoryMetadataException( e.getMessage(), e );
373 public List<ArtifactMetadata> getConflictingArtifacts( MetadataRepository metadataRepository, String sourceRepo,
375 throws RepositoryMergerException
379 List<ArtifactMetadata> targetArtifacts = metadataRepository.getArtifacts( targetRepo );
380 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( sourceRepo );
381 List<ArtifactMetadata> conflictsArtifacts = new ArrayList<>();
383 for ( ArtifactMetadata targetArtifact : targetArtifacts )
385 for ( ArtifactMetadata sourceArtifact : sourceArtifacts )
387 if ( isEquals( targetArtifact, sourceArtifact ) )
389 if ( !conflictsArtifacts.contains( sourceArtifact ) )
391 conflictsArtifacts.add( sourceArtifact );
397 sourceArtifacts.removeAll( conflictsArtifacts );
399 return conflictsArtifacts;
401 catch ( MetadataRepositoryException e )
403 throw new RepositoryMergerException( e.getMessage(), e );
407 private boolean isEquals( ArtifactMetadata sourceArtifact, ArtifactMetadata targetArtifact )
409 boolean isSame = false;
411 if ( ( sourceArtifact.getNamespace().equals( targetArtifact.getNamespace() ) )
412 && ( sourceArtifact.getProject().equals( targetArtifact.getProject() ) ) && ( sourceArtifact.getId().equals(
413 targetArtifact.getId() ) ) && ( sourceArtifact.getProjectVersion().equals(
414 targetArtifact.getProjectVersion() ) ) )