1 package org.apache.maven.plugin.clean;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24
25 import org.apache.maven.plugin.logging.Log;
26 import org.codehaus.plexus.util.Os;
27
28
29
30
31
32
33 class Cleaner
34 {
35
36 private static final boolean ON_WINDOWS = Os.isFamily( Os.FAMILY_WINDOWS );
37
38 private final Logger logDebug;
39
40 private final Logger logInfo;
41
42 private final Logger logVerbose;
43
44 private final Logger logWarn;
45
46
47
48
49
50
51
52 public Cleaner( final Log log, boolean verbose )
53 {
54 logDebug = ( log == null || !log.isDebugEnabled() ) ? null : new Logger()
55 {
56 public void log( CharSequence message )
57 {
58 log.debug( message );
59 }
60 };
61
62 logInfo = ( log == null || !log.isInfoEnabled() ) ? null : new Logger()
63 {
64 public void log( CharSequence message )
65 {
66 log.info( message );
67 }
68 };
69
70 logWarn = ( log == null || !log.isWarnEnabled() ) ? null : new Logger()
71 {
72 public void log( CharSequence message )
73 {
74 log.warn( message );
75 }
76 };
77
78 logVerbose = verbose ? logInfo : logDebug;
79 }
80
81
82
83
84
85
86
87
88
89
90
91
92
93 public void delete( File basedir, Selector selector, boolean followSymlinks, boolean failOnError,
94 boolean retryOnError )
95 throws IOException
96 {
97 if ( !basedir.isDirectory() )
98 {
99 if ( !basedir.exists() )
100 {
101 if ( logDebug != null )
102 {
103 logDebug.log( "Skipping non-existing directory " + basedir );
104 }
105 return;
106 }
107 throw new IOException( "Invalid base directory " + basedir );
108 }
109
110 if ( logInfo != null )
111 {
112 logInfo.log( "Deleting " + basedir + ( selector != null ? " (" + selector + ")" : "" ) );
113 }
114
115 File file = followSymlinks ? basedir : basedir.getCanonicalFile();
116
117 delete( file, "", selector, followSymlinks, failOnError, retryOnError );
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 private Result delete( File file, String pathname, Selector selector, boolean followSymlinks, boolean failOnError,
136 boolean retryOnError )
137 throws IOException
138 {
139 Result result = new Result();
140
141 boolean isDirectory = file.isDirectory();
142
143 if ( isDirectory )
144 {
145 if ( selector == null || selector.couldHoldSelected( pathname ) )
146 {
147 File canonical = followSymlinks ? file : file.getCanonicalFile();
148 if ( followSymlinks || file.equals( canonical ) )
149 {
150 String[] filenames = canonical.list();
151 if ( filenames != null )
152 {
153 String prefix = ( pathname.length() > 0 ) ? pathname + File.separatorChar : "";
154 for ( int i = filenames.length - 1; i >= 0; i-- )
155 {
156 String filename = filenames[i];
157 File child = new File( canonical, filename );
158 result.update( delete( child, prefix + filename, selector, followSymlinks, failOnError,
159 retryOnError ) );
160 }
161 }
162 }
163 else if ( logDebug != null )
164 {
165 logDebug.log( "Not recursing into symlink " + file );
166 }
167 }
168 else if ( logDebug != null )
169 {
170 logDebug.log( "Not recursing into directory without included files " + file );
171 }
172 }
173
174 if ( !result.excluded && ( selector == null || selector.isSelected( pathname ) ) )
175 {
176 if ( logVerbose != null )
177 {
178 if ( isDirectory )
179 {
180 logVerbose.log( "Deleting directory " + file );
181 }
182 else if ( file.exists() )
183 {
184 logVerbose.log( "Deleting file " + file );
185 }
186 else
187 {
188 logVerbose.log( "Deleting dangling symlink " + file );
189 }
190 }
191 result.failures += delete( file, failOnError, retryOnError );
192 }
193 else
194 {
195 result.excluded = true;
196 }
197
198 return result;
199 }
200
201
202
203
204
205
206
207
208
209
210
211 private int delete( File file, boolean failOnError, boolean retryOnError )
212 throws IOException
213 {
214 if ( !file.delete() )
215 {
216 boolean deleted = false;
217
218 if ( retryOnError )
219 {
220 if ( ON_WINDOWS )
221 {
222
223 System.gc();
224 }
225
226 int[] delays = { 50, 250, 750 };
227 for ( int i = 0; !deleted && i < delays.length; i++ )
228 {
229 try
230 {
231 Thread.sleep( delays[i] );
232 }
233 catch ( InterruptedException e )
234 {
235
236 }
237 deleted = file.delete() || !file.exists();
238 }
239 }
240 else
241 {
242 deleted = !file.exists();
243 }
244
245 if ( !deleted )
246 {
247 if ( failOnError )
248 {
249 throw new IOException( "Failed to delete " + file );
250 }
251 else
252 {
253 if ( logWarn != null )
254 {
255 logWarn.log( "Failed to delete " + file );
256 }
257 return 1;
258 }
259 }
260 }
261
262 return 0;
263 }
264
265 private static class Result
266 {
267
268 public int failures;
269
270 public boolean excluded;
271
272 public void update( Result result )
273 {
274 failures += result.failures;
275 excluded |= result.excluded;
276 }
277
278 }
279
280 private static interface Logger
281 {
282
283 public void log( CharSequence message );
284
285 }
286
287 }