blob: 1d3c7bd3aa33d56c2fdb3bdea2b36ae7351af1c9 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.eclipse.adt.internal.build;
import com.android.annotations.NonNull;
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
import com.android.sdklib.build.RenderScriptProcessor.CommandLineLauncher;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A {@link SourceProcessor} for RenderScript files.
*/
public class RenderScriptLauncher implements CommandLineLauncher {
/**
* Single line llvm-rs-cc error: {@code <path>:<line>:<col>: <error>}
*/
private static Pattern sLlvmPattern1 = Pattern.compile("^(.+?):(\\d+):(\\d+):\\s(.+)$"); //$NON-NLS-1$
@NonNull
private final IProject mProject;
@NonNull
private final IFolder mSourceOutFolder;
@NonNull
private final IFolder mResOutFolder;
@NonNull
private final IProgressMonitor mMonitor;
private final boolean mVerbose;
public RenderScriptLauncher(
@NonNull IProject project,
@NonNull IFolder sourceOutFolder,
@NonNull IFolder resOutFolder,
@NonNull IProgressMonitor monitor,
boolean verbose) {
mProject = project;
mSourceOutFolder = sourceOutFolder;
mResOutFolder = resOutFolder;
mMonitor = monitor;
mVerbose = verbose;
}
@Override
public void launch(File executable, List<String> arguments, Map<String, String> envVariableMap)
throws IOException, InterruptedException {
// do the exec
try {
if (mVerbose) {
StringBuilder sb = new StringBuilder(executable.getAbsolutePath());
for (String c : arguments) {
sb.append(' ').append(c);
}
String cmd_line = sb.toString();
AdtPlugin.printToConsole(mProject, cmd_line);
}
String[] commandArray = new String[1 + arguments.size()];
commandArray[0] = executable.getAbsolutePath();
System.arraycopy(arguments.toArray(), 0, commandArray, 1, arguments.size());
ProcessBuilder processBuilder = new ProcessBuilder(commandArray);
Map<String, String> processEnvs = processBuilder.environment();
for (Map.Entry<String, String> entry : envVariableMap.entrySet()) {
processEnvs.put(entry.getKey(), entry.getValue());
}
Process p = processBuilder.start();
// list to store each line of stderr
ArrayList<String> stdErr = new ArrayList<String>();
// get the output and return code from the process
int returnCode = BuildHelper.grabProcessOutput(mProject, p, stdErr);
if (stdErr.size() > 0) {
// attempt to parse the error output
boolean parsingError = parseLlvmOutput(stdErr);
// If the process failed and we couldn't parse the output
// we print a message, mark the project and exit
if (returnCode != 0) {
if (parsingError || mVerbose) {
// display the message in the console.
if (parsingError) {
AdtPlugin.printErrorToConsole(mProject, stdErr.toArray());
// mark the project
BaseProjectHelper.markResource(mProject,
AdtConstants.MARKER_RENDERSCRIPT,
"Unparsed Renderscript error! Check the console for output.",
IMarker.SEVERITY_ERROR);
} else {
AdtPlugin.printToConsole(mProject, stdErr.toArray());
}
}
return;
}
} else if (returnCode != 0) {
// no stderr output but exec failed.
String msg = String.format("Error executing Renderscript: Return code %1$d",
returnCode);
BaseProjectHelper.markResource(mProject, AdtConstants.MARKER_AIDL,
msg, IMarker.SEVERITY_ERROR);
return;
}
} catch (IOException e) {
// mark the project and exit
String msg = String.format(
"Error executing Renderscript. Please check %1$s is present at %2$s",
executable.getName(), executable.getAbsolutePath());
AdtPlugin.log(IStatus.ERROR, msg);
BaseProjectHelper.markResource(mProject, AdtConstants.MARKER_RENDERSCRIPT, msg,
IMarker.SEVERITY_ERROR);
throw e;
} catch (InterruptedException e) {
// mark the project and exit
String msg = String.format(
"Error executing Renderscript. Please check %1$s is present at %2$s",
executable.getName(), executable.getAbsolutePath());
AdtPlugin.log(IStatus.ERROR, msg);
BaseProjectHelper.markResource(mProject, AdtConstants.MARKER_RENDERSCRIPT, msg,
IMarker.SEVERITY_ERROR);
throw e;
}
try {
mSourceOutFolder.refreshLocal(IResource.DEPTH_ONE, mMonitor);
mResOutFolder.refreshLocal(IResource.DEPTH_ONE, mMonitor);
} catch (CoreException e) {
AdtPlugin.log(e, "failed to refresh folders");
}
return;
}
/**
* Parse the output of llvm-rs-cc and mark the file with any errors.
* @param lines The output to parse.
* @return true if the parsing failed, false if success.
*/
private boolean parseLlvmOutput(ArrayList<String> lines) {
// nothing to parse? just return false;
if (lines.size() == 0) {
return false;
}
// get the root folder for the project as we're going to ignore everything that's
// not in the project
String rootPath = mProject.getLocation().toOSString();
int rootPathLength = rootPath.length();
Matcher m;
boolean parsing = false;
for (int i = 0; i < lines.size(); i++) {
String p = lines.get(i);
m = sLlvmPattern1.matcher(p);
if (m.matches()) {
// get the file path. This may, or may not be the main file being compiled.
String filePath = m.group(1);
if (filePath.startsWith(rootPath) == false) {
// looks like the error in a non-project file. Keep parsing, but
// we'll return true
parsing = true;
continue;
}
// get the actual file.
filePath = filePath.substring(rootPathLength);
// remove starting separator since we want the path to be relative
if (filePath.startsWith(File.separator)) {
filePath = filePath.substring(1);
}
// get the file
IFile f = mProject.getFile(new Path(filePath));
String lineStr = m.group(2);
// ignore group 3 for now, this is the col number
String msg = m.group(4);
// get the line number
int line = 0;
try {
line = Integer.parseInt(lineStr);
} catch (NumberFormatException e) {
// looks like the string we extracted wasn't a valid
// file number. Parsing failed and we return true
return true;
}
// mark the file
BaseProjectHelper.markResource(f, AdtConstants.MARKER_RENDERSCRIPT, msg, line,
IMarker.SEVERITY_ERROR);
// success, go to the next line
continue;
}
// invalid line format, flag as error, and keep going
parsing = true;
}
return parsing;
}
}