blob: a8c2ed8a5da5e1765519966f47e427c95c7a6931 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2016 Red Hat Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.autotools.core;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.cdt.autotools.core.AutotoolsPlugin;
import org.eclipse.cdt.core.IErrorParser;
import org.eclipse.cdt.core.ProblemMarkerInfo;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
// This class would normally extend IErrorParser and use the CDT error parser
// extension. However, we want an extended IMarker that contains library info and
// possibly other data in the future. The standard CDT ErrorParserManager doesn't allow
// us to pass an extended ProblemMarkerInfo, so we are forced to have our own mechanism
// which is similar to the CDT one.
public class ErrorParser extends MarkerGenerator implements IErrorParser {
public static final String ID = AutotoolsPlugin.PLUGIN_ID + ".errorParser"; //$NON-NLS-1$
private Pattern pkgconfigError = Pattern
.compile(".*?(configure:\\s+error:\\s+Package requirements\\s+\\((.*?)\\)\\s+were not met).*"); //$NON-NLS-1$
private Pattern genconfigError = Pattern.compile(".*?configure:\\s+error:\\s+(.*)"); //$NON-NLS-1$
private Pattern checkingFail = Pattern.compile("checking for (.*)\\.\\.\\. no"); //$NON-NLS-1$
private Pattern changingConfigDirectory = Pattern.compile("Configuring in (.*)"); //$NON-NLS-1$
private IPath buildDir;
private IPath sourcePath;
private IProject project;
public ErrorParser() {
}
public ErrorParser(IPath sourcePath, IPath buildPath) {
this.buildDir = buildPath;
this.sourcePath = sourcePath;
}
@Override
public boolean processLine(String line, org.eclipse.cdt.core.ErrorParserManager eoParser) {
if (this.project == null)
this.project = eoParser.getProject();
if (this.buildDir == null)
this.buildDir = new Path(eoParser.getWorkingDirectoryURI().getPath());
if (this.sourcePath == null)
this.sourcePath = eoParser.getProject().getLocation();
AutotoolsProblemMarkerInfo marker = processLine(line);
if (marker != null) {
// Check to see if addProblemMarker exists.
try {
Method method = eoParser.getClass().getMethod("addProblemMarker", ProblemMarkerInfo.class); //$NON-NLS-1$
try {
method.invoke(eoParser, marker);
return true;
} catch (Exception e) {
throw new RuntimeException(e);
}
} catch (SecurityException | NoSuchMethodException e) {
return false;
}
}
return false;
}
public boolean processLine(String line, ErrorParserManager eoParser) {
if (this.project == null)
this.project = eoParser.getProject();
AutotoolsProblemMarkerInfo marker = processLine(line);
if (marker != null) {
eoParser.addProblemMarker(marker);
return true;
}
return false;
}
public AutotoolsProblemMarkerInfo processLine(String line) {
Matcher m;
m = changingConfigDirectory.matcher(line);
if (m.matches()) {
// set configuration directory.
this.buildDir = this.buildDir.append(m.group(1));
this.sourcePath = this.sourcePath.append(m.group(1));
return null;
}
m = pkgconfigError.matcher(line);
if (m.matches()) {
return new AutotoolsProblemMarkerInfo(getProject(), -1, m.group(1), SEVERITY_ERROR_BUILD, null, null,
m.group(2), AutotoolsProblemMarkerInfo.Type.PACKAGE);
}
m = genconfigError.matcher(line);
if (m.matches()) {
return new AutotoolsProblemMarkerInfo(getProject(), -1, m.group(1), SEVERITY_ERROR_BUILD, null,
AutotoolsProblemMarkerInfo.Type.GENERIC);
}
m = checkingFail.matcher(line);
if (m.matches()) {
// We know that there is a 'checking for ...' fail.
// Find the log file containing this check
AutotoolsProblemMarkerInfo.Type type = getCheckType(m.group(1));
if (type != null)
return new AutotoolsProblemMarkerInfo(getProject(), "Missing " + type + " " + m.group(1), SEVERITY_INFO,
m.group(1), type);
}
return null;
}
/**
* Given the name of the filed check object, look for it in the log file
* file and then examine the configure script to figure out what the type of
* the check was.
*
* @param name
* @return
*/
private AutotoolsProblemMarkerInfo.Type getCheckType(String name) {
int lineNumber = getErrorConfigLineNumber(name);
// now open configure file.
File file = new File(sourcePath + "/configure"); //$NON-NLS-1$
// If the log file is not present there is nothing we can do.
if (!file.exists())
return null;
try (LineNumberReader reader = new LineNumberReader(new FileReader(file))) {
// look for something like:
// if test "${ac_cv_prog_WINDRES+set}" = set; then :
Pattern errorPattern = Pattern.compile(".*ac_cv_([a-z]*)_.*"); //$NON-NLS-1$
// skip to the line
String line = reader.readLine();
for (int i = 0; i < lineNumber + 10 && line != null; i++) {
if (i < lineNumber) {
line = reader.readLine();
continue;
}
Matcher m = errorPattern.matcher(line);
if (m.matches()) {
String typeString = m.group(1);
if (typeString.equals("prog")) //$NON-NLS-1$
return AutotoolsProblemMarkerInfo.Type.PROG;
if (typeString.equals("header")) //$NON-NLS-1$
return AutotoolsProblemMarkerInfo.Type.HEADER;
if (typeString.equals("file")) //$NON-NLS-1$
return AutotoolsProblemMarkerInfo.Type.FILE;
if (typeString.equals("lib")) //$NON-NLS-1$
return AutotoolsProblemMarkerInfo.Type.LIB;
return null;
}
line = reader.readLine();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
/**
* Check the log file for the check for the given name and return the line
* number in configure where the check occurs.
*
* @param name
* @return
*/
private int getErrorConfigLineNumber(String name) {
File file = new File(buildDir + "/config.log"); //$NON-NLS-1$
// If the log file is not present there is nothing we can do.
if (!file.exists())
return -1;
try (LineNumberReader reader = new LineNumberReader(new FileReader(file))) {
Pattern errorPattern = Pattern.compile("configure:(\\d+): checking for " + name); //$NON-NLS-1$
String line;
while ((line = reader.readLine()) != null) {
Matcher m = errorPattern.matcher(line);
if (m.matches()) {
return Integer.parseInt(m.group(1));
}
}
} catch (IOException e) {
return -1;
}
return -1;
}
@Override
public IProject getProject() {
return this.project;
}
}