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