]> source.dussan.org Git - archiva.git/blob
bc65d9959e69a99c4a3df9c136dac89d7155ae3d
[archiva.git] /
1 package org.apache.archiva.consumers.core.repository;
2
3 /*
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
11  *
12  *  http://www.apache.org/licenses/LICENSE-2.0
13  *
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
19  * under the License.
20  */
21
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;
36
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;
44 import java.util.Set;
45 import java.util.TimeZone;
46 import java.util.regex.Matcher;
47 import java.util.stream.Collectors;
48 import java.util.stream.Stream;
49
50 /**
51  * Purge from repository all snapshots older than the specified days in the repository configuration.
52  */
53 public class DaysOldRepositoryPurge
54     extends AbstractRepositoryPurge
55 {
56     private SimpleDateFormat timestampParser;
57
58     private int retentionPeriod;
59
60     private int retentionCount;
61
62     public DaysOldRepositoryPurge( ManagedRepositoryContent repository, int retentionPeriod, int retentionCount,
63                                    RepositorySession repositorySession, List<RepositoryListener> listeners )
64     {
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" ) );
70     }
71
72     @Override
73     public void process( String path )
74         throws RepositoryPurgeException
75     {
76         try
77         {
78
79             ContentItem item = repository.toItem( path );
80             if ( item instanceof Artifact )
81             {
82                 Artifact artifactItem = (Artifact) item;
83
84                 if ( !artifactItem.exists( ) )
85                 {
86                     return;
87                 }
88
89                 // ArtifactReference artifact = repository.toArtifactReference( path );
90
91                 Calendar olderThanThisDate = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
92                 olderThanThisDate.add( Calendar.DATE, -retentionPeriod );
93
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( )
105                     .build( );
106
107                 List<String> artifactVersions;
108                 try( Stream<? extends Artifact> stream = repository.newArtifactStream( selector )){
109                      artifactVersions = stream.map( a -> a.getArtifactVersion( ) )
110                          .filter( StringUtils::isNotEmpty )
111                          .distinct()
112                          .collect( Collectors.toList( ) );
113                 }
114
115                 Collections.sort( artifactVersions, VersionComparator.getInstance( ) );
116
117                 if ( retentionCount > artifactVersions.size( ) )
118                 {
119                     // Done. nothing to do here. skip it.
120                     return;
121                 }
122
123                 int countToPurge = artifactVersions.size( ) - retentionCount;
124
125
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( );
133
134                 Set<Artifact> artifactsToDelete = new HashSet<>( );
135                 for ( String version : artifactVersions )
136                 {
137                     if ( countToPurge-- <= 0 )
138                     {
139                         break;
140                     }
141
142                     ArchivaItemSelector artifactSelector = artifactSelectorBuilder.withArtifactVersion( version ).build( );
143                     try
144                     {
145
146
147                         // Is this a generic snapshot "1.0-SNAPSHOT" ?
148                         if ( VersionUtil.isGenericSnapshot( version ) )
149                         {
150                             List<? extends Artifact> artifactList = repository.getArtifacts( artifactSelector );
151                             if ( artifactList.size()>0 && artifactList.get(0).getAsset().getModificationTime( ).toEpochMilli( ) < olderThanThisDate.getTimeInMillis( ) )
152                             {
153                                 artifactsToDelete.addAll( artifactList );
154                             }
155                         }
156                         // Is this a timestamp snapshot "1.0-20070822.123456-42" ?
157                         else if ( VersionUtil.isUniqueSnapshot( version ) )
158                         {
159                             Calendar timestampCal = uniqueSnapshotToCalendar( version );
160
161                             if ( timestampCal.getTimeInMillis( ) < olderThanThisDate.getTimeInMillis( ) )
162                             {
163                                 artifactsToDelete.addAll( repository.getArtifacts( artifactSelector ) );
164                             }
165                         }
166                     } catch ( IllegalArgumentException e ) {
167                         log.error( "Bad selector for artifact: {}", e.getMessage( ), e );
168                         // continue
169                     }
170                 }
171                 purge( artifactsToDelete );
172             }
173         }
174         catch ( LayoutException e )
175         {
176             log.debug( "Not processing file that is not an artifact: {}", e.getMessage( ) );
177         }
178         catch ( org.apache.archiva.repository.ContentAccessException e )
179         {
180             e.printStackTrace( );
181         }
182     }
183
184     private Calendar uniqueSnapshotToCalendar( String version )
185     {
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}
188
189         Matcher m = VersionUtil.UNIQUE_SNAPSHOT_PATTERN.matcher( version );
190         if ( m.matches( ) )
191         {
192             Matcher mtimestamp = VersionUtil.TIMESTAMP_PATTERN.matcher( m.group( 2 ) );
193             if ( mtimestamp.matches( ) )
194             {
195                 String tsDate = mtimestamp.group( 1 );
196                 String tsTime = mtimestamp.group( 2 );
197
198                 Date versionDate;
199                 try
200                 {
201                     versionDate = timestampParser.parse( tsDate + "." + tsTime );
202                     Calendar cal = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
203                     cal.setTime( versionDate );
204
205                     return cal;
206                 }
207                 catch ( ParseException e )
208                 {
209                     // Invalid Date/Time
210                     return null;
211                 }
212             }
213         }
214         return null;
215     }
216
217 }