make/langtools/intellij/src/idea/LangtoolsIdeaAntLogger.java
branchihse-runtestprebuilt-branch
changeset 56894 da01b7339c5e
parent 56875 395b1ac9cdda
parent 51676 5a1be00ea4f6
child 56895 3289d2b19b94
--- a/make/langtools/intellij/src/idea/LangtoolsIdeaAntLogger.java	Wed Aug 29 09:45:58 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,364 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package idea;
-
-import org.apache.tools.ant.BuildEvent;
-import org.apache.tools.ant.BuildListener;
-import org.apache.tools.ant.DefaultLogger;
-import org.apache.tools.ant.Project;
-
-import java.util.EnumSet;
-import java.util.Stack;
-
-import static org.apache.tools.ant.Project.*;
-
-/**
- * This class is used to wrap the IntelliJ ant logger in order to provide more meaningful
- * output when building langtools. The basic ant output in IntelliJ can be quite cumbersome to
- * work with, as it provides two separate views: (i) a tree view, which is good to display build task
- * in a hierarchical fashion as they are processed; and a (ii) plain text view, which gives you
- * the full ant output. The main problem is that javac-related messages are buried into the
- * ant output (which is made very verbose by IntelliJ in order to support the tree view). It is
- * not easy to figure out which node to expand in order to see the error message; switching
- * to plain text doesn't help either, as now the output is totally flat.
- *
- * This logger class removes a lot of verbosity from the IntelliJ ant logger by not propagating
- * all the events to the IntelliJ's logger. In addition, certain events are handled in a custom
- * fashion, to generate better output during the build.
- */
-public final class LangtoolsIdeaAntLogger extends DefaultLogger {
-
-    /**
-     * This is just a way to pass in customized binary string predicates;
-     *
-     * TODO: replace with @code{BiPredicate<String, String>} and method reference when moving to 8
-     */
-    enum StringBinaryPredicate {
-        CONTAINS() {
-            @Override
-            boolean apply(String s1, String s2) {
-                return s1.contains(s2);
-            }
-        },
-        STARTS_WITH {
-            @Override
-            boolean apply(String s1, String s2) {
-                return s1.startsWith(s2);
-            }
-        };
-
-        abstract boolean apply(String s1, String s2);
-    }
-
-    /**
-     * Various kinds of ant messages that we shall intercept
-     */
-    enum MessageKind {
-
-        /** a javac error */
-        JAVAC_ERROR(StringBinaryPredicate.CONTAINS, MSG_ERR, "error:", "compiler.err"),
-        /** a javac warning */
-        JAVAC_WARNING(StringBinaryPredicate.CONTAINS, MSG_WARN, "warning:", "compiler.warn"),
-        /** a javac note */
-        JAVAC_NOTE(StringBinaryPredicate.CONTAINS, MSG_INFO, "note:", "compiler.note"),
-        /** a javac raw error (these typically come from a build misconfiguration - such as a bad javac flag) */
-        JAVAC_RAW_ERROR(StringBinaryPredicate.STARTS_WITH, MSG_INFO, "javac: "),
-        /** continuation of some javac error message */
-        JAVAC_NESTED_DIAG(StringBinaryPredicate.STARTS_WITH, MSG_INFO, "  "),
-        /** a javac crash */
-        JAVAC_CRASH(StringBinaryPredicate.STARTS_WITH, MSG_ERR, "An exception has occurred in the compiler"),
-        /** jtreg test success */
-        JTREG_TEST_PASSED(StringBinaryPredicate.STARTS_WITH, MSG_INFO, "Passed: "),
-        /** jtreg test failure */
-        JTREG_TEST_FAILED(StringBinaryPredicate.STARTS_WITH, MSG_ERR, "FAILED: "),
-        /** jtreg test error */
-        JTREG_TEST_ERROR(StringBinaryPredicate.STARTS_WITH, MSG_ERR, "Error: "),
-        /** jtreg report */
-        JTREG_TEST_REPORT(StringBinaryPredicate.STARTS_WITH, MSG_INFO, "Report written");
-
-        StringBinaryPredicate sbp;
-        int priority;
-        String[] keys;
-
-        MessageKind(StringBinaryPredicate sbp, int priority, String... keys) {
-            this.sbp = sbp;
-            this.priority = priority;
-            this.keys = keys;
-        }
-
-        /**
-         * Does a given message string matches this kind?
-         */
-        boolean matches(String s) {
-            for (String key : keys) {
-                if (sbp.apply(s, key)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
-    /**
-     * This enum is used to represent the list of tasks we need to keep track of during logging.
-     */
-    enum Task {
-        /** exec task - invoked during compilation */
-        JAVAC("exec", MessageKind.JAVAC_ERROR, MessageKind.JAVAC_WARNING, MessageKind.JAVAC_NOTE,
-                       MessageKind.JAVAC_RAW_ERROR, MessageKind.JAVAC_NESTED_DIAG, MessageKind.JAVAC_CRASH),
-        /** jtreg task - invoked during test execution */
-        JTREG("jtreg", MessageKind.JTREG_TEST_PASSED, MessageKind.JTREG_TEST_FAILED, MessageKind.JTREG_TEST_ERROR, MessageKind.JTREG_TEST_REPORT),
-        /** initial synthetic task when the logger is created */
-        ROOT("") {
-            @Override
-            boolean matches(String s) {
-                return false;
-            }
-        },
-        /** synthetic task catching any other tasks not in this list */
-        ANY("") {
-            @Override
-            boolean matches(String s) {
-                return true;
-            }
-        };
-
-        String taskName;
-        MessageKind[] msgs;
-
-        Task(String taskName, MessageKind... msgs) {
-            this.taskName = taskName;
-            this.msgs = msgs;
-        }
-
-        boolean matches(String s) {
-            return s.equals(taskName);
-        }
-    }
-
-    /**
-     * This enum is used to represent the list of targets we need to keep track of during logging.
-     * A regular expression is used to match a given target name.
-     */
-    enum Target {
-        /** jtreg target - executed when launching tests */
-        JTREG("jtreg") {
-            @Override
-            String getDisplayMessage(BuildEvent e) {
-                return "Running jtreg tests: " + e.getProject().getProperty("jtreg.tests");
-            }
-        },
-        /** build bootstrap tool target - executed when bootstrapping javac */
-        BUILD_BOOTSTRAP_JAVAC("build-bootstrap-javac-classes") {
-            @Override
-            String getDisplayMessage(BuildEvent e) {
-                return "Building bootstrap javac...";
-            }
-        },
-        /** build classes target - executed when building classes of given tool */
-        BUILD_ALL_CLASSES("build-all-classes") {
-            @Override
-            String getDisplayMessage(BuildEvent e) {
-                return "Building all classes...";
-            }
-        },
-        /** synthetic target catching any other target not in this list */
-        ANY("") {
-            @Override
-            String getDisplayMessage(BuildEvent e) {
-                return "Executing Ant target(s): " + e.getProject().getProperty("ant.project.invoked-targets");
-            }
-            @Override
-            boolean matches(String msg) {
-                return true;
-            }
-        };
-
-        String targetName;
-
-        Target(String targetName) {
-            this.targetName = targetName;
-        }
-
-        boolean matches(String msg) {
-            return msg.equals(targetName);
-        }
-
-        abstract String getDisplayMessage(BuildEvent e);
-    }
-
-    /**
-     * A custom build event used to represent status changes which should be notified inside
-     * Intellij
-     */
-    static class StatusEvent extends BuildEvent {
-
-        /** the target to which the status update refers */
-        Target target;
-
-        StatusEvent(BuildEvent e, Target target) {
-            super(new StatusTask(e, target.getDisplayMessage(e)));
-            this.target = target;
-            setMessage(getTask().getTaskName(), 2);
-        }
-
-        /**
-         * A custom task used to channel info regarding a status change
-         */
-        static class StatusTask extends org.apache.tools.ant.Task {
-            StatusTask(BuildEvent event, String msg) {
-                setProject(event.getProject());
-                setOwningTarget(event.getTarget());
-                setTaskName(msg);
-            }
-        }
-    }
-
-    /** wrapped ant logger (IntelliJ's own logger) */
-    DefaultLogger logger;
-
-    /** flag - is this the first target we encounter? */
-    boolean firstTarget = true;
-
-    /** flag - should subsequenet failures be suppressed ? */
-    boolean suppressTaskFailures = false;
-
-    /** flag - have we ran into a javac crash ? */
-    boolean crashFound = false;
-
-    /** stack of status changes associated with pending targets */
-    Stack<StatusEvent> statusEvents = new Stack<>();
-
-    /** stack of pending tasks */
-    Stack<Task> tasks = new Stack<>();
-
-    public LangtoolsIdeaAntLogger(Project project) {
-        for (Object o : project.getBuildListeners()) {
-            if (o instanceof DefaultLogger) {
-                this.logger = (DefaultLogger)o;
-                project.removeBuildListener((BuildListener)o);
-                project.addBuildListener(this);
-            }
-        }
-        logger.setMessageOutputLevel(3);
-        tasks.push(Task.ROOT);
-    }
-
-    @Override
-    public void buildStarted(BuildEvent event) {
-        //do nothing
-    }
-
-    @Override
-    public void buildFinished(BuildEvent event) {
-        //do nothing
-    }
-
-    @Override
-    public void targetStarted(BuildEvent event) {
-        EnumSet<Target> statusKinds = firstTarget ?
-                EnumSet.allOf(Target.class) :
-                EnumSet.complementOf(EnumSet.of(Target.ANY));
-
-        String targetName = event.getTarget().getName();
-
-        for (Target statusKind : statusKinds) {
-            if (statusKind.matches(targetName)) {
-                StatusEvent statusEvent = new StatusEvent(event, statusKind);
-                statusEvents.push(statusEvent);
-                logger.taskStarted(statusEvent);
-                firstTarget = false;
-                return;
-            }
-        }
-    }
-
-    @Override
-    public void targetFinished(BuildEvent event) {
-        if (!statusEvents.isEmpty()) {
-            StatusEvent lastEvent = statusEvents.pop();
-            if (lastEvent.target.matches(event.getTarget().getName())) {
-                logger.taskFinished(lastEvent);
-            }
-        }
-    }
-
-    @Override
-    public void taskStarted(BuildEvent event) {
-        String taskName = event.getTask().getTaskName();
-        for (Task task : Task.values()) {
-            if (task.matches(taskName)) {
-                tasks.push(task);
-                return;
-            }
-        }
-    }
-
-    @Override
-    public void taskFinished(BuildEvent event) {
-        if (tasks.peek() == Task.ROOT) {
-            //we need to 'close' the root task to get nicer output
-            logger.taskFinished(event);
-        } else if (!suppressTaskFailures && event.getException() != null) {
-            //the first (innermost) task failure should always be logged
-            event.setMessage(event.getException().toString(), 0);
-            event.setException(null);
-            //note: we turn this into a plain message to avoid stack trace being logged by Idea
-            logger.messageLogged(event);
-            suppressTaskFailures = true;
-        }
-        tasks.pop();
-    }
-
-    @Override
-    public void messageLogged(BuildEvent event) {
-        String msg = event.getMessage();
-
-        boolean processed = false;
-
-        if (!tasks.isEmpty()) {
-            Task task = tasks.peek();
-            for (MessageKind messageKind : task.msgs) {
-                if (messageKind.matches(msg)) {
-                    event.setMessage(msg, messageKind.priority);
-                    processed = true;
-                    if (messageKind == MessageKind.JAVAC_CRASH) {
-                        crashFound = true;
-                    }
-                    break;
-                }
-            }
-        }
-
-        if (event.getPriority() == MSG_ERR || crashFound) {
-            //we log errors regardless of owning task
-            logger.messageLogged(event);
-            suppressTaskFailures = true;
-        } else if (processed) {
-            logger.messageLogged(event);
-        }
-    }
-}