如何从Eclipse插件运行ant,将输出发送到Eclipse控制台,并捕获构建结果(成功/失败)?

时间:2010-03-02 15:25:52

标签: eclipse ant console

在Eclipse插件中,我想运行一个Ant构建脚本。我还想通过在Eclipse控制台中显示Ant输出来向用户显示它。最后,我还想等待Ant构建完成,并捕获结果:构建成功还是失败?

我找到了三种从eclipse运行Ant脚本的方法:

  • 实例化org.eclipse.ant.core.AntRunner,致电某些设置者并致电run()run(IProgressMonitor)。结果是正常终止(表示成功),或者包含IStatus {表示失败的BuildException的CoreException,或者其他错误。但是,我没有在任何地方看到Ant输出。
  • 实例化org.eclipse.ant.core.AntRunner并调用run(Object),传递包含命令行参数的String[]。结果是正常终止(指示成功)或InvocationTargetException(指示失败),否则出现其他问题。看来,Ant输出被发送到Eclipse的stdout;它在Eclipse本身中不可见。
  • 调用DebugPlugin.getDefault().getLaunchManager(),然后调用getLaunchConfigurationType(IAntLaunchConfigurationConstants.ID_ANT_BUILDER_LAUNCH_CONFIGURATION_TYPE),然后在该集合属性"org.eclipse.ui.externaltools.ATTR_LOCATION"上调用构建文件名(并将属性DebugPlugin.ATTR_CAPTURE_OUTPUT更改为true),最后调用{ {1}}。 Ant输出显示在Eclipse控制台中,但我不知道如何在代码中捕获构建结果(成功/失败)。或者甚至如何等待终止发布。

有没有办法让两个控制台输出捕获结果?

2 个答案:

答案 0 :(得分:4)

编辑05/16/2016 @Lii提醒我,ILaunchConfigurationWorkingCopy#launch电话和附加IStreamListener之间的任何输出都将丢失。他为这个答案做出了贡献here

原始答案 我意识到这是一个老帖子,但我能够在我的一个插件中完全按照你想要的那样做。如果它在这一点上没有帮助你,也许它会帮助别人。我最初在3.2中做过这个,但它已针对3.6 API更改进行了更新...

// show the console
final IWorkbenchPage activePage = PlatformUI.getWorkbench()
        .getActiveWorkbenchWindow()
        .getActivePage();
activePage.showView(IConsoleConstants.ID_CONSOLE_VIEW);

// let launch manager handle ant script so output is directed to Console view
final ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
ILaunchConfigurationType type = manager.getLaunchConfigurationType(IAntLaunchConstants.ID_ANT_LAUNCH_CONFIGURATION_TYPE);
final ILaunchConfigurationWorkingCopy workingCopy = type.newInstance(null, [*** GIVE YOUR LAUNCHER A NAME ***]);
workingCopy.setAttribute(ILaunchManager.ATTR_PRIVATE, true);
workingCopy.setAttribute(IExternalToolConstants.ATTR_LOCATION, [*** PATH TO ANT SCRIPT HERE ***]);
final ILaunch launch = workingCopy.launch(ILaunchManager.RUN_MODE, null);
// make sure the build doesnt fail
final boolean[] buildSucceeded = new boolean[] { true };
((AntProcess) launch.getProcesses()[0]).getStreamsProxy()
        .getErrorStreamMonitor()
        .addListener(new IStreamListener() {
            @Override
            public void streamAppended(String text, IStreamMonitor monitor) {
                if (text.indexOf("BUILD FAILED") > -1) {
                    buildSucceeded[0] = false;
                }
            }
        });
// wait for the launch (ant build) to complete
manager.addLaunchListener(new ILaunchesListener2() {
    public void launchesTerminated(ILaunch[] launches) {
        boolean patchSuccess = false;
        try {
            if (!buildSucceeded[0]) {
                throw new Exception("Build FAILED!");
            }
            for (int i = 0; i < launches.length; i++) {
                if (launches[i].equals(launch)
                        && buildSucceeded[0]
                        && !((IProgressMonitor) launches[i].getProcesses()[0]).isCanceled()) {
                    [*** DO YOUR THING... ***]
                    break;
                }
            }
        } catch (Exception e) {
            [*** DO YOUR THING... ***]
        } finally {
            // get rid of this listener
            manager.removeLaunchListener(this);
            [*** DO YOUR THING... ***]
        }
    }

    public void launchesAdded(ILaunch[] launches) {
    }

    public void launchesChanged(ILaunch[] launches) {
    }

    public void launchesRemoved(ILaunch[] launches) {
    }
});

答案 1 :(得分:1)

我想向happytime harry's answer添加一件事。

有时,第一次写入流发生在添加流侦听器之前。然后,永远不会为侦听器调用streamAppended,因此输出会丢失。

例如,见bug。我认为快乐时候哈里的解决方案可能有这个问题。我自己在ILaunchListener.launchChanged注册了我的流监听器,这发生了4/5次。

如果想确保从流中获取所有输出,那么IStreamMonitor.getContents方法可用于获取在添加侦听器之前发生的输出。

以下是对处理此问题的实用程序方法的尝试。它基于ProcessConsole中的代码。

/**
 * Adds listener to monitor, and calls listener with any content monitor already has.
 * NOTE: This methods synchronises on monitor while listener is called. Listener may
 * not wait on any thread that waits for monitors monitor, what would result in dead-lock.
 */
public static void addAndNotifyStreamListener(IStreamMonitor monitor, IStreamListener listener) {
    // Synchronise on monitor to prevent writes to stream while we are adding listener.
    // It's weird to synchronise on monitor because that's a shared object, but that's 
    // what ProcessConsole does.  
    synchronized (monitor) {
        String contents = monitor.getContents();
        if (!contents.isEmpty()) {
            // Call to unknown code while synchronising on monitor. This is dead-lock prone!
            // Listener must not wait for other threads that are waiting in line to 
            // synchronise on monitor.
            listener.streamAppended(contents, monitor);
        }
        monitor.addListener(listener);
    }
}

PS:ProcessConsole.java中有一些奇怪的事情发生了。为什么内容缓冲从ProcessConsole.StreamListener构造函数切换?!如果ProcessConsole.StreamListener在此之前运行,则此解决方案可能无效。