Как запустить ant из плагина Eclipse, отправить вывод на консоль Eclipse и зафиксировать результат сборки (успех / сбой)? - PullRequest
3 голосов
/ 02 марта 2010

В плагине Eclipse я бы хотел запустить скрипт сборки Ant. Я также хочу отобразить вывод Ant пользователю, отображая его в консоли Eclipse. Наконец, я также хочу дождаться завершения сборки Ant и зафиксировать результат: сборка прошла успешно или не удалась?

Я нашел три способа запуска сценария Ant из eclipse:

  • Создайте org.eclipse.ant.core.AntRunner, вызовите некоторые сеттеры и наберите run() или run(IProgressMonitor). Результатом является либо обычное завершение (указывающее на успешность), либо исключение CoreException с IStatus, содержащее BuildException (указывающее на сбой), либо что-то еще пошло не так. Однако я нигде не вижу вывод Ant.
  • Создает org.eclipse.ant.core.AntRunner и вызывает run(Object), передавая String[], содержащий аргументы командной строки. Результатом является либо нормальное завершение (указание на успех), либо InvocationTargetException (указание на сбой), либо что-то еще пошло не так. Похоже, вывод Ant отправляется на стандартный вывод Eclipse; это не видно в самом Eclipse.
  • Позвоните DebugPlugin.getDefault().getLaunchManager(), затем на этот вызов getLaunchConfigurationType(IAntLaunchConfigurationConstants.ID_ANT_BUILDER_LAUNCH_CONFIGURATION_TYPE), затем на этот набор атрибутов "org.eclipse.ui.externaltools.ATTR_LOCATION" укажите имя файла сборки (и атрибут DebugPlugin.ATTR_CAPTURE_OUTPUT в true) и, наконец, вызовите launch(). Выходные данные Ant отображаются в консоли Eclipse, но я не знаю, как зафиксировать результат сборки (успех / сбой) в моем коде. Или как дождаться окончания запуска хотя бы.

Есть ли способ заставить и консольный вывод и захватить результат?

Ответы [ 2 ]

4 голосов
/ 18 октября 2010

Изменить 05/16/2016 @Lii предупредил меня о том, что любой вывод между вызовом ILaunchConfigurationWorkingCopy#launch и добавлением IStreamListener будет потерян. Он сделал вклад в этот ответ здесь .

Оригинальный ответ Я понимаю, что это старый пост, но я смог сделать именно то, что вы хотите в одном из моих плагинов. Если это не поможет вам, возможно, это поможет кому-то еще. Первоначально я делал это в 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 голос
/ 16 мая 2016

Я бы хотел добавить одну вещь к счастливому ответу Гарри .

Иногда первая запись в поток происходит перед добавлением прослушивателя потока. Тогда streamAppended на слушателе никогда не вызывается для этих записей, поэтому вывод теряется.

См., Например, эту ошибку . Я думаю, что у счастливого времени у Гарри может быть эта проблема. Я сам зарегистрировал свой потоковый слушатель в 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 работает до этого, возможно, это решение не работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...