1 package org.apache.archiva.consumers.core.repository;
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.metadata.audit.RepositoryListener;
25 import org.apache.archiva.metadata.repository.RepositorySession;
26 import org.apache.archiva.model.ArtifactReference;
27 import org.apache.archiva.repository.ContentNotFoundException;
28 import org.apache.archiva.repository.LayoutException;
29 import org.apache.archiva.repository.ManagedRepositoryContent;
30 import org.apache.archiva.repository.content.Artifact;
31 import org.apache.archiva.repository.content.ContentItem;
32 import org.apache.archiva.repository.content.ItemNotFoundException;
33 import org.apache.archiva.repository.content.base.ArchivaItemSelector;
34 import org.apache.archiva.repository.storage.StorageAsset;
35 import org.apache.commons.lang3.StringUtils;
37 import java.text.ParseException;
38 import java.text.SimpleDateFormat;
39 import java.util.Calendar;
40 import java.util.Collections;
41 import java.util.Date;
42 import java.util.HashSet;
43 import java.util.List;
45 import java.util.TimeZone;
46 import java.util.regex.Matcher;
47 import java.util.stream.Collectors;
48 import java.util.stream.Stream;
51 * Purge from repository all snapshots older than the specified days in the repository configuration.
53 public class DaysOldRepositoryPurge
54 extends AbstractRepositoryPurge
56 private SimpleDateFormat timestampParser;
58 private int retentionPeriod;
60 private int retentionCount;
62 public DaysOldRepositoryPurge( ManagedRepositoryContent repository, int retentionPeriod, int retentionCount,
63 RepositorySession repositorySession, List<RepositoryListener> listeners )
65 super( repository, repositorySession, listeners );
66 this.retentionPeriod = retentionPeriod;
67 this.retentionCount = retentionCount;
68 timestampParser = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
69 timestampParser.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
73 public void process( String path )
74 throws RepositoryPurgeException
79 ContentItem item = repository.toItem( path );
80 if ( item instanceof Artifact )
82 Artifact artifactItem = (Artifact) item;
84 if ( !artifactItem.exists( ) )
89 // ArtifactReference artifact = repository.toArtifactReference( path );
91 Calendar olderThanThisDate = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
92 olderThanThisDate.add( Calendar.DATE, -retentionPeriod );
94 ArchivaItemSelector selector = ArchivaItemSelector.builder( )
95 .withNamespace( artifactItem.getVersion( ).getProject( ).getNamespace( ).getNamespace( ) )
96 .withProjectId( artifactItem.getVersion( ).getProject( ).getId( ) )
97 .withVersion( artifactItem.getVersion( ).getVersion( ) )
98 .withClassifier( "*" )
99 .includeRelatedArtifacts( )
102 List<String> artifactVersions;
103 try( Stream<? extends Artifact> stream = repository.newArtifactStream( selector )){
104 artifactVersions = stream.map( a -> a.getArtifactVersion( ) )
105 .filter( StringUtils::isNotEmpty )
107 .collect( Collectors.toList( ) );
110 Collections.sort( artifactVersions, VersionComparator.getInstance( ) );
112 if ( retentionCount > artifactVersions.size( ) )
114 // Done. nothing to do here. skip it.
118 int countToPurge = artifactVersions.size( ) - retentionCount;
121 ArchivaItemSelector.Builder artifactSelectorBuilder = ArchivaItemSelector.builder( )
122 .withNamespace( artifactItem.getVersion( ).getProject( ).getNamespace( ).getNamespace( ) )
123 .withProjectId( artifactItem.getVersion( ).getProject( ).getId( ) )
124 .withVersion( artifactItem.getVersion( ).getVersion( ) )
125 .withArtifactId( artifactItem.getId() )
126 .withClassifier( "*" )
127 .includeRelatedArtifacts( );
129 Set<Artifact> artifactsToDelete = new HashSet<>( );
130 for ( String version : artifactVersions )
132 if ( countToPurge-- <= 0 )
137 ArchivaItemSelector artifactSelector = artifactSelectorBuilder.withArtifactVersion( version ).build( );
142 // Is this a generic snapshot "1.0-SNAPSHOT" ?
143 if ( VersionUtil.isGenericSnapshot( version ) )
145 List<? extends Artifact> artifactList = repository.getArtifacts( artifactSelector );
146 if ( artifactList.size()>0 && artifactList.get(0).getAsset().getModificationTime( ).toEpochMilli( ) < olderThanThisDate.getTimeInMillis( ) )
148 artifactsToDelete.addAll( artifactList );
151 // Is this a timestamp snapshot "1.0-20070822.123456-42" ?
152 else if ( VersionUtil.isUniqueSnapshot( version ) )
154 Calendar timestampCal = uniqueSnapshotToCalendar( version );
156 if ( timestampCal.getTimeInMillis( ) < olderThanThisDate.getTimeInMillis( ) )
158 artifactsToDelete.addAll( repository.getArtifacts( artifactSelector ) );
161 } catch ( IllegalArgumentException e ) {
162 log.error( "Bad selector for artifact: {}", e.getMessage( ), e );
166 purge( artifactsToDelete );
169 catch ( LayoutException e )
171 log.debug( "Not processing file that is not an artifact: {}", e.getMessage( ) );
173 catch ( org.apache.archiva.repository.ContentAccessException e )
175 e.printStackTrace( );
179 private Calendar uniqueSnapshotToCalendar( String version )
181 // The latestVersion will contain the full version string "1.0-alpha-5-20070821.213044-8"
182 // This needs to be broken down into ${base}-${timestamp}-${build_number}
184 Matcher m = VersionUtil.UNIQUE_SNAPSHOT_PATTERN.matcher( version );
187 Matcher mtimestamp = VersionUtil.TIMESTAMP_PATTERN.matcher( m.group( 2 ) );
188 if ( mtimestamp.matches( ) )
190 String tsDate = mtimestamp.group( 1 );
191 String tsTime = mtimestamp.group( 2 );
196 versionDate = timestampParser.parse( tsDate + "." + tsTime );
197 Calendar cal = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
198 cal.setTime( versionDate );
202 catch ( ParseException e )