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 // respect retention count
95 // VersionedReference reference = new VersionedReference( );
96 // reference.setGroupId( artifact.getGroupId( ) );
97 // reference.setArtifactId( artifact.getArtifactId( ) );
98 // reference.setVersion( artifact.getVersion( ) );
99 ArchivaItemSelector selector = ArchivaItemSelector.builder( )
100 .withNamespace( artifactItem.getVersion( ).getProject( ).getNamespace( ).getNamespace( ) )
101 .withProjectId( artifactItem.getVersion( ).getProject( ).getId( ) )
102 .withVersion( artifactItem.getVersion( ).getVersion( ) )
103 .withClassifier( "*" )
104 .includeRelatedArtifacts( )
107 List<String> artifactVersions;
108 try( Stream<? extends Artifact> stream = repository.newArtifactStream( selector )){
109 artifactVersions = stream.map( a -> a.getArtifactVersion( ) )
110 .filter( StringUtils::isNotEmpty )
112 .collect( Collectors.toList( ) );
115 Collections.sort( artifactVersions, VersionComparator.getInstance( ) );
117 if ( retentionCount > artifactVersions.size( ) )
119 // Done. nothing to do here. skip it.
123 int countToPurge = artifactVersions.size( ) - retentionCount;
126 ArchivaItemSelector.Builder artifactSelectorBuilder = ArchivaItemSelector.builder( )
127 .withNamespace( artifactItem.getVersion( ).getProject( ).getNamespace( ).getNamespace( ) )
128 .withProjectId( artifactItem.getVersion( ).getProject( ).getId( ) )
129 .withVersion( artifactItem.getVersion( ).getVersion( ) )
130 .withArtifactId( artifactItem.getId() )
131 .withClassifier( "*" )
132 .includeRelatedArtifacts( );
134 Set<Artifact> artifactsToDelete = new HashSet<>( );
135 for ( String version : artifactVersions )
137 if ( countToPurge-- <= 0 )
142 ArchivaItemSelector artifactSelector = artifactSelectorBuilder.withArtifactVersion( version ).build( );
147 // Is this a generic snapshot "1.0-SNAPSHOT" ?
148 if ( VersionUtil.isGenericSnapshot( version ) )
150 List<? extends Artifact> artifactList = repository.getArtifacts( artifactSelector );
151 if ( artifactList.size()>0 && artifactList.get(0).getAsset().getModificationTime( ).toEpochMilli( ) < olderThanThisDate.getTimeInMillis( ) )
153 artifactsToDelete.addAll( artifactList );
156 // Is this a timestamp snapshot "1.0-20070822.123456-42" ?
157 else if ( VersionUtil.isUniqueSnapshot( version ) )
159 Calendar timestampCal = uniqueSnapshotToCalendar( version );
161 if ( timestampCal.getTimeInMillis( ) < olderThanThisDate.getTimeInMillis( ) )
163 artifactsToDelete.addAll( repository.getArtifacts( artifactSelector ) );
166 } catch ( IllegalArgumentException e ) {
167 log.error( "Bad selector for artifact: {}", e.getMessage( ), e );
171 purge( artifactsToDelete );
174 catch ( LayoutException e )
176 log.debug( "Not processing file that is not an artifact: {}", e.getMessage( ) );
178 catch ( org.apache.archiva.repository.ContentAccessException e )
180 e.printStackTrace( );
184 private Calendar uniqueSnapshotToCalendar( String version )
186 // The latestVersion will contain the full version string "1.0-alpha-5-20070821.213044-8"
187 // This needs to be broken down into ${base}-${timestamp}-${build_number}
189 Matcher m = VersionUtil.UNIQUE_SNAPSHOT_PATTERN.matcher( version );
192 Matcher mtimestamp = VersionUtil.TIMESTAMP_PATTERN.matcher( m.group( 2 ) );
193 if ( mtimestamp.matches( ) )
195 String tsDate = mtimestamp.group( 1 );
196 String tsTime = mtimestamp.group( 2 );
201 versionDate = timestampParser.parse( tsDate + "." + tsTime );
202 Calendar cal = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
203 cal.setTime( versionDate );
207 catch ( ParseException e )