1 package org.apache.maven.plugins.clean; 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.maven.execution.MavenSession; 23 import org.apache.maven.plugin.AbstractMojo; 24 import org.apache.maven.plugin.MojoExecutionException; 25 import org.apache.maven.plugins.annotations.Mojo; 26 import org.apache.maven.plugins.annotations.Parameter; 27 28 import java.io.File; 29 import java.io.IOException; 30 31 /** 32 * Goal which cleans the build. 33 * <p> 34 * This attempts to clean a project's working directory of the files that were generated at build-time. By default, it 35 * discovers and deletes the directories configured in <code>project.build.directory</code>, 36 * <code>project.build.outputDirectory</code>, <code>project.build.testOutputDirectory</code>, and 37 * <code>project.reporting.outputDirectory</code>. 38 * </p> 39 * <p> 40 * Files outside the default may also be included in the deletion by configuring the <code>filesets</code> tag. 41 * </p> 42 * 43 * @author <a href="mailto:evenisse@maven.org">Emmanuel Venisse</a> 44 * @see org.apache.maven.plugins.clean.Fileset 45 * @since 2.0 46 */ 47 @Mojo( name = "clean", threadSafe = true ) 48 public class CleanMojo 49 extends AbstractMojo 50 { 51 52 public static final String FAST_MODE_BACKGROUND = "background"; 53 54 public static final String FAST_MODE_AT_END = "at-end"; 55 56 public static final String FAST_MODE_DEFER = "defer"; 57 58 /** 59 * This is where build results go. 60 */ 61 @Parameter( defaultValue = "${project.build.directory}", readonly = true, required = true ) 62 private File directory; 63 64 /** 65 * This is where compiled classes go. 66 */ 67 @Parameter( defaultValue = "${project.build.outputDirectory}", readonly = true, required = true ) 68 private File outputDirectory; 69 70 /** 71 * This is where compiled test classes go. 72 */ 73 @Parameter( defaultValue = "${project.build.testOutputDirectory}", readonly = true, required = true ) 74 private File testOutputDirectory; 75 76 /** 77 * This is where the site plugin generates its pages. 78 * 79 * @since 2.1.1 80 */ 81 @Parameter( defaultValue = "${project.build.outputDirectory}", readonly = true, required = true ) 82 private File reportDirectory; 83 84 /** 85 * Sets whether the plugin runs in verbose mode. As of plugin version 2.3, the default value is derived from Maven's 86 * global debug flag (compare command line switch <code>-X</code>). <br/> 87 * Starting with <b>3.0.0</b> the property has been renamed from <code>clean.verbose</code> to 88 * <code>maven.clean.verbose</code>. 89 * 90 * @since 2.1 91 */ 92 @Parameter( property = "maven.clean.verbose" ) 93 private Boolean verbose; 94 95 /** 96 * The list of file sets to delete, in addition to the default directories. For example: 97 * 98 * <pre> 99 * <filesets> 100 * <fileset> 101 * <directory>src/main/generated</directory> 102 * <followSymlinks>false</followSymlinks> 103 * <useDefaultExcludes>true</useDefaultExcludes> 104 * <includes> 105 * <include>*.java</include> 106 * </includes> 107 * <excludes> 108 * <exclude>Template*</exclude> 109 * </excludes> 110 * </fileset> 111 * </filesets> 112 * </pre> 113 * 114 * @since 2.1 115 */ 116 @Parameter 117 private Fileset[] filesets; 118 119 /** 120 * Sets whether the plugin should follow symbolic links while deleting files from the default output directories of 121 * the project. Not following symlinks requires more IO operations and heap memory, regardless whether symlinks are 122 * actually present. So projects with a huge output directory that knowingly does not contain symlinks can improve 123 * performance by setting this parameter to <code>true</code>. <br/> 124 * Starting with <code>3.0.0</code> the property has been renamed from <code>clean.followSymLinks</code> to 125 * <code>maven.clean.followSymLinks</code>. 126 * 127 * @since 2.1 128 */ 129 @Parameter( property = "maven.clean.followSymLinks", defaultValue = "false" ) 130 private boolean followSymLinks; 131 132 /** 133 * Disables the plugin execution. <br/> 134 * Starting with <code>3.0.0</code> the property has been renamed from <code>clean.skip</code> to 135 * <code>maven.clean.skip</code>. 136 * 137 * @since 2.2 138 */ 139 @Parameter( property = "maven.clean.skip", defaultValue = "false" ) 140 private boolean skip; 141 142 /** 143 * Indicates whether the build will continue even if there are clean errors. 144 * 145 * @since 2.2 146 */ 147 @Parameter( property = "maven.clean.failOnError", defaultValue = "true" ) 148 private boolean failOnError; 149 150 /** 151 * Indicates whether the plugin should undertake additional attempts (after a short delay) to delete a file if the 152 * first attempt failed. This is meant to help deleting files that are temporarily locked by third-party tools like 153 * virus scanners or search indexing. 154 * 155 * @since 2.4.2 156 */ 157 @Parameter( property = "maven.clean.retryOnError", defaultValue = "true" ) 158 private boolean retryOnError; 159 160 /** 161 * Disables the deletion of the default output directories configured for a project. If set to <code>true</code>, 162 * only the files/directories selected via the parameter {@link #filesets} will be deleted. <br/> 163 * Starting with <b>3.0.0</b> the property has been renamed from <code>clean.excludeDefaultDirectories</code> to 164 * <code>maven.clean.excludeDefaultDirectories</code>. 165 * 166 * @since 2.3 167 */ 168 @Parameter( property = "maven.clean.excludeDefaultDirectories", defaultValue = "false" ) 169 private boolean excludeDefaultDirectories; 170 171 /** 172 * Enables fast clean if possible. If set to <code>true</code>, when the plugin is executed, a directory to 173 * be deleted will be atomically moved inside the <code>maven.clean.fastDir</code> directory and a thread will 174 * be launched to delete the needed files in the background. When the build is completed, maven will wait 175 * until all the files have been deleted. If any problem occurs during the atomic move of the directories, 176 * the plugin will default to the traditional deletion mechanism. 177 * 178 * @since 3.2 179 */ 180 @Parameter( property = "maven.clean.fast", defaultValue = "false" ) 181 private boolean fast; 182 183 /** 184 * When fast clean is specified, the <code>fastDir</code> property will be used as the location where directories 185 * to be deleted will be moved prior to background deletion. If not specified, the 186 * <code>${maven.multiModuleProjectDirectory}/target/.clean</code> directory will be used. If the 187 * <code>${build.directory}</code> has been modified, you'll have to adjust this property explicitly. 188 * In order for fast clean to work correctly, this directory and the various directories that will be deleted 189 * should usually reside on the same volume. The exact conditions are system dependant though, but if an atomic 190 * move is not supported, the standard deletion mechanism will be used. 191 * 192 * @since 3.2 193 * @see #fast 194 */ 195 @Parameter( property = "maven.clean.fastDir" ) 196 private File fastDir; 197 198 /** 199 * Mode to use when using fast clean. Values are: <code>background</code> to start deletion immediately and 200 * waiting for all files to be deleted when the session ends, <code>at-end</code> to indicate that the actual 201 * deletion should be performed synchronously when the session ends, or <code>defer</code> to specify that 202 * the actual file deletion should be started in the background when the session ends (this should only be used 203 * when maven is embedded in a long running process). 204 * 205 * @since 3.2 206 * @see #fast 207 */ 208 @Parameter( property = "maven.clean.fastMode", defaultValue = FAST_MODE_BACKGROUND ) 209 private String fastMode; 210 211 @Parameter( defaultValue = "${session}", readonly = true ) 212 private MavenSession session; 213 214 /** 215 * Deletes file-sets in the following project build directory order: (source) directory, output directory, test 216 * directory, report directory, and then the additional file-sets. 217 * 218 * @throws MojoExecutionException When a directory failed to get deleted. 219 * @see org.apache.maven.plugin.Mojo#execute() 220 */ 221 public void execute() 222 throws MojoExecutionException 223 { 224 if ( skip ) 225 { 226 getLog().info( "Clean is skipped." ); 227 return; 228 } 229 230 String multiModuleProjectDirectory = session != null 231 ? session.getSystemProperties().getProperty( "maven.multiModuleProjectDirectory" ) : null; 232 File fastDir; 233 if ( fast && this.fastDir != null ) 234 { 235 fastDir = this.fastDir; 236 } 237 else if ( fast && multiModuleProjectDirectory != null ) 238 { 239 fastDir = new File( multiModuleProjectDirectory, "target/.clean" ); 240 } 241 else 242 { 243 fastDir = null; 244 if ( fast ) 245 { 246 getLog().warn( "Fast clean requires maven 3.3.1 or newer, " 247 + "or an explicit directory to be specified with the 'fastDir' configuration of " 248 + "this plugin, or the 'maven.clean.fastDir' user property to be set." ); 249 } 250 } 251 if ( fast && !FAST_MODE_BACKGROUND.equals( fastMode ) 252 && !FAST_MODE_AT_END.equals( fastMode ) 253 && !FAST_MODE_DEFER.equals( fastMode ) ) 254 { 255 throw new IllegalArgumentException( "Illegal value '" + fastMode + "' for fastMode. Allowed values are '" 256 + FAST_MODE_BACKGROUND + "', '" + FAST_MODE_AT_END + "' and '" + FAST_MODE_DEFER + "'." ); 257 } 258 259 Cleaner cleaner = new Cleaner( session, getLog(), isVerbose(), fastDir, fastMode ); 260 261 try 262 { 263 for ( File directoryItem : getDirectories() ) 264 { 265 if ( directoryItem != null ) 266 { 267 cleaner.delete( directoryItem, null, followSymLinks, failOnError, retryOnError ); 268 } 269 } 270 271 if ( filesets != null ) 272 { 273 for ( Fileset fileset : filesets ) 274 { 275 if ( fileset.getDirectory() == null ) 276 { 277 throw new MojoExecutionException( "Missing base directory for " + fileset ); 278 } 279 GlobSelector selector = new GlobSelector( fileset.getIncludes(), fileset.getExcludes(), 280 fileset.isUseDefaultExcludes() ); 281 cleaner.delete( fileset.getDirectory(), selector, fileset.isFollowSymlinks(), failOnError, 282 retryOnError ); 283 } 284 } 285 } 286 catch ( IOException e ) 287 { 288 throw new MojoExecutionException( "Failed to clean project: " + e.getMessage(), e ); 289 } 290 } 291 292 /** 293 * Indicates whether verbose output is enabled. 294 * 295 * @return <code>true</code> if verbose output is enabled, <code>false</code> otherwise. 296 */ 297 private boolean isVerbose() 298 { 299 return ( verbose != null ) ? verbose : getLog().isDebugEnabled(); 300 } 301 302 /** 303 * Gets the directories to clean (if any). The returned array may contain null entries. 304 * 305 * @return The directories to clean or an empty array if none, never <code>null</code>. 306 */ 307 private File[] getDirectories() 308 { 309 File[] directories; 310 if ( excludeDefaultDirectories ) 311 { 312 directories = new File[0]; 313 } 314 else 315 { 316 directories = new File[] { directory, outputDirectory, testOutputDirectory, reportDirectory }; 317 } 318 return directories; 319 } 320 321 }