1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 06:02:11 +02:00

Add Run ninja command context menu item for Meson projects

- add new RunNinjaCommandHandler, RunNinja,
  AbstractMesonCommandHandler, and
  RunNinjaPage classes to support running ninja manually
  with env variables added and options specified
- add a new build method to MesonBuildConfiguration which
  specifies ninja options and environment variables
- add SWTImagesFactory for supplying the meson logo image
- add WizardMessages class for specifying messages for
  meson ui wizards
- add new MesonUtils class and move stripEnvVars from
  MesonBuildConfiguration to here
- add new constants to IMesonConstants interface

Change-Id: I8d635b2bd96792800bb07f4b3f1730be6e41eb24
This commit is contained in:
Jeff Johnston 2018-02-08 14:58:26 -05:00
parent db1cd491d6
commit ba7f4f26eb
14 changed files with 811 additions and 56 deletions

View file

@ -17,8 +17,6 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.cdt.core.CommandLauncherManager;
import org.eclipse.cdt.core.ConsoleOutputStream;
@ -102,8 +100,13 @@ public class MesonBuildConfiguration extends CBuildConfiguration {
@Override
public IProject[] build(int kind, Map<String, String> args, IConsole console, IProgressMonitor monitor)
throws CoreException {
return build(kind, args, null, null, console, monitor);
}
public IProject[] build(int kind, Map<String, String> args, String[] ninjaEnv, String[] ninjaArgs, IConsole console, IProgressMonitor monitor)
throws CoreException {
IProject project = getProject();
try {
project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
@ -117,7 +120,7 @@ public class MesonBuildConfiguration extends CBuildConfiguration {
if (toolChainFile == null && !isLocal()) {
IMesonToolChainManager manager = Activator.getService(IMesonToolChainManager.class);
toolChainFile = manager.getToolChainFileFor(getToolChain());
if (toolChainFile == null) {
// error
console.getErrorStream().write(Messages.MesonBuildConfiguration_NoToolchainFile);
@ -133,12 +136,12 @@ public class MesonBuildConfiguration extends CBuildConfiguration {
}
List<String> argsList = new ArrayList<>();
String userArgs = getProperty(IMesonConstants.MESON_ARGUMENTS);
if (userArgs != null) {
argsList.addAll(Arrays.asList(userArgs.trim().split("\\s+"))); //$NON-NLS-1$
}
argsList.add(getBuildDirectory().toString());
Map<String, String> envMap = System.getenv();
@ -148,25 +151,25 @@ public class MesonBuildConfiguration extends CBuildConfiguration {
}
String envStr = getProperty(IMesonConstants.MESON_ENV);
if (envStr != null) {
envList.addAll(stripEnvVars(envStr));
envList.addAll(MesonUtils.stripEnvVars(envStr));
}
String[] env = envList.toArray(new String[0]);
ICommandLauncher launcher = CommandLauncherManager.getInstance().getCommandLauncher(this);
launcher.setProject(getProject());
if (launcher instanceof ICBuildCommandLauncher) {
((ICBuildCommandLauncher)launcher).setBuildConfiguration(this);
}
monitor.subTask(Messages.MesonBuildConfiguration_RunningMeson);
org.eclipse.core.runtime.Path mesonPath = new org.eclipse.core.runtime.Path(path.toString());
outStream.write(String.join(" ", envStr != null ? envStr : "", //$NON-NLS-1$ //$NON-NLS-2$
mesonPath.toString(), userArgs, "\n")); //$NON-NLS-1$
outStream.write(getBuildDirectory() + "\n"); //$NON-NLS-1$
org.eclipse.core.runtime.Path workingDir = new org.eclipse.core.runtime.Path(getBuildDirectory().getParent().getParent().toString());
launcher.execute(mesonPath, argsList.toArray(new String[0]), env, workingDir, monitor);
if (launcher.waitAndRead(outStream, outStream, SubMonitor.convert(monitor)) != ICommandLauncher.OK) {
String errMsg = launcher.getErrorMessage();
@ -178,28 +181,39 @@ public class MesonBuildConfiguration extends CBuildConfiguration {
try (ErrorParserManager epm = new ErrorParserManager(project, getBuildDirectoryURI(), this,
getToolChain().getErrorParserIds())) {
epm.setOutputStream(console.getOutputStream());
String buildCommand = getProperty(IMesonConstants.BUILD_COMMAND);
if (buildCommand == null || buildCommand.isEmpty()) {
buildCommand = "ninja";
}
String[] env = new String[0];
Map<String, String> envMap = System.getenv();
List<String> envList = new ArrayList<>();
for (Map.Entry<String, String> entry : envMap.entrySet()) {
envList.add(entry.getKey() + "=" + entry.getValue());
}
if (ninjaEnv != null) {
envList.addAll(Arrays.asList(ninjaEnv));
}
String[] env = envList.toArray(new String[0]);
ICommandLauncher launcher = CommandLauncherManager.getInstance().getCommandLauncher(this);
launcher.setProject(getProject());
if (launcher instanceof ICBuildCommandLauncher) {
((ICBuildCommandLauncher)launcher).setBuildConfiguration(this);
}
monitor.subTask(Messages.MesonBuildConfiguration_RunningMeson);
monitor.subTask(Messages.MesonBuildConfiguration_RunningNinja);
org.eclipse.core.runtime.Path ninjaPath = new org.eclipse.core.runtime.Path(buildCommand);
outStream.write(String.join(" ", ninjaPath.toString() + '\n')); //$NON-NLS-1$
org.eclipse.core.runtime.Path workingDir = new org.eclipse.core.runtime.Path(getBuildDirectory().toString());
launcher.execute(ninjaPath, new String[] {"-v"}, env, workingDir, monitor); //$NON-NLS-1$
if (ninjaArgs == null) {
ninjaArgs = new String[] {"-v"}; //$NON-NLS-1$
}
launcher.execute(ninjaPath, ninjaArgs, env, workingDir, monitor);
if (launcher.waitAndRead(epm.getOutputStream(), epm.getOutputStream(), SubMonitor.convert(monitor)) != ICommandLauncher.OK) {
String errMsg = launcher.getErrorMessage();
console.getErrorStream().write(String.format(Messages.MesonBuildConfiguration_RunningNinjaFailure, errMsg));
@ -300,44 +314,6 @@ public class MesonBuildConfiguration extends CBuildConfiguration {
}
}
/**
* Strip a command of VAR=VALUE pairs that appear ahead or behind the command and add
* them to a list of environment variables.
*
* @param command - command to strip
* @param envVars - ArrayList to add environment variables to
* @return stripped command
*/
public static List<String> stripEnvVars(String envString) {
Pattern p1 = Pattern.compile("(\\w+[=]\\\".*?\\\").*"); //$NON-NLS-1$
Pattern p2 = Pattern.compile("(\\w+[=]'.*?').*"); //$NON-NLS-1$
Pattern p3 = Pattern.compile("(\\w+[=][^\\s]+).*"); //$NON-NLS-1$
boolean finished = false;
List<String> envVars = new ArrayList<>();
while (!finished) {
Matcher m1 = p1.matcher(envString);
if (m1.matches()) {
envString = envString.replaceFirst("\\w+[=]\\\".*?\\\"","").trim(); //$NON-NLS-1$ //$NON-NLS-2$
String s = m1.group(1).trim();
envVars.add(s.replaceAll("\\\"", "")); //$NON-NLS-1$ //$NON-NLS-2$
} else {
Matcher m2 = p2.matcher(envString);
if (m2.matches()) {
envString = envString.replaceFirst("\\w+[=]'.*?'", "").trim(); //$NON-NLS-1$ //$NON-NLS-2$
String s = m2.group(1).trim();
envVars.add(s.replaceAll("'", "")); //$NON-NLS-1$ //$NON-NLS-2$
} else {
Matcher m3 = p3.matcher(envString);
if (m3.matches()) {
envString = envString.replaceFirst("\\w+[=][^\\s]+", "").trim(); //$NON-NLS-1$ //$NON-NLS-2$
envVars.add(m3.group(1).trim());
} else {
finished = true;
}
}
}
}
return envVars;
}
}

View file

@ -0,0 +1,57 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat 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
*
* Red Hat Inc. - initial version
*******************************************************************************/
package org.eclipse.cdt.internal.meson.core;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MesonUtils {
/**
* Parse a string containing environment variables into individual VAR=VALUE pairs.
*
* @param envString - String to parse
* @return List of var=value Strings
*/
public static List<String> stripEnvVars(String envString) {
Pattern p1 = Pattern.compile("(\\w+[=]\\\".*?\\\").*"); //$NON-NLS-1$
Pattern p2 = Pattern.compile("(\\w+[=]'.*?').*"); //$NON-NLS-1$
Pattern p3 = Pattern.compile("(\\w+[=][^\\s]+).*"); //$NON-NLS-1$
boolean finished = false;
List<String> envVars = new ArrayList<>();
while (!finished) {
Matcher m1 = p1.matcher(envString);
if (m1.matches()) {
envString = envString.replaceFirst("\\w+[=]\\\".*?\\\"","").trim(); //$NON-NLS-1$ //$NON-NLS-2$
String s = m1.group(1).trim();
envVars.add(s.replaceAll("\\\"", "")); //$NON-NLS-1$ //$NON-NLS-2$
} else {
Matcher m2 = p2.matcher(envString);
if (m2.matches()) {
envString = envString.replaceFirst("\\w+[=]'.*?'", "").trim(); //$NON-NLS-1$ //$NON-NLS-2$
String s = m2.group(1).trim();
envVars.add(s.replaceAll("'", "")); //$NON-NLS-1$ //$NON-NLS-2$
} else {
Matcher m3 = p3.matcher(envString);
if (m3.matches()) {
envString = envString.replaceFirst("\\w+[=][^\\s]+", "").trim(); //$NON-NLS-1$ //$NON-NLS-2$
envVars.add(m3.group(1).trim());
} else {
finished = true;
}
}
}
}
return envVars;
}
}

View file

@ -19,6 +19,7 @@ public class Messages extends NLS {
public static String MesonBuildConfiguration_BuildingComplete;
public static String MesonBuildConfiguration_Cleaning;
public static String MesonBuildConfiguration_RunningMeson;
public static String MesonBuildConfiguration_RunningNinja;
public static String MesonBuildConfiguration_RunningMesonFailure;
public static String MesonBuildConfiguration_RunningNinjaFailure;
public static String MesonBuildConfiguration_NoToolchainFile;

View file

@ -12,6 +12,7 @@ MesonBuildConfiguration_BuildingIn=Building in: %s\n
MesonBuildConfiguration_BuildingComplete=Build complete: %s\n
MesonBuildConfiguration_Cleaning=Cleaning %s
MesonBuildConfiguration_RunningMeson=Running meson
MesonBuildConfiguration_RunningNinja=Running ninja
MesonBuildConfiguration_ProcCompCmds=Processing compile commands %s
MesonBuildConfiguration_ProcCompJson=Processing compile_commands.json
MesonBuildConfiguration_NoToolchainFile=No toolchain file found for this target.

View file

@ -14,6 +14,8 @@ public interface IMesonConstants {
public static final String MESON_ARGUMENTS = "meson.arguments"; //$NON-NLS-1$
public static final String MESON_ENV = "meson.environment"; //$NON-NLS-1$
public static final String NINJA_ENV = "meson.ninja.environment"; //$NON-NLS-1$
public static final String NINJA_ARGUMENTS = "meson.ninja.arguments"; //$NON-NLS-1$
public static final String MESON_ENV_SEPARATOR = "|"; //$NON-NLS-1$
String MESON_GENERATOR = "meson.generator"; //$NON-NLS-1$
String BUILD_COMMAND = "meson.command.build"; //$NON-NLS-1$

View file

@ -7,3 +7,5 @@
###############################################################################
meson.preferences.name = Meson
meson.run.ninja.label=Run ninja
meson.run.ninja.mnemonic=j

View file

@ -74,5 +74,63 @@
tabClass="org.eclipse.cdt.internal.meson.ui.MesonBuildTab">
</provider>
</extension>
<extension
id="org.eclipse.cdt.meson.ui.commands.ninja"
name="%meson.run.ninja.label"
point="org.eclipse.ui.commands">
</extension>
<extension
point="org.eclipse.ui.handlers">
<handler
class="org.eclipse.cdt.internal.meson.ui.commands.RunNinjaCommandHandler"
commandId="org.eclipse.cdt.meson.ui.command.runninja">
</handler>
</extension>
<extension
point="org.eclipse.core.expressions.definitions">
<definition
id="org.eclipse.cdt.meson.ui.handlerEnablement">
<with
variable="selection">
<count
value="1">
</count>
<iterate
ifEmpty="false"
operator="and">
<adapt
type="org.eclipse.core.resources.IResource">
<test
property="org.eclipse.core.resources.projectNature"
value="org.eclipse.cdt.meson.core.mesonNature">
</test>
</adapt>
</iterate>
</with>
</definition>
</extension>
<extension
point="org.eclipse.ui.menus">
<menuContribution
locationURI="popup:org.eclipse.ui.popup.any?before=additions">
<separator
name="mesonGroup"
visible="true">
</separator>
</menuContribution>
<menuContribution
locationURI="popup:org.eclipse.ui.popup.any?after=mesonGroup">
<command
commandId="org.eclipse.cdt.meson.ui.command.runninja"
id="ninja"
label="%meson.run.ninja.label"
mnemonic="%meson.run.ninja.mnemonic"
style="push">
<visibleWhen checkEnabled="true"/>
</command>
</menuContribution>
</extension>
</plugin>

View file

@ -0,0 +1,103 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat 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:
* Red Hat Inc. - initial implementation
*******************************************************************************/
package org.eclipse.cdt.internal.meson.ui;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.cdt.meson.ui.Activator;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.graphics.Image;
public class SWTImagesFactory {
// The plug-in registry
private static ImageRegistry imageRegistry = Activator.getPlugin()
.getImageRegistry();
// Sub-directory (under the package containing this class) where 16 color
// images are
private static URL fgIconBaseURL;
static {
try {
fgIconBaseURL = new URL(Activator.getPlugin().getBundle()
.getEntry("/"), "icons/"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (MalformedURLException e) {
Activator.log(e);
}
}
private static final String NAME_PREFIX = Activator.PLUGIN_ID + '.';
private static final int NAME_PREFIX_LENGTH = NAME_PREFIX.length();
public static final String IMG_MESON = NAME_PREFIX + "meson-logo.png"; //$NON-NLS-1$
public static final ImageDescriptor DESC_MESON = createManaged("",
IMG_MESON);
private static ImageDescriptor createManaged(String prefix, String name) {
return createManaged(imageRegistry, prefix, name);
}
private static ImageDescriptor createManaged(ImageRegistry registry,
String prefix, String name) {
ImageDescriptor result = ImageDescriptor.createFromURL(makeIconFileURL(
prefix, name.substring(NAME_PREFIX_LENGTH)));
registry.put(name, result);
return result;
}
public static Image get(String key) {
return imageRegistry.get(key);
}
private static ImageDescriptor create(String prefix, String name) {
return ImageDescriptor.createFromURL(makeIconFileURL(prefix, name));
}
private static URL makeIconFileURL(String prefix, String name) {
StringBuffer buffer = new StringBuffer(prefix);
buffer.append(name);
try {
return new URL(fgIconBaseURL, buffer.toString());
} catch (MalformedURLException e) {
Activator.log(e);
return null;
}
}
/**
* Sets all available image descriptors for the given action.
*
* @param action
* - action
* @param type
* - type of image descriptor
* @param relPath
* - relative path
*/
public static void setImageDescriptors(IAction action, String type,
String relPath) {
if (relPath.startsWith(NAME_PREFIX))
relPath = relPath.substring(NAME_PREFIX_LENGTH);
action.setDisabledImageDescriptor(create("d" + type, relPath)); //$NON-NLS-1$
action.setImageDescriptor(create("e" + type, relPath)); //$NON-NLS-1$
}
/**
* Helper method to access the image registry from the CUIPlugin class.
*/
static ImageRegistry getImageRegistry() {
return imageRegistry;
}
}

View file

@ -0,0 +1,242 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat 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:
* Red Hat Incorporated - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.meson.ui.commands;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.cdt.core.model.ICContainer;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.handlers.HandlerUtil;
public abstract class AbstractMesonCommandHandler extends AbstractHandler {
private IContainer fContainer;
protected abstract void run(Shell activeShell);
protected Object execute1(ExecutionEvent event) {
ISelection k = HandlerUtil.getCurrentSelection(event);
if (!k.isEmpty() && k instanceof IStructuredSelection) {
Object obj = ((IStructuredSelection)k).getFirstElement();
IContainer container = getContainer(obj);
if (container != null) {
setSelectedContainer(container);
run(HandlerUtil.getActiveShell(event));
}
}
return null;
}
@SuppressWarnings("unchecked")
protected IContainer getContainer(Object obj) {
IContainer fContainer = null;
if (obj instanceof Collection) {
Collection<Object> c = (Collection<Object>)obj;
Object[] objArray = c.toArray();
if (objArray.length > 0)
obj = objArray[0];
}
if (obj instanceof ICElement) {
if ( obj instanceof ICContainer || obj instanceof ICProject) {
fContainer = (IContainer) ((ICElement) obj).getUnderlyingResource();
} else {
obj = ((ICElement)obj).getResource();
if ( obj != null) {
fContainer = ((IResource)obj).getParent();
}
}
} else if (obj instanceof IResource) {
if (obj instanceof IContainer) {
fContainer = (IContainer) obj;
} else {
fContainer = ((IResource)obj).getParent();
}
} else {
fContainer = null;
}
return fContainer;
}
public final String SHELL_COMMAND = "sh"; //$NON-NLS-1$
protected void showError(String title, String content) {
MessageDialog.openError(new Shell(), title, content);
}
/**
* Separate targets to array from a string.
*
* @param rawArgList
* @return targets in string[] array. if targets are not formatted properly,
* returns null
*/
protected List<String> separateTargets(String rawArgList) {
StringTokenizer st = new StringTokenizer(rawArgList, " "); //$NON-NLS-1$
List<String> targetList = new ArrayList<>();
while (st.hasMoreTokens()) {
String currentWord = st.nextToken().trim();
if (currentWord.startsWith("'")) { //$NON-NLS-1$
StringBuilder tmpTarget = new StringBuilder();
while (!currentWord.endsWith("'")) { //$NON-NLS-1$
tmpTarget.append(currentWord).append(' ');
if (!st.hasMoreTokens()) {
// quote not closed properly, so return null
return null;
}
currentWord = st.nextToken().trim();
}
tmpTarget.append(currentWord);
targetList.add(tmpTarget.toString());
continue;
}
if (currentWord.startsWith("\"")) { //$NON-NLS-1$
StringBuilder tmpTarget = new StringBuilder();
while (!currentWord.endsWith("\"")) { //$NON-NLS-1$
tmpTarget.append(currentWord).append(' ');
if (!st.hasMoreTokens()) {
// double quote not closed properly, so return null
return null;
}
currentWord = st.nextToken().trim();
}
tmpTarget.append(currentWord);
targetList.add(tmpTarget.toString());
continue;
}
// for targets without quote/double quotes.
targetList.add(currentWord);
}
return targetList;
}
protected List<String> separateOptions(String rawArgList) {
List<String> argList = new ArrayList<>();
// May be multiple user-specified options in which case we
// need to split them up into individual options
rawArgList = rawArgList.trim();
boolean finished = false;
int lastIndex = rawArgList.indexOf("--"); //$NON-NLS-1$
if (lastIndex != -1) {
while (!finished) {
int index = rawArgList.indexOf("--", lastIndex + 2); //$NON-NLS-1$
if (index != -1) {
String previous = rawArgList.substring(lastIndex, index).trim();
argList.add(previous);
rawArgList = rawArgList.substring(index);
} else {
argList.add(rawArgList);
finished = true;
}
}
}
return argList;
}
protected List<String> simpleParseOptions(String rawArgList) {
List<String> argList = new ArrayList<>();
int lastArgIndex = -1;
int i = 0;
while (i < rawArgList.length()) {
char ch = rawArgList.charAt(i);
// Skip white-space
while (Character.isWhitespace(ch)) {
++i;
if (i < rawArgList.length())
ch = rawArgList.charAt(i);
else // Otherwise we are done
return argList;
}
// Simplistic parser. We break up into strings delimited
// by blanks. If quotes are used, we ignore blanks within.
// If a backslash is used, we ignore the next character and
// pass it through.
lastArgIndex = i;
boolean inString = false;
while (i < rawArgList.length()) {
ch = rawArgList.charAt(i);
if (ch == '\\') // escape character
++i; // skip over the next character
else if (ch == '\"') { // double quotes
inString = !inString;
} else if (Character.isWhitespace(ch)) {
if (!inString) {
argList.add(rawArgList.substring(lastArgIndex, i));
break;
}
}
++i;
}
// Look for the case where we ran out of chars for the last
// token.
if (i >= rawArgList.length())
argList.add(rawArgList.substring(lastArgIndex));
++i;
}
return argList;
}
protected IPath getExecDir(IContainer container) {
int type = container.getType();
IPath execDir = null;
if (type == IResource.FILE) {
execDir = container.getLocation().removeLastSegments(1);
} else {
execDir = container.getLocation();
}
return execDir;
}
protected IPath getCWD(IContainer container) {
int type = container.getType();
IPath cwd = null;
if (type == IResource.FILE) {
cwd = container.getFullPath().removeLastSegments(1);
} else {
cwd = container.getFullPath();
}
return cwd;
}
protected IContainer getSelectedContainer() {
return fContainer;
}
public void setSelectedContainer(IContainer container) {
fContainer = container;
}
}

View file

@ -0,0 +1,105 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat 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:
* Red Hat Inc. - initial implementation
*******************************************************************************/
package org.eclipse.cdt.internal.meson.ui.commands;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.build.CBuildConfiguration;
import org.eclipse.cdt.core.build.ICBuildConfiguration;
import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.cdt.internal.meson.core.MesonBuildConfiguration;
import org.eclipse.cdt.internal.meson.core.MesonUtils;
import org.eclipse.cdt.internal.meson.ui.wizards.RunNinja;
import org.eclipse.cdt.meson.core.IMesonConstants;
import org.eclipse.cdt.meson.ui.Activator;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class RunNinjaCommandHandler extends AbstractMesonCommandHandler {
@Override
public Object execute(ExecutionEvent event) {
return execute1(event);
}
@Override
public void run (Shell shell) {
// Set up console
IConsole console = CCorePlugin.getDefault().getConsole();
IProject project = getSelectedContainer().getAdapter(IProject.class);
console.start(project);
try {
ICBuildConfiguration buildConfig = ((CBuildConfiguration)project.getActiveBuildConfig().getAdapter(ICBuildConfiguration.class));
if (buildConfig instanceof MesonBuildConfiguration) {
MesonBuildConfiguration config = (MesonBuildConfiguration)buildConfig;
RunNinja wizard = new RunNinja(buildConfig);
final WizardDialog dialog = new WizardDialog(shell, wizard);
Display.getDefault().syncExec(() -> {
dialog.create();
dialog.open();
});
if (dialog.getReturnCode() == Window.OK) {
// Run ninja command in a Job so user can cancel if it stalls
Job buildJob = new Job("Running Ninja") {
@Override
public IStatus run(final IProgressMonitor monitor) {
String envString = config.getProperty(IMesonConstants.NINJA_ENV);
String[] ninjaEnv = null;
if (envString != null) {
ninjaEnv = MesonUtils.stripEnvVars(envString).toArray(new String[0]);
}
String argString = config.getProperty(IMesonConstants.NINJA_ARGUMENTS);
String[] ninjaArgs = null;
if (argString != null) {
List<String> ninjaArgList = new ArrayList<>();
Matcher m = Pattern.compile("([^\"]\\S*|\".+?\")\\s*").matcher(argString);
while (m.find()) {
ninjaArgList.add(m.group(1));
}
ninjaArgs = ninjaArgList.toArray(new String[0]);
}
try {
config.build(IncrementalProjectBuilder.FULL_BUILD, null, ninjaEnv, ninjaArgs, console, monitor);
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
} catch (CoreException e) {
Activator.log(e);
}
return Status.OK_STATUS;
}
};
buildJob.schedule();
}
}
} catch (CoreException e) {
Activator.log(e);
}
}
}

View file

@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat Inc.
* 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:
* Red Hat Inc. - Initial Contribution
*******************************************************************************/
package org.eclipse.cdt.internal.meson.ui.wizards;
import org.eclipse.cdt.core.build.ICBuildConfiguration;
import org.eclipse.cdt.meson.core.IMesonConstants;
import org.eclipse.jface.wizard.Wizard;
public class RunNinja extends Wizard {
private RunNinjaPage mainPage;
private ICBuildConfiguration config;
private String envStr;
private String ninjaArgs;
public RunNinja(ICBuildConfiguration config) {
this.config = config;
}
@Override
public void addPages() {
mainPage = new RunNinjaPage(config);
addPage(mainPage);
}
@Override
public boolean canFinish() {
return mainPage.isPageComplete();
}
@Override
public boolean performFinish() {
envStr = mainPage.getEnvStr();
config.setProperty(IMesonConstants.NINJA_ENV, envStr);
ninjaArgs = mainPage.getNinjaArgs();
config.setProperty(IMesonConstants.NINJA_ARGUMENTS, ninjaArgs);
return true;
}
public String getEnvStr() {
return envStr;
}
public String getNinjaArgs() {
return ninjaArgs;
}
}

View file

@ -0,0 +1,102 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat Inc
* 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:
* Red Hat Inc. - Initial Contribution
*******************************************************************************/
package org.eclipse.cdt.internal.meson.ui.wizards;
import org.eclipse.cdt.core.build.ICBuildConfiguration;
import org.eclipse.cdt.internal.meson.ui.SWTImagesFactory;
import org.eclipse.cdt.meson.core.IMesonConstants;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
/**
* A standard file selection dialog which solicits a list of files from the user.
* The <code>getResult</code> method returns the selected files.
* <p>
* This class may be instantiated; it is not intended to be subclassed.
* </p>
* <p>
* Example:
* <pre>
* FileSelectionDialog dialog =
* new FileSelectionDialog(getShell(), rootElement, msg);
* dialog.setInitialSelections(selectedResources);
* dialog.open();
* return dialog.getResult();
* </pre>
* </p>
* @noextend This class is not intended to be subclassed by clients.
*/
public class RunNinjaPage extends WizardPage {
private ICBuildConfiguration config;
private Text envText;
private Text ninjaArgs;
public RunNinjaPage(ICBuildConfiguration config) {
super(WizardMessages.RunNinjaPage_name);
setDescription(WizardMessages.RunNinjaPage_description);
setTitle(WizardMessages.RunNinjaPage_title);
setImageDescriptor(SWTImagesFactory.DESC_MESON);
this.config = config;
}
@Override
public void createControl(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
composite.setLayout(new GridLayout(1, true));
Label envLabel = new Label(composite, SWT.NONE);
envLabel.setText(WizardMessages.RunNinjaPage_env_label);
envLabel.setLayoutData(new GridData());
envText = new Text(composite, SWT.BORDER);
String lastEnv = config.getProperty(IMesonConstants.NINJA_ENV);
if (lastEnv == null) {
lastEnv = ""; //$NON-NLS-1$
}
envText.setToolTipText(WizardMessages.RunNinjaPage_env_description);
envText.setText(lastEnv);
GridData gdata = new GridData(SWT.FILL, SWT.FILL, true, false);
envText.setLayoutData(gdata);
Label argLabel = new Label(composite, SWT.NONE);
argLabel.setText(WizardMessages.RunNinjaPage_options_label);
argLabel.setLayoutData(new GridData());
ninjaArgs = new Text(composite, SWT.BORDER);
String lastNinjaArgs = config.getProperty(IMesonConstants.NINJA_ARGUMENTS);
if (lastNinjaArgs == null) {
lastNinjaArgs = ""; //$NON-NLS-1$
}
ninjaArgs.setToolTipText(WizardMessages.RunNinjaPage_options_description);
ninjaArgs.setText(lastNinjaArgs);
GridData gdata2 = new GridData(SWT.FILL, SWT.FILL, true, false);
ninjaArgs.setLayoutData(gdata2);
setControl(composite);
}
public String getEnvStr() {
return envText.getText();
}
public String getNinjaArgs() {
return ninjaArgs.getText();
}
}

View file

@ -0,0 +1,33 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat 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:
* Red Hat Inc. - initial implementation
*******************************************************************************/
package org.eclipse.cdt.internal.meson.ui.wizards;
import org.eclipse.osgi.util.NLS;
public class WizardMessages extends NLS {
public static String RunNinjaPage_name;
public static String RunNinjaPage_description;
public static String RunNinjaPage_title;
public static String RunNinjaPage_env_label;
public static String RunNinjaPage_env_description;
public static String RunNinjaPage_options_label;
public static String RunNinjaPage_options_description;
static {
// initialize resource bundle
NLS.initializeMessages("org.eclipse.cdt.internal.meson.ui.wizards.wizardmessages", WizardMessages.class); //$NON-NLS-1$
}
private WizardMessages() {
}
}

View file

@ -0,0 +1,17 @@
################################################################################
# Copyright (c) 2018 Red Hat Inc.
# 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:
# Red Hat Inc. - Initial Contribution
################################################################################
RunNinjaPage_name=Run ninja
RunNinjaPage_description=Run ninja manually for the active build configuration
RunNinjaPage_title=Run ninja manually
RunNinjaPage_env_label=Environment:
RunNinjaPage_env_description=Environment variables for ninja command
RunNinjaPage_options_label=Options:
RunNinjaPage_options_description=Options to pass to ninja command