]> source.dussan.org Git - archiva.git/blob
7e61593072303af29d2f286e61d299fa52e06a2e
[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                 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( )
100                     .build( );
101
102                 List<String> artifactVersions;
103                 try( Stream<? extends Artifact> stream = repository.newArtifactStream( selector )){
104                      artifactVersions = stream.map( a -> a.getArtifactVersion( ) )
105                          .filter( StringUtils::isNotEmpty )
106                          .distinct()
107                          .collect( Collectors.toList( ) );
108                 }
109
110                 Collections.sort( artifactVersions, VersionComparator.getInstance( ) );
111
112                 if ( retentionCount > artifactVersions.size( ) )
113                 {
114                     // Done. nothing to do here. skip it.
115                     return;
116                 }
117
118                 int countToPurge = artifactVersions.size( ) - retentionCount;
119
120
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( );
128
129                 Set<Artifact> artifactsToDelete = new HashSet<>( );
130                 for ( String version : artifactVersions )
131                 {
132                     if ( countToPurge-- <= 0 )
133                     {
134                         break;
135                     }
136
137                     ArchivaItemSelector artifactSelector = artifactSelectorBuilder.withArtifactVersion( version ).build( );
138                     try
139                     {
140
141
142                         // Is this a generic snapshot "1.0-SNAPSHOT" ?
143                         if ( VersionUtil.isGenericSnapshot( version ) )
144                         {
145                             List<? extends Artifact> artifactList = repository.getArtifacts( artifactSelector );
146                             if ( artifactList.size()>0 && artifactList.get(0).getAsset().getModificationTime( ).toEpochMilli( ) < olderThanThisDate.getTimeInMillis( ) )
147                             {
148                                 artifactsToDelete.addAll( artifactList );
149                             }
150                         }
151                         // Is this a timestamp snapshot "1.0-20070822.123456-42" ?
152                         else if ( VersionUtil.isUniqueSnapshot( version ) )
153                         {
154                             Calendar timestampCal = uniqueSnapshotToCalendar( version );
155
156                             if ( timestampCal.getTimeInMillis( ) < olderThanThisDate.getTimeInMillis( ) )
157                             {
158                                 artifactsToDelete.addAll( repository.getArtifacts( artifactSelector ) );
159                             }
160                         }
161                     } catch ( IllegalArgumentException e ) {
162                         log.error( "Bad selector for artifact: {}", e.getMessage( ), e );
163                         // continue
164                     }
165                 }
166                 purge( artifactsToDelete );
167             }
168         }
169         catch ( LayoutException e )
170         {
171             log.debug( "Not processing file that is not an artifact: {}", e.getMessage( ) );
172         }
173         catch ( org.apache.archiva.repository.ContentAccessException e )
174         {
175             e.printStackTrace( );
176         }
177     }
178
179     private Calendar uniqueSnapshotToCalendar( String version )
180     {
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}
183
184         Matcher m = VersionUtil.UNIQUE_SNAPSHOT_PATTERN.matcher( version );
185         if ( m.matches( ) )
186         {
187             Matcher mtimestamp = VersionUtil.TIMESTAMP_PATTERN.matcher( m.group( 2 ) );
188             if ( mtimestamp.matches( ) )
189             {
190                 String tsDate = mtimestamp.group( 1 );
191                 String tsTime = mtimestamp.group( 2 );
192
193                 Date versionDate;
194                 try
195                 {
196                     versionDate = timestampParser.parse( tsDate + "." + tsTime );
197                     Calendar cal = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
198                     cal.setTime( versionDate );
199
200                     return cal;
201                 }
202                 catch ( ParseException e )
203                 {
204                     // Invalid Date/Time
205                     return null;
206                 }
207             }
208         }
209         return null;
210     }
211
212 }