/******************************************************************************* * Copyright (c) 2017 Rogue Wave Software Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Michał Niewrzał (Rogue Wave Software Inc.) - initial implementation *******************************************************************************/ package org.eclipse.php.composer.ui.terminal; import java.io.*; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.ExecuteException; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.php.composer.core.ComposerPlugin; import org.eclipse.php.composer.core.launch.ScriptLauncher; import org.eclipse.php.composer.core.launch.ScriptNotFoundException; import org.eclipse.php.composer.core.launch.environment.Environment; import org.eclipse.php.composer.core.launch.execution.ExecutionResponseListener; import org.eclipse.php.composer.core.log.Logger; import org.eclipse.php.internal.debug.core.launching.PHPLaunchUtilities; import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService.Done; import org.eclipse.tm.terminal.view.core.interfaces.ITerminalServiceOutputStreamMonitorListener; import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; import org.eclipse.ui.console.ConsolePlugin; import org.eclipse.ui.console.IConsole; import org.eclipse.ui.console.IConsoleManager; public class ComposerLauncher extends ScriptLauncher { private final static String WINDOWS_END_OF_LINE = "\r\n"; //$NON-NLS-1$ private Environment environment; private IProject project; private TerminalConsole terminalConsole; public ComposerLauncher(Environment environment, IProject project) throws ScriptNotFoundException { super(environment, project); this.environment = environment; this.project = project; } @Override public void launch(String argument, String... params) throws ExecuteException, IOException, InterruptedException { CommandLine cmd = environment.getCommand(); cmd.addArgument(argument); cmd.addArguments(params); Map<String, String> env = new HashMap<String, String>(System.getenv()); PHPLaunchUtilities.appendExecutableToPathEnv(env, new File(cmd.getExecutable()).getParentFile()); PHPLaunchUtilities.appendLibrarySearchPathEnv(env, new File(cmd.getExecutable()).getParentFile()); Map<String, Object> properties = new HashMap<String, Object>(); List<String> envs = new ArrayList<>(env.size()); for (String key : env.keySet()) { envs.add(key + '=' + env.get(key)); } properties.put(ITerminalsConnectorConstants.PROP_PROCESS_ENVIRONMENT, envs.toArray(new String[envs.size()])); properties.put(ITerminalsConnectorConstants.PROP_PROCESS_MERGE_ENVIRONMENT, true); ITerminalServiceOutputStreamMonitorListener[] outListeners = new ITerminalServiceOutputStreamMonitorListener[] { new ITerminalServiceOutputStreamMonitorListener() { @Override public void onContentReadFromStream(byte[] byteBuffer, int bytesRead) { for (ExecutionResponseListener handler : getListeners()) { handler.executionMessage(new String(byteBuffer, 0, bytesRead)); } } } }; properties.put(ITerminalsConnectorConstants.PROP_STDOUT_LISTENERS, outListeners); // workaround for colored output on Windows if (Platform.OS_WIN32.equals(Platform.getOS())) { StringBuilder builder = new StringBuilder(); builder.append("@echo off").append(WINDOWS_END_OF_LINE); // $NON-NLS-1$ // 65001 - UTF-8 builder.append("chcp 65001").append(WINDOWS_END_OF_LINE); // $NON-NLS-1$ builder.append("cls").append(WINDOWS_END_OF_LINE); //$NON-NLS-1$ builder.append(escapePath(cmd.getExecutable())).append(' '); for (String arg : cmd.getArguments()) { builder.append(arg).append(' '); } File file = File.createTempFile("composer_windows_", ".bat"); // $NON-NLS-1$ //$NON-NLS-2$ file.deleteOnExit(); try (BufferedWriter writer = new BufferedWriter(new FileWriter(file));) { writer.write(builder.toString()); } catch (FileNotFoundException ex) { ComposerPlugin.logException(ex); } properties.put(ITerminalsConnectorConstants.PROP_PROCESS_PATH, "cmd"); //$NON-NLS-1$ String args = "/C " + file.getAbsolutePath(); //$NON-NLS-1$ properties.put(ITerminalsConnectorConstants.PROP_PROCESS_ARGS, args); } else { properties.put(ITerminalsConnectorConstants.PROP_PROCESS_PATH, escapePath(cmd.getExecutable())); StringBuilder builder = new StringBuilder(); for (String arg : cmd.getArguments()) { builder.append(arg + ' '); } properties.put(ITerminalsConnectorConstants.PROP_PROCESS_ARGS, builder.toString()); } Logger.debug("Setting executor working directory to " + project.getLocation().toOSString()); //$NON-NLS-1$ properties.put(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR, project.getLocation().toOSString()); String title = MessageFormat.format(Messages.ComposerConsoleManager_ConsoleLabel, Messages.ComposerConsoleManager_ConsoleName, project.getName()); IConsoleManager consoleManager = ConsolePlugin.getDefault().getConsoleManager(); final CountDownLatch latch = new CountDownLatch(1); terminalConsole = new TerminalConsole(title, 0, properties, new Done() { @Override public void done(IStatus status) { latch.countDown(); } }); for (ExecutionResponseListener handler : getListeners()) { handler.executionStarted(); } consoleManager.addConsoles(new IConsole[] { terminalConsole }); consoleManager.showConsoleView(terminalConsole); latch.await(); for (ExecutionResponseListener handler : getListeners()) { handler.executionFinished("", 0); //$NON-NLS-1$ } } @Override public void abort() { terminalConsole.getTerminalConnector().disconnect(); } private String escapePath(String path) { return '\"' + path.replace("\\", "\\\\") + '\"'; //$NON-NLS-1$ //$NON-NLS-2$ } }