use of com.android.ide.common.blame.Message in project android by JetBrains.
the class JavacOutputParser method parse.
@Override
public boolean parse(@NotNull String line, @NotNull OutputLineReader reader, @NotNull List<Message> messages, @NotNull ILogger logger) throws ParsingFailedException {
int colonIndex1 = line.indexOf(COLON);
if (colonIndex1 == 1) {
// drive letter (Windows)
colonIndex1 = line.indexOf(COLON, colonIndex1 + 1);
}
if (colonIndex1 >= 0) {
// looks like found something like a file path.
String part1 = line.substring(0, colonIndex1).trim();
if (part1.equalsIgnoreCase("error") || /* jikes */
part1.equalsIgnoreCase("Caused by")) {
// +1 so we don't include the colon
String text = line.substring(colonIndex1 + 1).trim();
addMessage(new Message(Message.Kind.ERROR, text, SourceFilePosition.UNKNOWN), messages);
return true;
}
if (part1.equalsIgnoreCase("warning")) {
// +1 so we don't include the colon
String text = line.substring(colonIndex1 + 1).trim();
addMessage(new Message(Message.Kind.WARNING, text, SourceFilePosition.UNKNOWN), messages);
return true;
}
if (part1.equalsIgnoreCase("javac")) {
addMessage(new Message(Message.Kind.ERROR, line, SourceFilePosition.UNKNOWN), messages);
return true;
}
int colonIndex2 = line.indexOf(COLON, colonIndex1 + 1);
if (colonIndex2 >= 0) {
File file = new File(part1);
if (!file.isFile()) {
// the part one is not a file path.
return false;
}
try {
// 1-based.
int lineNumber = Integer.parseInt(line.substring(colonIndex1 + 1, colonIndex2).trim());
String text = line.substring(colonIndex2 + 1).trim();
Message.Kind kind = Message.Kind.ERROR;
if (text.startsWith(WARNING_PREFIX)) {
text = text.substring(WARNING_PREFIX.length()).trim();
kind = Message.Kind.WARNING;
}
// Only slurp up line pointer (^) information if this is really javac
if (!file.getPath().endsWith(SdkConstants.DOT_JAVA)) {
// Fall back to the MergingExceptionParser (which handles similar messages in a more general way)
return false;
}
List<String> messageList = Lists.newArrayList();
messageList.add(text);
// 0-based.
int column;
String prevLine = null;
do {
String nextLine = reader.readLine();
if (nextLine == null) {
return false;
}
if (nextLine.trim().equals("^")) {
column = nextLine.indexOf('^');
String messageEnd = reader.readLine();
while (isMessageEnd(messageEnd)) {
messageList.add(messageEnd.trim());
messageEnd = reader.readLine();
}
if (messageEnd != null) {
reader.pushBack();
}
break;
}
if (prevLine != null) {
messageList.add(prevLine);
}
prevLine = nextLine;
} while (true);
if (column >= 0) {
messageList = convertMessages(messageList);
StringBuilder buf = StringBuilderSpinAllocator.alloc();
try {
for (String m : messageList) {
if (buf.length() > 0) {
buf.append(SystemProperties.getLineSeparator());
}
buf.append(m);
}
Message msg = new Message(kind, buf.toString(), new SourceFilePosition(file, new SourcePosition(lineNumber - 1, column, -1)));
addMessage(msg, messages);
} finally {
StringBuilderSpinAllocator.dispose(buf);
}
return true;
}
} catch (NumberFormatException ignored) {
}
}
}
if (line.endsWith("java.lang.OutOfMemoryError")) {
addMessage(new Message(Message.Kind.ERROR, "Out of memory.", SourceFilePosition.UNKNOWN), messages);
return true;
}
return false;
}
use of com.android.ide.common.blame.Message in project android by JetBrains.
the class BuildFailureParser method parse.
@Override
public boolean parse(@NotNull String line, @NotNull OutputLineReader reader, @NotNull List<Message> messages, @NotNull ILogger logger) throws ParsingFailedException {
State state = State.BEGINNING;
int pos = 0;
String currentLine = line;
SourceFile file = SourceFile.UNKNOWN;
SourcePosition position = SourcePosition.UNKNOWN;
String lastQuotedLine = null;
StringBuilder errorMessage = new StringBuilder();
Matcher matcher;
// some of the output. We should fall back to emitting all the output in that case.
while (true) {
switch(state) {
case BEGINNING:
if (WHERE_LINE_1.matcher(currentLine).matches()) {
state = State.WHERE;
} else if (!BEGINNING_PATTERNS[pos].matcher(currentLine).matches()) {
return false;
} else if (++pos >= BEGINNING_PATTERNS.length) {
state = State.MESSAGE;
}
break;
case WHERE:
matcher = WHERE_LINE_2.matcher(currentLine);
if (!matcher.matches()) {
return false;
}
file = new SourceFile(new File(matcher.group(1)));
position = new SourcePosition(Integer.parseInt(matcher.group(2)) - 1, 0, -1);
state = State.BEGINNING;
break;
case MESSAGE:
if (ENDING_PATTERNS[0].matcher(currentLine).matches()) {
state = State.ENDING;
pos = 1;
} else if (COMMAND_FAILURE_MESSAGE.matcher(currentLine).matches()) {
state = State.COMMAND_FAILURE_COMMAND_LINE;
} else if (COMPILE_FAILURE_MESSAGE.matcher(currentLine).matches()) {
state = State.COMPILE_FAILURE_OUTPUT;
// We don't need errorMessage anymore.
// Individual errors will be reported.
errorMessage.setLength(0);
} else {
// Determine whether the string starts with ">" (possibly indented by whitespace), and if so, where
int quoted = -1;
for (int i = 0, n = currentLine.length(); i < n; i++) {
char c = currentLine.charAt(i);
if (c == '>') {
quoted = i;
break;
} else if (!Character.isWhitespace(c)) {
break;
}
}
if (quoted != -1) {
if (currentLine.startsWith("> In DataSet ", quoted) && currentLine.contains("no data file for changedFile")) {
matcher = Pattern.compile("\\s*> In DataSet '.+', no data file for changedFile '(.+)'").matcher(currentLine);
if (matcher.find()) {
file = new SourceFile(new File(matcher.group(1)));
}
} else if (currentLine.startsWith("> Duplicate resources: ", quoted)) {
// For exact format, see com.android.ide.common.res2.DuplicateDataException
matcher = Pattern.compile("\\s*> Duplicate resources: (.+):(.+), (.+):(.+)\\s*").matcher(currentLine);
if (matcher.matches()) {
file = new SourceFile(new File(matcher.group(1)));
position = AbstractAaptOutputParser.findResourceLine(file.getSourceFile(), matcher.group(2), logger);
File other = new File(matcher.group(3));
SourcePosition otherPos = AbstractAaptOutputParser.findResourceLine(other, matcher.group(4), logger);
messages.add(new Message(Message.Kind.ERROR, currentLine, new SourceFilePosition(file, position), new SourceFilePosition(other, otherPos)));
// Skip appending to the errorMessage buffer; we've already added both locations to the message
break;
}
} else if (currentLine.startsWith("> Problems pinging owner of lock ", quoted)) {
String text = "Possibly unstable network connection: Failed to connect to lock owner. Try to rebuild.";
messages.add(new Message(Message.Kind.ERROR, text, SourceFilePosition.UNKNOWN));
}
}
boolean handledByDataBinding = myDataBindingParser.parse(currentLine, reader, messages, logger);
if (!handledByDataBinding) {
if (errorMessage.length() > 0) {
errorMessage.append("\n");
}
errorMessage.append(currentLine);
}
if (isGradleQuotedLine(currentLine)) {
lastQuotedLine = currentLine;
}
}
break;
case COMMAND_FAILURE_COMMAND_LINE:
// Gradle can put an unescaped "Android Studio" in its command-line output. (It doesn't care because this doesn't have to be
// a perfectly valid command line; it's just an error message). To keep it from messing up our parsing, let's convert those
// to "Android_Studio". If there are other spaces in the command-line path, though, it will mess up our parsing. Oh, well.
currentLine = currentLine.replaceAll("Android Studio", "Android_Studio");
matcher = COMMAND_LINE_PARSER.matcher(currentLine);
if (matcher.matches()) {
String message = String.format("Error while executing %s command", matcher.group(2));
messages.add(new Message(Message.Kind.ERROR, message, SourceFilePosition.UNKNOWN));
} else if (COMMAND_LINE_ERROR_OUTPUT.matcher(currentLine).matches()) {
state = State.COMMAND_FAILURE_OUTPUT;
} else if (ENDING_PATTERNS[0].matcher(currentLine).matches()) {
state = State.ENDING;
pos = 1;
}
break;
case COMMAND_FAILURE_OUTPUT:
if (ENDING_PATTERNS[0].matcher(currentLine).matches()) {
state = State.ENDING;
pos = 1;
} else {
currentLine = currentLine.trim();
if (!myAaptParser.parse(currentLine, reader, messages, logger)) {
// The AAPT parser punted on it. Just create a message with the unparsed error.
messages.add(new Message(Message.Kind.ERROR, currentLine, SourceFilePosition.UNKNOWN));
}
}
break;
case COMPILE_FAILURE_OUTPUT:
if (ENDING_PATTERNS[0].matcher(currentLine).matches()) {
state = State.ENDING;
pos = 1;
} else {
matcher = COMPILE_LINE_PARSER.matcher(currentLine);
if (matcher.matches()) {
file = new SourceFile(new File(matcher.group(1)));
position = new SourcePosition(Integer.parseInt(matcher.group(2)) - 1, Integer.parseInt(matcher.group(3)) - 1, 0);
String text = matcher.group(4);
String type = matcher.group(5);
Message.Kind kind = Message.Kind.UNKNOWN;
if (type.endsWith("error")) {
kind = Message.Kind.ERROR;
} else if (type.equals("warning")) {
kind = Message.Kind.WARNING;
} else if (type.equals("note")) {
kind = Message.Kind.INFO;
}
messages.add(new Message(kind, text, new SourceFilePosition(file, position)));
}
}
break;
case ENDING:
if (!ENDING_PATTERNS[pos].matcher(currentLine).matches()) {
return false;
} else if (++pos >= ENDING_PATTERNS.length) {
if (errorMessage.length() > 0) {
String text = errorMessage.toString();
// duplicate resources.
if (SourceFile.UNKNOWN.equals(file) && lastQuotedLine != null) {
String msg = unquoteGradleLine(lastQuotedLine);
Message rootCause = findRootCause(msg, messages);
if (rootCause == null) {
// Try searching there instead.
if (msg.endsWith("Failed to run command:")) {
String[] lines = text.split("\n");
if (lines.length > 2 && lines[lines.length - 2].contains("Output:")) {
String lastLine = lines[lines.length - 1];
if (!lastLine.isEmpty()) {
rootCause = findRootCause(lastLine.trim(), messages);
}
}
}
}
if (rootCause != null) {
if (!rootCause.getSourceFilePositions().isEmpty()) {
SourceFilePosition sourceFilePosition = rootCause.getSourceFilePositions().get(0);
file = sourceFilePosition.getFile();
position = sourceFilePosition.getPosition();
}
}
}
if (!SourceFile.UNKNOWN.equals(file)) {
messages.add(new Message(Message.Kind.ERROR, text, new SourceFilePosition(file, position)));
} else if (text.contains("Build cancelled")) {
// Gradle throws an exception (BuildCancelledException) when we cancel task processing
// (org.gradle.tooling.CancellationTokenSource.cancel()). We don't want to report that as an error though.
messages.add(new Message(Message.Kind.INFO, text, SourceFilePosition.UNKNOWN));
} else {
messages.add(new Message(Message.Kind.ERROR, text, SourceFilePosition.UNKNOWN));
}
}
return true;
}
break;
}
while (true) {
currentLine = reader.readLine();
if (currentLine == null) {
return false;
}
if (!currentLine.trim().isEmpty()) {
break;
}
}
}
}
use of com.android.ide.common.blame.Message in project android by JetBrains.
the class DataBindingOutputParser method parseErrorIn.
private static boolean parseErrorIn(@NotNull String output, @NotNull List<Message> messages) {
String message;
String file = "";
List<Location> locations = new ArrayList<Location>();
int msgStart = output.indexOf(MSG_KEY);
if (msgStart < 0) {
message = output;
} else {
int fileStart = output.indexOf(FILE_KEY, msgStart + MSG_KEY.length());
if (fileStart < 0) {
message = output;
} else {
message = output.substring(msgStart + MSG_KEY.length(), fileStart);
int locStart = output.indexOf(LOCATION_KEY, fileStart + FILE_KEY.length());
if (locStart < 0) {
file = output.substring(fileStart + FILE_KEY.length()).trim();
} else {
file = output.substring(fileStart + FILE_KEY.length(), locStart).trim();
int nextLoc = 0;
while (nextLoc >= 0) {
nextLoc = output.indexOf(LOCATION_KEY, locStart + LOCATION_KEY.length());
Location loc;
if (nextLoc < 0) {
loc = Location.fromUserReadableString(output.substring(locStart + LOCATION_KEY.length()));
} else {
loc = Location.fromUserReadableString(output.substring(locStart + LOCATION_KEY.length(), nextLoc));
}
if (loc.isValid()) {
locations.add(loc);
}
locStart = nextLoc;
}
}
}
}
if (StringUtil.isEmpty(file)) {
return false;
}
List<SourceFilePosition> sourceFilePositions = new ArrayList<SourceFilePosition>();
File sourceFile = new File(file);
if (locations.size() == 0) {
messages.add(new Message(Message.Kind.ERROR, message, SourceFilePosition.UNKNOWN));
} else {
for (Location location : locations) {
sourceFilePositions.add(new SourceFilePosition(sourceFile, new SourcePosition(location.startLine, location.startOffset, 0, location.endLine, location.endOffset, 0)));
}
SourceFilePosition first = sourceFilePositions.get(0);
if (locations.size() == 1) {
messages.add(new Message(Message.Kind.ERROR, message, first));
} else {
SourceFilePosition[] rest = new SourceFilePosition[sourceFilePositions.size() - 1];
for (int i = 1; i < sourceFilePositions.size(); i++) {
rest[i - 1] = sourceFilePositions.get(i);
}
messages.add(new Message(Message.Kind.ERROR, message, first, rest));
}
}
return true;
}
use of com.android.ide.common.blame.Message in project android by JetBrains.
the class BuildOutputParserTest method parseParsedBuildIssue.
@Test
public void parseParsedBuildIssue() throws IOException {
// Do not run tests on Windows (see http://b.android.com/222904)
assumeFalse(SystemInfo.isWindows);
String output = "AGPBI: {\"kind\":\"ERROR\",\"text\":\"" + "No resource identifier found for attribute \\u0027a\\u0027 in package" + " \\u0027android\\u0027\",\"sourcePath\":\"/usr/local/google/home/cmw/" + "udacity/Sunshine/app/src/main/res/menu/detail.xml\",\"position\":" + "{\"startLine\":5},\"original\":\"\"}";
List<Message> Messages = parser.parseGradleOutput(output);
assertEquals("Expect one message.", 1, Messages.size());
Message message = Messages.iterator().next();
assertEquals("No resource identifier found for attribute 'a' in package 'android'", message.getText());
assertEquals(Message.Kind.ERROR, message.getKind());
assertEquals("/usr/local/google/home/cmw/udacity/Sunshine/app/src/main/res/menu/detail.xml", message.getSourcePath());
assertEquals(new SourcePosition(5, -1, -1), message.getSourceFilePositions().get(0).getPosition());
}
use of com.android.ide.common.blame.Message in project android by JetBrains.
the class BuildOutputParserTest method redirectValueLinksOutput.
@Test
public void redirectValueLinksOutput() throws Exception {
// Do not run tests on Windows (see http://b.android.com/222904)
assumeFalse(SystemInfo.isWindows);
TestResources.getFileInDirectory(getClass(), "/values.xml", "src/test/resources/testData/resources/baseSet/values/values.xml");
// Need file to be named (exactly) values.xml
File tempDir = Files.createTempDir();
File valueDir = new File(tempDir, "values-en");
valueDir.mkdirs();
// Keep in sync with MergedResourceWriter.FN_VALUES_XML
sourceFile = new File(valueDir, "values.xml");
sourceFilePath = sourceFile.getAbsolutePath();
writeToFile("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<resources xmlns:ns1=\"urn:oasis:names:tc:xliff:document:1.2\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + " xmlns:alias_for_tools=\"http://schemas.android.com/tools\">\n" + "\n" + " <!-- From: src/test/resources/testData/resources/baseSet/values/values.xml -->\n" + " <string-array name=\"string_array\" translatable=\"false\">\n" + " <item/> <!-- 0 -->\n" + " <item/> <!-- 1 -->\n" + " <item>ABC</item> <!-- 2 -->\n" + " <item>DEF</item> <!-- 3 -->\n" + " <item>GHI</item> <!-- 4 -->\n" + " <item>JKL</item> <!-- 5 -->\n" + " <item>MNO</item> <!-- 6 -->\n" + " <item>PQRS</item> <!-- 7 -->\n" + " <item>TUV</item> <!-- 8 -->\n" + " <item>WXYZ</item> <!-- 9 -->\n" + " </string-array>\n" + "\n" + " <attr name=\"dimen_attr\" format=\"dimension\" />\n" + " <attr name=\"enum_attr\">\n" + " <enum name=\"normal\" value=\"0\" />\n" + " <enum name=\"sans\" value=\"1\" />\n" + " <enum name=\"serif\" value=\"2\" />\n" + " <enum name=\"monospace\" value=\"3\" />\n" + " </attr>\n" + " <attr name=\"flag_attr\">\n" + " <flag name=\"normal\" value=\"0\" />\n" + " <flag name=\"bold\" value=\"1\" />\n" + " <flag name=\"italic\" value=\"2\" />\n" + " </attr>\n" + " <attr name=\"string_attr\" format=\"string\" />\n" + " <!-- From: src/test/resources/testData/resources/baseMerge/overlay/values/values.xml -->\n" + " <color name=\"color\">#FFFFFFFF</color>\n" + " <!-- From: src/test/resources/testData/resources/baseSet/values/values.xml -->\n" + " <declare-styleable name=\"declare_styleable\">\n" + "\n" + " <!-- ============== -->\n" + " <!-- Generic styles -->\n" + " <!-- ============== -->\n" + " <eat-comment />\n" + "\n" + " <!-- Default color of foreground imagery. -->\n" + " <attr name=\"blah\" format=\"color\" />\n" + " <!-- Default color of foreground imagery on an inverted background. -->\n" + " <attr name=\"android:colorForegroundInverse\" />\n" + " </declare-styleable>\n" + "\n" + " <dimen name=\"dimen\">164dp</dimen>\n" + "\n" + " <drawable name=\"color_drawable\">#ffffffff</drawable>\n" + " <drawable name=\"drawable_ref\">@drawable/stat_notify_sync_anim0</drawable>\n" + "\n" + " <item name=\"item_id\" type=\"id\"/>\n" + "\n" + " <integer name=\"integer\">75</integer>\n" + " <!-- From: src/test/resources/testData/resources/baseMerge/overlay/values/values.xml -->\n" + " <item name=\"file_replaced_by_alias\" type=\"layout\">@layout/ref</item>\n" + " <!-- From: src/test/resources/testData/resources/baseSet/values/values.xml -->\n" + " <item name=\"layout_ref\" type=\"layout\">@layout/ref</item>\n" + " <!-- From: src/test/resources/testData/resources/baseMerge/overlay/values/values.xml -->\n" + " <string name=\"basic_string\">overlay_string</string>\n" + " <!-- From: src/test/resources/testData/resources/baseSet/values/values.xml -->\n" + " <string name=\"styled_string\">Forgot your username or password\\?\\nVisit <b>google.com/accounts/recovery</b>.</string>\n" + " <string name=\"xliff_string\"><ns1:g id=\"number\" example=\"123\">%1$s</ns1:g><ns1:g id=\"unit\" example=\"KB\">%2$s</ns1:g></string>\n" + "\n" + " <style name=\"style\" parent=\"@android:style/Holo.Light\">\n" + " <item name=\"android:singleLine\">true</item>\n" + " <item name=\"android:textAppearance\">@style/TextAppearance.WindowTitle</item>\n" + " <item name=\"android:shadowColor\">#BB000000</item>\n" + " <item name=\"android:shadowRadius\">2.75</item>\n" + " <item name=\"foo\">foo</item>\n" + " </style>\n" + "\n" + "</resources>\n");
String messageText = "String types not allowed (at 'drawable_ref' with value '@drawable/stat_notify_sync_anim0').";
String err = sourceFilePath + ":46: error: Error: " + messageText;
Collection<Message> messages = parser.parseGradleOutput(err);
assertEquals(1, messages.size());
assertEquals("[message count]", 1, messages.size());
Message message = ContainerUtil.getFirstItem(messages);
assertNotNull(message);
// NOT sourceFilePath; should be translated back from source comment
assertEquals("[file path]", "src/test/resources/testData/resources/baseSet/values/values.xml", getSystemIndependentSourcePath(message));
assertEquals("[message severity]", Message.Kind.ERROR, message.getKind());
assertEquals("[message text]", messageText, message.getText());
assertEquals("[position line]", 11, message.getLineNumber());
assertEquals("[position column]", 35, message.getColumn());
}
Aggregations