/*******************************************************************************
* Copyright (c) 2014 Bruno Medeiros and other Contributors.
* 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:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package com.googlecode.goclipse.tooling;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import melnorme.lang.tooling.common.ToolSourceMessage;
import melnorme.lang.tooling.toolchain.ops.BuildOutputParser2;
import melnorme.lang.tooling.toolchain.ops.ToolMessageData;
import melnorme.lang.utils.parse.LexingUtils;
import melnorme.lang.utils.parse.StringCharSource;
import melnorme.utilbox.collections.ArrayList2;
import melnorme.utilbox.core.CommonException;
import melnorme.utilbox.misc.StringUtil;
import melnorme.utilbox.process.ExternalProcessHelper.ExternalProcessResult;
import melnorme.utilbox.status.StatusLevel;
public abstract class GoBuildOutputProcessor extends BuildOutputParser2 {
public GoBuildOutputProcessor() {
}
@Override
public ArrayList2<ToolSourceMessage> doParseResult(ExternalProcessResult result) throws CommonException {
// validateExitCode(result);
ArrayList2<ToolSourceMessage> msgs = new ArrayList2<>();
// Parse both stderr and stdout as different commands may output message to different streams
// for example go build outputs to stderr, but gometalinter to stdout
msgs.addAll(parseOutput(result.getStdErrBytes().toString(StringUtil.UTF8)));
msgs.addAll(parseOutput(result.getStdOutBytes().toString(StringUtil.UTF8)));
return msgs;
}
protected static final Pattern ERROR_LINE_Regex = Pattern.compile(
"^([^:\\n]*):" + // file
"(\\d*):" + // line
"(\\d*)?(:)?" + // column
"((warning|error|info):)?" + // type
"\\s(.*)$" // error message
);
public static final Pattern WINDOWS_DRIVE_LETTER = Pattern.compile("[a-zA-Z]:\\\\.*", Pattern.DOTALL);
@Override
protected ToolMessageData parseMessageData(StringCharSource output) throws CommonException {
String outputLine = LexingUtils.consumeLine(output);
if(!outputLine.contains(":") || outputLine.startsWith("# ") || outputLine.startsWith("WARNING:")) {
return null; // Ignore line
}
String pathDevicePrefix = "";
if(WINDOWS_DRIVE_LETTER.matcher(outputLine).matches()) {
// Remove Windows drive letter from path, cause it will mess up regex
pathDevicePrefix = outputLine.substring(0, 2);
outputLine = outputLine.substring(2);
}
ToolMessageData msgData = new ToolMessageData();
Matcher matcher = ERROR_LINE_Regex.matcher(outputLine);
if(!matcher.matches()) {
throw createUnknownLineSyntaxError(outputLine);
}
msgData.pathString = pathDevicePrefix + matcher.group(1);
msgData.lineString = matcher.group(2);
msgData.columnString = matcher.group(3);
msgData.messageTypeString = matcher.group(6);
msgData.messageText = matcher.group(7);
while(true) {
int readChar = output.lookahead();
if(readChar == '\t') {
String nextLine = LexingUtils.consumeLine(output);
msgData.messageText += "\n" + nextLine;
} else {
break;
}
}
return msgData;
}
@Override
protected void addBuildMessage(ToolMessageData msgdata) throws CommonException {
if(msgdata.messageTypeString == null) {
msgdata.messageTypeString = StatusLevel.ERROR.toString();
}
super.addBuildMessage(msgdata);
}
}