Java 未能在ANT中编译的类的列表

Java 未能在ANT中编译的类的列表,java,compiler-construction,ant,Java,Compiler Construction,Ant,我有一个小问题要问你们大家。 我有几个build.xml文件可以编译数百个类,每当我运行build时,都会在服务器上保存一个日志文件 现在到目前为止还不错,例如,如果有什么失败,我可以通过日志文件。。。但有时我会遇到很多错误,因此扫描日志文件是很痛苦的 我想知道是否可以对ant(即使在运行时)或通过 javac任务,如果可以给出未能编译的类的列表 (我指的不是所有错误堆栈,而是失败类的列表)为什么不从日志中删除文件名 一个简单的例子: grep javac build.log | grep ja

我有一个小问题要问你们大家。 我有几个build.xml文件可以编译数百个类,每当我运行build时,都会在服务器上保存一个日志文件

现在到目前为止还不错,例如,如果有什么失败,我可以通过日志文件。。。但有时我会遇到很多错误,因此扫描日志文件是很痛苦的

我想知道是否可以对ant(即使在运行时)或通过 javac任务,如果可以给出未能编译的类的列表
(我指的不是所有错误堆栈,而是失败类的列表)

为什么不从日志中删除文件名

一个简单的例子:

grep javac build.log | grep java:
---编辑以包含具体示例---

这个例子应该让您在日志记录方面领先一步。请记住,在调用ant之前,必须将其添加到类路径中。如果可能,只将其添加到ant副本使用的类路径中,但将普通ant调用包装在设置类路径然后调用ant的脚本中

然后像这样用这个记录器运行ant

