Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MCLEAN-116] Use default Log interface #37

Merged
merged 2 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/main/java/org/apache/maven/plugins/clean/CleanMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ public class CleanMojo extends AbstractMojo {
* should usually reside on the same volume. The exact conditions are system dependant though, but if an atomic
* move is not supported, the standard deletion mechanism will be used.
*
* @since 3.2
* @see #fast
* @since 3.2
*/
@Parameter(property = "maven.clean.fastDir")
private File fastDir;
Expand All @@ -199,8 +199,8 @@ public class CleanMojo extends AbstractMojo {
* the actual file deletion should be started in the background when the session ends (this should only be used
* when maven is embedded in a long running process).
*
* @since 3.2
* @see #fast
* @since 3.2
*/
@Parameter(property = "maven.clean.fastMode", defaultValue = FAST_MODE_BACKGROUND)
private String fastMode;
Expand Down
160 changes: 75 additions & 85 deletions src/main/java/org/apache/maven/plugins/clean/Cleaner.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,65 +56,60 @@ class Cleaner {
*/
private final MavenSession session;

private final Logger logDebug;

private final Logger logInfo;

private final Logger logVerbose;

private final Logger logWarn;

private final File fastDir;

private final String fastMode;

private final boolean verbose;

private Log log;

/**
* Creates a new cleaner.
* @param log The logger to use, may be <code>null</code> to disable logging.
* @param verbose Whether to perform verbose logging.
* @param fastMode The fast deletion mode
*
* @param session The Maven session to be used.
* @param log The logger to use.
* @param verbose Whether to perform verbose logging.
* @param fastDir The explicit configured directory or to be deleted in fast mode.
* @param fastMode The fast deletion mode.
*/
Cleaner(MavenSession session, final Log log, boolean verbose, File fastDir, String fastMode) {
logDebug = (log == null || !log.isDebugEnabled()) ? null : log::debug;

logInfo = (log == null || !log.isInfoEnabled()) ? null : log::info;

logWarn = (log == null || !log.isWarnEnabled()) ? null : log::warn;

logVerbose = verbose ? logInfo : logDebug;

this.session = session;
// This can't be null as the Cleaner gets it from the CleanMojo which gets it from AbstractMojo class, where it
// is never null.
this.log = log;
this.fastDir = fastDir;
this.fastMode = fastMode;
this.verbose = verbose;
}

/**
* Deletes the specified directories and its contents.
*
* @param basedir The directory to delete, must not be <code>null</code>. Non-existing directories will be silently
* ignored.
* @param selector The selector used to determine what contents to delete, may be <code>null</code> to delete
* everything.
* @param basedir The directory to delete, must not be <code>null</code>. Non-existing directories will be silently
* ignored.
* @param selector The selector used to determine what contents to delete, may be <code>null</code> to delete
* everything.
* @param followSymlinks Whether to follow symlinks.
* @param failOnError Whether to abort with an exception in case a selected file/directory could not be deleted.
* @param retryOnError Whether to undertake additional delete attempts in case the first attempt failed.
* @param failOnError Whether to abort with an exception in case a selected file/directory could not be deleted.
* @param retryOnError Whether to undertake additional delete attempts in case the first attempt failed.
* @throws IOException If a file/directory could not be deleted and <code>failOnError</code> is <code>true</code>.
*/
public void delete(
File basedir, Selector selector, boolean followSymlinks, boolean failOnError, boolean retryOnError)
throws IOException {
if (!basedir.isDirectory()) {
if (!basedir.exists()) {
if (logDebug != null) {
logDebug.log("Skipping non-existing directory " + basedir);
if (log.isDebugEnabled()) {
log.debug("Skipping non-existing directory " + basedir);
}
return;
}
throw new IOException("Invalid base directory " + basedir);
}

if (logInfo != null) {
logInfo.log("Deleting " + basedir + (selector != null ? " (" + selector + ")" : ""));
if (log.isInfoEnabled()) {
log.info("Deleting " + basedir + (selector != null ? " (" + selector + ")" : ""));
}

File file = followSymlinks ? basedir : basedir.getCanonicalFile();
Expand Down Expand Up @@ -148,9 +143,8 @@ private boolean fastDelete(File baseDirFile) {
throw e;
}
} catch (IOException e) {
if (logDebug != null) {
// TODO: this Logger interface cannot log exceptions and needs refactoring
logDebug.log("Unable to fast delete directory: " + e);
if (log.isDebugEnabled()) {
log.debug("Unable to fast delete directory: ", e);
}
return false;
}
Expand All @@ -161,10 +155,11 @@ private boolean fastDelete(File baseDirFile) {
Files.createDirectories(fastDir);
}
} catch (IOException e) {
if (logDebug != null) {
// TODO: this Logger interface cannot log exceptions and needs refactoring
logDebug.log("Unable to fast delete directory as the path " + fastDir
+ " does not point to a directory or cannot be created: " + e);
if (log.isDebugEnabled()) {
log.debug(
"Unable to fast delete directory as the path " + fastDir
+ " does not point to a directory or cannot be created: ",
e);
}
return false;
}
Expand All @@ -180,9 +175,8 @@ private boolean fastDelete(File baseDirFile) {
BackgroundCleaner.delete(this, tmpDir.toFile(), fastMode);
return true;
} catch (IOException e) {
if (logDebug != null) {
// TODO: this Logger interface cannot log exceptions and needs refactoring
logDebug.log("Unable to fast delete directory: " + e);
if (log.isDebugEnabled()) {
log.debug("Unable to fast delete directory: ", e);
}
return false;
}
Expand All @@ -191,15 +185,15 @@ private boolean fastDelete(File baseDirFile) {
/**
* Deletes the specified file or directory.
*
* @param file The file/directory to delete, must not be <code>null</code>. If <code>followSymlinks</code> is
* <code>false</code>, it is assumed that the parent file is canonical.
* @param pathname The relative pathname of the file, using {@link File#separatorChar}, must not be
* <code>null</code>.
* @param selector The selector used to determine what contents to delete, may be <code>null</code> to delete
* everything.
* @param file The file/directory to delete, must not be <code>null</code>. If <code>followSymlinks</code> is
* <code>false</code>, it is assumed that the parent file is canonical.
* @param pathname The relative pathname of the file, using {@link File#separatorChar}, must not be
* <code>null</code>.
* @param selector The selector used to determine what contents to delete, may be <code>null</code> to delete
* everything.
* @param followSymlinks Whether to follow symlinks.
* @param failOnError Whether to abort with an exception in case a selected file/directory could not be deleted.
* @param retryOnError Whether to undertake additional delete attempts in case the first attempt failed.
* @param failOnError Whether to abort with an exception in case a selected file/directory could not be deleted.
* @param retryOnError Whether to undertake additional delete attempts in case the first attempt failed.
* @return The result of the cleaning, never <code>null</code>.
* @throws IOException If a file/directory could not be deleted and <code>failOnError</code> is <code>true</code>.
*/
Expand Down Expand Up @@ -229,24 +223,30 @@ private Result delete(
child, prefix + filename, selector, followSymlinks, failOnError, retryOnError));
}
}
} else if (logDebug != null) {
logDebug.log("Not recursing into symlink " + file);
} else if (log.isDebugEnabled()) {
log.debug("Not recursing into symlink " + file);
}
} else if (logDebug != null) {
logDebug.log("Not recursing into directory without included files " + file);
} else if (log.isDebugEnabled()) {
log.debug("Not recursing into directory without included files " + file);
}
}

if (!result.excluded && (selector == null || selector.isSelected(pathname))) {
if (logVerbose != null) {
if (isDirectory) {
logVerbose.log("Deleting directory " + file);
} else if (file.exists()) {
logVerbose.log("Deleting file " + file);
} else {
logVerbose.log("Deleting dangling symlink " + file);
}
String logmessage;
if (isDirectory) {
logmessage = "Deleting directory " + file;
} else if (file.exists()) {
logmessage = "Deleting file " + file;
} else {
logmessage = "Deleting dangling symlink " + file;
}

if (verbose && log.isInfoEnabled()) {
log.info(logmessage);
} else if (log.isDebugEnabled()) {
log.debug(logmessage);
}

result.failures += delete(file, failOnError, retryOnError);
} else {
result.excluded = true;
Expand All @@ -266,8 +266,8 @@ private boolean isSymbolicLink(Path path) throws IOException {
* Deletes the specified file, directory. If the path denotes a symlink, only the link is removed, its target is
* left untouched.
*
* @param file The file/directory to delete, must not be <code>null</code>.
* @param failOnError Whether to abort with an exception in case the file/directory could not be deleted.
* @param file The file/directory to delete, must not be <code>null</code>.
* @param failOnError Whether to abort with an exception in case the file/directory could not be deleted.
* @param retryOnError Whether to undertake additional delete attempts in case the first attempt failed.
* @return <code>0</code> if the file was deleted, <code>1</code> otherwise.
* @throws IOException If a file/directory could not be deleted and <code>failOnError</code> is <code>true</code>.
Expand Down Expand Up @@ -299,8 +299,8 @@ private int delete(File file, boolean failOnError, boolean retryOnError) throws
if (failOnError) {
throw new IOException("Failed to delete " + file);
} else {
if (logWarn != null) {
logWarn.log("Failed to delete " + file);
if (log.isWarnEnabled()) {
log.warn("Failed to delete " + file);
}
return 1;
}
Expand All @@ -322,27 +322,24 @@ public void update(Result result) {
}
}

private interface Logger {

void log(CharSequence message);
}

private static class BackgroundCleaner extends Thread {

private static final int NEW = 0;
private static final int RUNNING = 1;
private static final int STOPPED = 2;
private static BackgroundCleaner instance;

private final Deque<File> filesToDelete = new ArrayDeque<>();

private final Cleaner cleaner;

private final String fastMode;

private static final int NEW = 0;
private static final int RUNNING = 1;
private static final int STOPPED = 2;

private int status = NEW;

private BackgroundCleaner(Cleaner cleaner, File dir, String fastMode) {
super("mvn-background-cleaner");
this.cleaner = cleaner;
this.fastMode = fastMode;
init(cleaner.fastDir, dir);
}

public static void delete(Cleaner cleaner, File dir, String fastMode) {
synchronized (BackgroundCleaner.class) {
if (instance == null || !instance.doDelete(dir)) {
Expand All @@ -359,13 +356,6 @@ static void sessionEnd() {
}
}

private BackgroundCleaner(Cleaner cleaner, File dir, String fastMode) {
super("mvn-background-cleaner");
this.cleaner = cleaner;
this.fastMode = fastMode;
init(cleaner.fastDir, dir);
}

public void run() {
while (true) {
File basedir = pollNext();
Expand Down Expand Up @@ -450,8 +440,8 @@ synchronized void doSessionEnd() {
}
if (!FAST_MODE_DEFER.equals(fastMode)) {
try {
if (cleaner.logInfo != null) {
cleaner.logInfo.log("Waiting for background file deletion");
if (cleaner.log.isInfoEnabled()) {
cleaner.log.info("Waiting for background file deletion");
}
while (status != STOPPED) {
wait();
Expand Down
16 changes: 10 additions & 6 deletions src/test/java/org/apache/maven/plugins/clean/CleanMojoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.Collections;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.SystemStreamLog;
import org.apache.maven.plugin.testing.AbstractMojoTestCase;

import static org.apache.commons.io.FileUtils.copyDirectory;
Expand Down Expand Up @@ -273,6 +274,7 @@ public void testCleanLockedFileWithNoError() throws Exception {

/**
* Test the followLink option with windows junctions
*
* @throws Exception
*/
public void testFollowLinksWithWindowsJunction() throws Exception {
Expand All @@ -298,6 +300,7 @@ public void testFollowLinksWithWindowsJunction() throws Exception {

/**
* Test the followLink option with sym link
*
* @throws Exception
*/
public void testFollowLinksWithSymLinkOnPosix() throws Exception {
Expand All @@ -315,13 +318,9 @@ public void testFollowLinksWithSymLinkOnPosix() throws Exception {
});
}

@FunctionalInterface
interface LinkCreator {
void createLink(Path link, Path target) throws Exception;
}

private void testSymlink(LinkCreator linkCreator) throws Exception {
Cleaner cleaner = new Cleaner(null, null, false, null, null);
// We use the SystemStreamLog() as the AbstractMojo class, because from there the Log is always provided
Cleaner cleaner = new Cleaner(null, new SystemStreamLog(), false, null, null);
Path testDir = Paths.get("target/test-classes/unit/test-dir").toAbsolutePath();
Path dirWithLnk = testDir.resolve("dir");
Path orgDir = testDir.resolve("org-dir");
Expand Down Expand Up @@ -371,4 +370,9 @@ private boolean checkEmpty(String dir) {
File[] files = new File(dir).listFiles();
return files == null || files.length == 0;
}

@FunctionalInterface
interface LinkCreator {
void createLink(Path link, Path target) throws Exception;
}
}