blob: 221e5707e9f21dbad0791d55f6c80210ca737bb8 [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
***********************************************************************/
package org.eclipse.cdt.make.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.CommandLauncher;
import org.eclipse.cdt.core.ErrorParserManager;
import org.eclipse.cdt.core.model.ICModelMarker;
import org.eclipse.cdt.core.resources.ACBuilder;
import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.cdt.make.internal.core.StreamMonitor;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.SubProgressMonitor;
public class MakeBuilder extends ACBuilder {
private static final String BUILD_ERROR = "MakeBuilder.buildError"; //$NON-NLS-1$
public final static String BUILDER_ID = MakeCorePlugin.getUniqueIdentifier() + ".makeBuilder"; //$NON-NLS-1$
public MakeBuilder() {
}
public class MyResourceDeltaVisitor implements IResourceDeltaVisitor {
boolean bContinue;
public boolean visit(IResourceDelta delta) throws CoreException {
IResource resource = delta.getResource();
if (resource != null && resource.getProject() == getProject()) {
bContinue = true;
return false;
}
return true;
}
public boolean shouldBuild() {
return bContinue;
}
}
/**
* @see IncrementalProjectBuilder#build
*/
protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
boolean bPerformBuild = true;
IMakeBuilderInfo info = MakeCorePlugin.createBuildInfo(args, MakeBuilder.BUILDER_ID);
if (!shouldBuild(kind, info)) {
forgetLastBuiltState();
return new IProject[0];
}
if (kind == IncrementalProjectBuilder.AUTO_BUILD) {
MyResourceDeltaVisitor vis = new MyResourceDeltaVisitor();
IResourceDelta delta = getDelta(getProject());
if (delta != null) {
delta.accept(vis);
bPerformBuild = vis.shouldBuild();
} else
bPerformBuild = false;
}
if (bPerformBuild) {
boolean isClean = invokeMake(kind, info, monitor);
if (isClean) {
forgetLastBuiltState();
}
} else { // This should really be based of last build state, for now its safer to just
// forget last, until we get some kind of build state manager in the CDT Core.
forgetLastBuiltState();
}
checkCancel(monitor);
return getProject().getReferencedProjects();
}
private boolean invokeMake(int kind, IMakeBuilderInfo info, IProgressMonitor monitor) {
boolean isClean = false;
IProject currProject = getProject();
if (monitor == null) {
monitor = new NullProgressMonitor();
}
monitor.beginTask(MakeCorePlugin.getResourceString("MakeBuilder.Invoking_Make_Builder") + currProject.getName(), 100); //$NON-NLS-1$
try {
IPath buildCommand = info.getBuildCommand();
if (buildCommand != null) {
IConsole console = CCorePlugin.getDefault().getConsole();
console.start(currProject);
OutputStream cos = console.getOutputStream();
// remove all markers for this project
removeAllMarkers(currProject);
IPath workingDirectory = null;
if (!info.getBuildLocation().isEmpty()) {
IResource res = currProject.getParent().findMember(info.getBuildLocation());
if (res instanceof IContainer && res.exists()) {
workingDirectory = res.getLocation();
}
}
if (workingDirectory == null) {
workingDirectory = currProject.getLocation();
}
String[] targets = getTargets(kind, info);
if (targets.length != 0 && targets[targets.length - 1].equals("clean")) //$NON-NLS-1$
isClean = true;
String errMsg = null;
CommandLauncher launcher = new CommandLauncher();
// Print the command for visual interaction.
launcher.showCommand(true);
// Set the environmennt, some scripts may need the CWD var to be set.
Properties props = launcher.getEnvironment();
props.putAll(info.getEnvironment());
props.put("CWD", workingDirectory.toOSString()); //$NON-NLS-1$
props.put("PWD", workingDirectory.toOSString()); //$NON-NLS-1$
String[] env = null;
ArrayList envList = new ArrayList();
Enumeration names = props.propertyNames();
if (names != null) {
while (names.hasMoreElements()) {
String key = (String) names.nextElement();
envList.add(key + "=" + props.getProperty(key)); //$NON-NLS-1$
}
env = (String[]) envList.toArray(new String[envList.size()]);
}
String[] buildArguments = targets;
if (info.isDefaultBuildCmd()) {
if (!info.isStopOnError()) {
buildArguments = new String[targets.length + 1];
buildArguments[0] = "-k"; //$NON-NLS-1$
System.arraycopy(targets, 0, buildArguments, 1, targets.length);
}
} else {
String args = info.getBuildArguments();
if (args != null && !args.equals("")) { //$NON-NLS-1$
String[] newArgs = makeArray(args);
buildArguments = new String[targets.length + newArgs.length];
System.arraycopy(newArgs, 0, buildArguments, 0, newArgs.length);
System.arraycopy(targets, 0, buildArguments, newArgs.length, targets.length);
}
}
// MakeRecon recon = new MakeRecon(buildCommand, buildArguments, env, workingDirectory, makeMonitor, cos);
// recon.invokeMakeRecon();
// cos = recon;
QualifiedName qName = new QualifiedName(MakeCorePlugin.getUniqueIdentifier(), "progressMonitor");
Integer last = (Integer)getProject().getSessionProperty(qName);
if (last == null) {
last = new Integer(100);
}
StreamMonitor streamMon = new StreamMonitor(new SubProgressMonitor(monitor, 100), cos, last.intValue());
ErrorParserManager epm = new ErrorParserManager(getProject(), this, info.getErrorParsers());
epm.setOutputStream(streamMon);
OutputStream stdout = epm.getOutputStream();
OutputStream stderr = epm.getOutputStream();
Process p = launcher.execute(buildCommand, buildArguments, env, workingDirectory);
if (p != null) {
try {
// Close the input of the Process explicitely.
// We will never write to it.
p.getOutputStream().close();
} catch (IOException e) {
}
// Before launching give visual cues via the monitor
monitor.subTask(MakeCorePlugin.getResourceString("MakeBuilder.Invoking_Command") + launcher.getCommandLine()); //$NON-NLS-1$
if (launcher.waitAndRead(stdout, stderr, new SubProgressMonitor(monitor, 0))
!= CommandLauncher.OK)
errMsg = launcher.getErrorMessage();
monitor.subTask(MakeCorePlugin.getResourceString("MakeBuilder.Updating_project")); //$NON-NLS-1$
try {
// Do not allow the cancel of the refresh, since the builder is external
// to Eclipse, files may have been created/modified and we will be out-of-sync.
// The caveat is for hugue projects, it may take sometimes at every build.
currProject.refreshLocal(IResource.DEPTH_INFINITE, null);
} catch (CoreException e) {
}
} else {
errMsg = launcher.getErrorMessage();
}
getProject().setSessionProperty(qName, !monitor.isCanceled() && !isClean ? new Integer(streamMon.getWorkDone()) : null);
if (errMsg != null) {
StringBuffer buf = new StringBuffer(buildCommand.toString() + " "); //$NON-NLS-1$
for (int i = 0; i < buildArguments.length; i++) {
buf.append(buildArguments[i]);
buf.append(' ');
}
String errorDesc = MakeCorePlugin.getFormattedString(BUILD_ERROR, buf.toString());
buf = new StringBuffer(errorDesc);
buf.append(System.getProperty("line.separator", "\n")); //$NON-NLS-1$ //$NON-NLS-2$
buf.append("(").append(errMsg).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
cos.write(buf.toString().getBytes());
cos.flush();
}
stdout.close();
stderr.close();
monitor.subTask(MakeCorePlugin.getResourceString("MakeBuilder.Creating_Markers")); //$NON-NLS-1$
epm.reportProblems();
cos.close();
}
} catch (Exception e) {
CCorePlugin.log(e);
} finally {
monitor.done();
}
return (isClean);
}
/**
* Check whether the build has been canceled.
*/
public void checkCancel(IProgressMonitor monitor) {
if (monitor != null && monitor.isCanceled())
throw new OperationCanceledException();
}
protected boolean shouldBuild(int kind, IMakeBuilderInfo info) {
switch (kind) {
case IncrementalProjectBuilder.AUTO_BUILD :
return info.isAutoBuildEnable();
case IncrementalProjectBuilder.INCREMENTAL_BUILD :
return info.isIncrementalBuildEnabled();
case IncrementalProjectBuilder.FULL_BUILD :
return info.isFullBuildEnabled();
}
return true;
}
protected String[] getTargets(int kind, IMakeBuilderInfo info) {
String targets = ""; //$NON-NLS-1$
switch (kind) {
case IncrementalProjectBuilder.AUTO_BUILD :
targets = info.getAutoBuildTarget();
break;
case IncrementalProjectBuilder.INCREMENTAL_BUILD :
targets = info.getIncrementalBuildTarget();
break;
case IncrementalProjectBuilder.FULL_BUILD :
targets = info.getFullBuildTarget();
break;
}
return makeArray(targets);
}
// Turn the string into an array.
String[] makeArray(String string) {
string.trim();
char[] array = string.toCharArray();
ArrayList aList = new ArrayList();
StringBuffer buffer = new StringBuffer();
boolean inComment = false;
for (int i = 0; i < array.length; i++) {
char c = array[i];
if (array[i] == '"' || array[i] == '\'') {
if (i > 0 && array[i - 1] == '\\') {
inComment = false;
} else {
inComment = !inComment;
}
}
if (c == ' ' && !inComment) {
aList.add(buffer.toString());
buffer = new StringBuffer();
} else {
buffer.append(c);
}
}
if (buffer.length() > 0)
aList.add(buffer.toString());
return (String[]) aList.toArray(new String[aList.size()]);
}
private void removeAllMarkers(IProject currProject) throws CoreException {
IWorkspace workspace = currProject.getWorkspace();
// remove all markers
IMarker[] markers = currProject.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
if (markers != null) {
workspace.deleteMarkers(markers);
}
}
}