ant -logger com.edwinbuck.JavacFileLogger
下面的代码将生成未编译文件的列表。它做出了一些假设(有些是好的,有些可能需要改进)

  • 它假定您必须在“javac”任务中才能编译java文件
  • 它假定所有非编译文件至少发出一条格式为“/some/path/to/the/file.java::description of failure”的消息
  • 它假定没有其他javac消息包含字符序列“.javac:”
  • 您可能需要修改以下代码以打开一个文件并对其进行写入,这是您认为合适的

    package com.edwinbuck;
    
    import java.io.PrintStream;
    import java.util.HashSet;
    import java.util.Set;
    
    import org.apache.tools.ant.BuildLogger;
    import org.apache.tools.ant.BuildEvent;
    import org.apache.tools.ant.util.StringUtils;
    
    public class JavacFileLogger implements BuildLogger {
    
      protected PrintStream out;
    
      protected PrintStream err;
    
      protected static final String eol = StringUtils.LINE_SEP;
    
      private Set<String> errorFiles = new HashSet<String>();
    
      private boolean ignoringMessages = true;
    
      public void buildStarted(BuildEvent event) {
      }
    
      public void buildFinished(BuildEvent event) {
      }
    
      public void targetStarted(BuildEvent event) {
      }
    
      public void targetFinished(BuildEvent event) {
      }
    
      public void taskStarted(BuildEvent event) {
        if (event.getTask().getTaskName().equals("javac")) {
          ignoringMessages = false;
        }
      }
    
      public void taskFinished(BuildEvent event) {
        if (event.getTask().getTaskName().equals("javac")) {
          ignoringMessages = true;
          // flush the set of files with errors
          for (String filename : errorFiles) {
            out.print(filename);
            out.print(eol);
          }
        }
      }
    
      public void messageLogged(BuildEvent event) {
        // we don't care about non-javac messages
        if (!ignoringMessages) {
          // error messages have a distinct ".java:" in the line containing the file name.
          if (event.getMessage().contains(".java:")) {
            // just add the (string) name to the set to condense multiple reported errors in the same file
            errorFiles.add(event.getMessage().substring(0, event.getMessage().indexOf(":")));
          }
        }
      }
    
      public void setErrorPrintStream(PrintStream err) {
        this.err = err;
      }
    
      public void setEmacsMode(boolean emacsMode) {
      }
    
      public void setOutputPrintStream(PrintStream output) {
        this.out = output;
      }
    
      public void setMessageOutputLevel(int level) {
        // this logger ignores message levels
      }
    
    }
    
    package com.edwinbuck;
    导入java.io.PrintStream;
    导入java.util.HashSet;
    导入java.util.Set;
    导入org.apache.tools.ant.BuildLogger;
    导入org.apache.tools.ant.BuildEvent;
    导入org.apache.tools.ant.util.StringUtils;
    公共类JavacFileLogger实现BuildLogger{
    受保护的打印流输出;
    受保护的打印流错误;
    受保护的静态最终字符串下线=StringUtils.LINE\u SEP;
    private Set errorFiles=new HashSet();
    private boolean ignoringMessages=true;
    public void buildStarted(BuildEvent事件){
    }
    public void buildFinished(BuildEvent事件){
    }
    public void targetStarted(BuildEvent事件){
    }
    public void targetFinished(BuildEvent事件){
    }
    已启动公共void任务(BuildEvent事件){
    if(event.getTask().getTaskName().equals(“javac”)){
    ignoringMessages=false;
    }
    }
    public void任务已完成(BuildEvent事件){
    if(event.getTask().getTaskName().equals(“javac”)){
    ignoringMessages=true;
    //刷新有错误的文件集
    用于(字符串文件名:errorFiles){
    out.print(文件名);
    打印输出(eol);
    }
    }
    }
    public void messageLogged(BuildEvent事件){
    //我们不关心非javac消息
    如果(!ignoringMessages){
    //错误消息在包含文件名的行中有一个独特的“.java:”。
    if(event.getMessage()包含(“.java:”){
    //只需将(字符串)名称添加到集合中,即可压缩同一文件中报告的多个错误
    errorFiles.add(event.getMessage().substring(0,event.getMessage().indexOf(“:”));
    }
    }
    }
    public void setErrorPrintStream(PrintStream错误){
    this.err=err;
    }
    public void setEmacsMode(布尔emacsMode){
    }
    public void setOutputPrintStream(PrintStream输出){
    this.out=输出;
    }
    public void setMessageOutputLevel(int级别){
    //此记录器忽略消息级别
    }
    }
    
    ---原文如下---

    根据您想要做什么,您可能需要一个定制的Ant侦听器或记录器

    如果您想要一个只提到失败类的日志文件,您可以将自己的记录器添加到ant中,等待
    javac
    任务,然后捕获日志事件,解析出失败的类名,并将它们附加到文件中

    如果您想在Ant内部获得这些信息,可以添加一个监听器,该监听器基本上收集必要的数据,并以某种方式使其可供Ant使用(可能通过定义属性)


    查看本页了解一些想法,并了解如何侦听特定任务(本例中为javac)以自动运行不同的任务(即使build.xml文件中未指定该任务).

    尝试过-太痛苦了,因为经常会在同一个文件中出现整个列表或多个消息错误。@7dr3am7:正如您所见,对编译器的输出有许多假设。脚本使更容易更改。。我这样做(和答案相同),当然,使用更多的管道使它成为脚本可以做到的唯一列表,但我更喜欢一个侦听器/记录器(参见上面的答案),这样我可以在运行时调用它。谢谢,我会尽快让您知道。好吧,两者都可以,我只是想知道哪一个是最快实现的。我在读几篇文章,我有一个问题。。记录器如何知道错误和简单输出之间的区别?最重要的是,我如何解析它?您必须确定它是错误还是简单的输出。这通常通过检查BuildEvent优先级和在BuildEvent消息中搜索关键字的组合来完成。通常,您可以找到一个字符串或子字符串来帮助您查找BuildEvent,我认为它可能类似于“error”或“compile failed”。至于解析它,您需要找出要从字符串中“提取”的模式,如第四个单词、第一组括号之间的东西等。如果我有时间,我将发布一个示例。@7dr3am7,我提供了一个记录器的工作示例,该记录器经过调优以收集未编译文件的文件名。它提出了许多假设,当您将代码与您的需求对齐时,您可能必须对这些假设进行调整。好好享受,哇!谢谢@Edwin:$我想自己得到答案,但那太好了