From 3332117fe3af5f66e2b453e9849a935626d2a9fc Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 9 Aug 2018 20:54:14 +0200 Subject: [PATCH] [core] Add support for Gradle's AntLoggingAdapter, default fallback loglevel is WARN Fixes #1288 --- docs/pages/release_notes.md | 1 + .../pmd/util/log/AntLogHandler.java | 62 +++++++++++++++++-- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 1237f0a89e..7cce15730e 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -30,6 +30,7 @@ This is a minor release. * core * [#1191](https://github.com/pmd/pmd/issues/1191): \[core] Test Framework: Sort violations by line/column + * [#1288](https://github.com/pmd/pmd/issues/1288): \[core] No supported build listeners found with Gradle * java-bestpractices * [#1267](https://github.com/pmd/pmd/pull/1267): \[java] MissingOverrideRule: Avoid NoClassDefFoundError with incomplete classpath * java-codestyle diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/AntLogHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/AntLogHandler.java index 0eb3162aa4..26c29b702a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/AntLogHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/AntLogHandler.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.util.log; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.logging.Formatter; import java.util.logging.Handler; import java.util.logging.Level; @@ -27,9 +28,17 @@ import org.apache.tools.ant.taskdefs.RecorderEntry; public class AntLogHandler extends Handler { private Project project; + private static final Level DEFAULT_LEVEL = Level.WARNING; + private static final Formatter FORMATTER = new PmdLogFormatter(); + + // Maps from ant's Project.MSG_* to java.util.logging.Level private static final Level[] LOG_LEVELS = { - Level.SEVERE, Level.WARNING, Level.INFO, Level.CONFIG, Level.FINEST, + Level.SEVERE, // Project.MSG_ERR=0 + Level.WARNING, // Project.MSG_WARN=1 + Level.INFO, // Project.MSG_INFO=2 + Level.CONFIG, // Project.MSG_VERBOSE=3 + Level.FINEST, // Project.MSG_DEBUG=4 }; public AntLogHandler(Project project) { @@ -46,9 +55,15 @@ public class AntLogHandler extends Handler { declaredField = XmlLogger.class.getDeclaredField("msgOutputLevel"); } else if (l instanceof RecorderEntry) { declaredField = RecorderEntry.class.getDeclaredField("loglevel"); + } else if (l.getClass().getName().equals("org.gradle.api.internal.project.ant.AntLoggingAdapter")) { + return determineGradleLogLevel(l); } else { try { declaredField = l.getClass().getDeclaredField("logLevel"); + if (declaredField.getType() != Integer.class && declaredField.getType() != int.class) { + declaredField = null; + project.log("Unsupported build listener: " + l.getClass(), Project.MSG_DEBUG); + } } catch (final NoSuchFieldException e) { project.log("Unsupported build listener: " + l.getClass(), Project.MSG_DEBUG); } @@ -58,15 +73,16 @@ public class AntLogHandler extends Handler { declaredField.setAccessible(true); return LOG_LEVELS[declaredField.getInt(l)]; } - } catch (final NoSuchFieldException | IllegalArgumentException | IllegalAccessException ignored) { + + } catch (final ReflectiveOperationException ignored) { // Just ignore it } } project.log("Could not determine ant log level, no supported build listeners found. " - + "Log level is set to FINEST", Project.MSG_WARN); + + "Log level is set to " + DEFAULT_LEVEL, Project.MSG_WARN); - return Level.FINEST; + return DEFAULT_LEVEL; } @Override @@ -110,4 +126,42 @@ public class AntLogHandler extends Handler { public void flush() { // nothing to do } + + private Level determineGradleLogLevel(BuildListener l) { + try { + project.log("Detected gradle AntLoggingAdapter", Project.MSG_DEBUG); + Field loggerField = l.getClass().getDeclaredField("logger"); + loggerField.setAccessible(true); + // org.gradle.internal.logging.slf4j.OutputEventListenerBackedLogger + Object logger = loggerField.get(l); + + Class gradleLogLevel = l.getClass().getClassLoader().loadClass("org.gradle.api.logging.LogLevel"); + + Method isLevelAtMostMethod = logger.getClass().getDeclaredMethod("isLevelAtMost", gradleLogLevel); + isLevelAtMostMethod.setAccessible(true); + + Object[] logLevels = gradleLogLevel.getEnumConstants(); + // the log levels in gradle are declared in the order DEBUG, INFO, LIFECYCLE, WARN, QUIET, ERROR + Level[] mapping = new Level[] { + Level.FINEST, // DEBUG + Level.CONFIG, // INFO + Level.INFO, // LIFECYCLE + Level.WARNING, // WARN + Level.SEVERE, // QUIET + Level.SEVERE, // ERROR + }; + + for (int i = 0; i < Math.min(logLevels.length, mapping.length); i++) { + boolean enabled = (boolean) isLevelAtMostMethod.invoke(logger, logLevels[i]); + if (enabled) { + project.log("Current log level: " + logLevels[i] + " -> " + mapping[i], Project.MSG_DEBUG); + return mapping[i]; + } + } + } catch (ReflectiveOperationException ignored) { + // ignored + } + project.log("Could not determine log level, falling back to default: " + DEFAULT_LEVEL, Project.MSG_WARN); + return DEFAULT_LEVEL; + } }