diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build')
31 files changed, 0 insertions, 9083 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptExecException.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptExecException.java deleted file mode 100644 index 23b1baa92..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptExecException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2010 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; - -/** - * Exception thrown when the execution of aapt fails. - * - */ -public final class AaptExecException extends Exception { - private static final long serialVersionUID = 1L; - - AaptExecException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptParser.java deleted file mode 100644 index 1f17fb7c6..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptParser.java +++ /dev/null @@ -1,783 +0,0 @@ -/* - * Copyright (C) 2010 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.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; - -import org.eclipse.core.resources.IFile; -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.jface.text.FindReplaceDocumentAdapter; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.Region; -import org.eclipse.ui.editors.text.TextFileDocumentProvider; -import org.eclipse.ui.texteditor.IDocumentProvider; - -import java.io.File; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public final class AaptParser { - - // TODO: rename the pattern to something that makes sense + javadoc comments. - /** - * Single line aapt warning for skipping files.<br> - * " (skipping hidden file '<file path>'" - */ - private final static Pattern sPattern0Line1 = Pattern.compile( - "^\\s+\\(skipping hidden file\\s'(.*)'\\)$"); //$NON-NLS-1$ - - /** - * First line of dual line aapt error.<br> - * "ERROR at line <line>: <error>"<br> - * " (Occurred while parsing <path>)" - */ - private final static Pattern sPattern1Line1 = Pattern.compile( - "^ERROR\\s+at\\s+line\\s+(\\d+):\\s+(.*)$"); //$NON-NLS-1$ - /** - * Second line of dual line aapt error.<br> - * "ERROR at line <line>: <error>"<br> - * " (Occurred while parsing <path>)"<br> - * @see #sPattern1Line1 - */ - private final static Pattern sPattern1Line2 = Pattern.compile( - "^\\s+\\(Occurred while parsing\\s+(.*)\\)$"); //$NON-NLS-1$ - /** - * First line of dual line aapt error.<br> - * "ERROR: <error>"<br> - * "Defined at file <path> line <line>" - */ - private final static Pattern sPattern2Line1 = Pattern.compile( - "^ERROR:\\s+(.+)$"); //$NON-NLS-1$ - /** - * Second line of dual line aapt error.<br> - * "ERROR: <error>"<br> - * "Defined at file <path> line <line>"<br> - * @see #sPattern2Line1 - */ - private final static Pattern sPattern2Line2 = Pattern.compile( - "Defined\\s+at\\s+file\\s+(.+)\\s+line\\s+(\\d+)"); //$NON-NLS-1$ - /** - * Single line aapt error<br> - * "<path> line <line>: <error>" - */ - private final static Pattern sPattern3Line1 = Pattern.compile( - "^(.+)\\sline\\s(\\d+):\\s(.+)$"); //$NON-NLS-1$ - /** - * First line of dual line aapt error.<br> - * "ERROR parsing XML file <path>"<br> - * "<error> at line <line>" - */ - private final static Pattern sPattern4Line1 = Pattern.compile( - "^Error\\s+parsing\\s+XML\\s+file\\s(.+)$"); //$NON-NLS-1$ - /** - * Second line of dual line aapt error.<br> - * "ERROR parsing XML file <path>"<br> - * "<error> at line <line>"<br> - * @see #sPattern4Line1 - */ - private final static Pattern sPattern4Line2 = Pattern.compile( - "^(.+)\\s+at\\s+line\\s+(\\d+)$"); //$NON-NLS-1$ - - /** - * Single line aapt warning<br> - * "<path>:<line>: <error>" - */ - private final static Pattern sPattern5Line1 = Pattern.compile( - "^(.+?):(\\d+):\\s+WARNING:(.+)$"); //$NON-NLS-1$ - - /** - * Single line aapt error<br> - * "<path>:<line>: <error>" - */ - private final static Pattern sPattern6Line1 = Pattern.compile( - "^(.+?):(\\d+):\\s+(.+)$"); //$NON-NLS-1$ - - /** - * 4 line aapt error<br> - * "ERROR: 9-path image <path> malformed"<br> - * Line 2 and 3 are taken as-is while line 4 is ignored (it repeats with<br> - * 'ERROR: failure processing <path>) - */ - private final static Pattern sPattern7Line1 = Pattern.compile( - "^ERROR:\\s+9-patch\\s+image\\s+(.+)\\s+malformed\\.$"); //$NON-NLS-1$ - - private final static Pattern sPattern8Line1 = Pattern.compile( - "^(invalid resource directory name): (.*)$"); //$NON-NLS-1$ - - /** - * Portion of the error message which states the context in which the error occurred, - * such as which property was being processed and what the string value was that - * caused the error. - * <p> - * Example: - * error: No resource found that matches the given name (at 'text' with value '@string/foo') - */ - private static final Pattern sValueRangePattern = - Pattern.compile("\\(at '(.+)' with value '(.*)'\\)"); //$NON-NLS-1$ - - - /** - * Portion of error message which points to the second occurrence of a repeated resource - * definition. - * <p> - * Example: - * error: Resource entry repeatedStyle1 already has bag item android:gravity. - */ - private static final Pattern sRepeatedRangePattern = - Pattern.compile("Resource entry (.+) already has bag item (.+)\\."); //$NON-NLS-1$ - - /** - * Error message emitted when aapt skips a file because for example it's name is - * invalid, such as a layout file name which starts with _. - * <p> - * This error message is used by AAPT in Tools 19 and earlier. - */ - private static final Pattern sSkippingPattern = - Pattern.compile(" \\(skipping (.+) .+ '(.*)'\\)"); //$NON-NLS-1$ - - /** - * Error message emitted when aapt skips a file because for example it's name is - * invalid, such as a layout file name which starts with _. - * <p> - * This error message is used by AAPT in Tools 20 and later. - */ - private static final Pattern sNewSkippingPattern = - Pattern.compile(" \\(skipping .+ '(.+)' due to ANDROID_AAPT_IGNORE pattern '.+'\\)"); //$NON-NLS-1$ - - /** - * Suffix of error message which points to the first occurrence of a repeated resource - * definition. - * Example: - * Originally defined here. - */ - private static final String ORIGINALLY_DEFINED_MSG = "Originally defined here."; //$NON-NLS-1$ - - /** - * Portion of error message which points to the second occurrence of a repeated resource - * definition. - * <p> - * Example: - * error: Resource entry repeatedStyle1 already has bag item android:gravity. - */ - private static final Pattern sNoResourcePattern = - Pattern.compile("No resource found that matches the given name: attr '(.+)'\\."); //$NON-NLS-1$ - - /** - * Portion of error message which points to a missing required attribute in a - * resource definition. - * <p> - * Example: - * error: error: A 'name' attribute is required for <style> - */ - private static final Pattern sRequiredPattern = - Pattern.compile("A '(.+)' attribute is required for <(.+)>"); //$NON-NLS-1$ - - /** - * 2 line aapt error<br> - * "ERROR: Invalid configuration: foo"<br> - * " ^^^"<br> - * There's no need to parse the 2nd line. - */ - private final static Pattern sPattern9Line1 = Pattern.compile( - "^Invalid configuration: (.+)$"); //$NON-NLS-1$ - - private final static Pattern sXmlBlockPattern = Pattern.compile( - "W/ResourceType\\(.*\\): Bad XML block: no root element node found"); //$NON-NLS-1$ - - /** - * Parse the output of aapt and mark the incorrect file with error markers - * - * @param results the output of aapt - * @param project the project containing the file to mark - * @return true if the parsing failed, false if success. - */ - public static boolean parseOutput(List<String> results, IProject project) { - int size = results.size(); - if (size > 0) { - return parseOutput(results.toArray(new String[size]), project); - } - - return false; - } - - /** - * Parse the output of aapt and mark the incorrect file with error markers - * - * @param results the output of aapt - * @param project the project containing the file to mark - * @return true if the parsing failed, false if success. - */ - public static boolean parseOutput(String[] results, IProject project) { - // nothing to parse? just return false; - if (results.length == 0) { - return false; - } - - // get the root of the project so that we can make IFile from full - // file path - String osRoot = project.getLocation().toOSString(); - - Matcher m; - - for (int i = 0; i < results.length ; i++) { - String p = results[i]; - - m = sPattern0Line1.matcher(p); - if (m.matches()) { - // we ignore those (as this is an ignore message from aapt) - continue; - } - - m = sPattern1Line1.matcher(p); - if (m.matches()) { - String lineStr = m.group(1); - String msg = m.group(2); - - // get the matcher for the next line. - m = getNextLineMatcher(results, ++i, sPattern1Line2); - if (m == null) { - return true; - } - - String location = m.group(1); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, project, - AdtConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) { - return true; - } - continue; - } - - // this needs to be tested before Pattern2 since they both start with 'ERROR:' - m = sPattern7Line1.matcher(p); - if (m.matches()) { - String location = m.group(1); - String msg = p; // default msg is the line in case we don't find anything else - - if (++i < results.length) { - msg = results[i].trim(); - if (++i < results.length) { - msg = msg + " - " + results[i].trim(); //$NON-NLS-1$ - - // skip the next line - i++; - } - } - - // display the error - if (checkAndMark(location, null, msg, osRoot, project, - AdtConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sPattern2Line1.matcher(p); - if (m.matches()) { - // get the msg - String msg = m.group(1); - - // get the matcher for the next line. - m = getNextLineMatcher(results, ++i, sPattern2Line2); - if (m == null) { - return true; - } - - String location = m.group(1); - String lineStr = m.group(2); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, project, - AdtConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) { - return true; - } - continue; - } - - m = sPattern3Line1.matcher(p); - if (m.matches()) { - String location = m.group(1); - String lineStr = m.group(2); - String msg = m.group(3); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, project, - AdtConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sPattern4Line1.matcher(p); - if (m.matches()) { - // get the filename. - String location = m.group(1); - - // get the matcher for the next line. - m = getNextLineMatcher(results, ++i, sPattern4Line2); - if (m == null) { - return true; - } - - String msg = m.group(1); - String lineStr = m.group(2); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, project, - AdtConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sPattern5Line1.matcher(p); - if (m.matches()) { - String location = m.group(1); - String lineStr = m.group(2); - String msg = m.group(3); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, project, - AdtConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_WARNING) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sPattern6Line1.matcher(p); - if (m.matches()) { - String location = m.group(1); - String lineStr = m.group(2); - String msg = m.group(3); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, project, - AdtConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sPattern8Line1.matcher(p); - if (m.matches()) { - String location = m.group(2); - String msg = m.group(1); - - // check the values and attempt to mark the file. - if (checkAndMark(location, null, msg, osRoot, project, - AdtConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sPattern9Line1.matcher(p); - if (m.matches()) { - String badConfig = m.group(1); - String msg = String.format("APK Configuration filter '%1$s' is invalid", badConfig); - - // skip the next line - i++; - - // check the values and attempt to mark the file. - if (checkAndMark(null /*location*/, null, msg, osRoot, project, - AdtConstants.MARKER_AAPT_PACKAGE, IMarker.SEVERITY_ERROR) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sNewSkippingPattern.matcher(p); - if (m.matches()) { - String location = m.group(1); - - if (location.startsWith(".") //$NON-NLS-1$ - || location.endsWith("~")) { //$NON-NLS-1$ - continue; - } - - // check the values and attempt to mark the file. - if (checkAndMark(location, null, p.trim(), osRoot, project, - AdtConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_WARNING) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sSkippingPattern.matcher(p); - if (m.matches()) { - String location = m.group(2); - - // Certain files can safely be skipped without marking the project - // as having errors. See isHidden() in AaptAssets.cpp: - String type = m.group(1); - if (type.equals("backup") //$NON-NLS-1$ // main.xml~, etc - || type.equals("hidden") //$NON-NLS-1$ // .gitignore, etc - || type.equals("index")) { //$NON-NLS-1$ // thumbs.db, etc - continue; - } - - // check the values and attempt to mark the file. - if (checkAndMark(location, null, p.trim(), osRoot, project, - AdtConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_WARNING) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sXmlBlockPattern.matcher(p); - if (m.matches()) { - // W/ResourceType(12345): Bad XML block: no root element node found - // Sadly there's NO filename reference; this error typically describes the - // error *after* this line. - if (results.length == 1) { - // This is the only error message: dump to console and quit - return true; - } - // Continue: the real culprit is displayed next and should get a marker - continue; - } - - return true; - } - - return false; - } - - /** - * Check if the parameters gotten from the error output are valid, and mark - * the file with an AAPT marker. - * @param location the full OS path of the error file. If null, the project is marked - * @param lineStr - * @param message - * @param root The root directory of the project, in OS specific format. - * @param project - * @param markerId The marker id to put. - * @param severity The severity of the marker to put (IMarker.SEVERITY_*) - * @return true if the parameters were valid and the file was marked successfully. - * - * @see IMarker - */ - private static final boolean checkAndMark(String location, String lineStr, - String message, String root, IProject project, String markerId, int severity) { - // check this is in fact a file - if (location != null) { - File f = new File(location); - if (f.exists() == false) { - return false; - } - } - - // get the line number - int line = -1; // default value for error with no line. - - if (lineStr != null) { - 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 false; - } - } - - // add the marker - IResource f2 = project; - if (location != null) { - f2 = getResourceFromFullPath(location, root, project); - if (f2 == null) { - return false; - } - } - - // Attempt to determine the exact range of characters affected by this error. - // This will look up the actual text of the file, go to the particular error line - // and scan for the specific string mentioned in the error. - int startOffset = -1; - int endOffset = -1; - if (f2 instanceof IFile) { - IRegion region = findRange((IFile) f2, line, message); - if (region != null) { - startOffset = region.getOffset(); - endOffset = startOffset + region.getLength(); - } - } - - // check if there's a similar marker already, since aapt is launched twice - boolean markerAlreadyExists = false; - try { - IMarker[] markers = f2.findMarkers(markerId, true, IResource.DEPTH_ZERO); - - for (IMarker marker : markers) { - if (startOffset != -1) { - int tmpBegin = marker.getAttribute(IMarker.CHAR_START, -1); - if (tmpBegin != startOffset) { - break; - } - int tmpEnd = marker.getAttribute(IMarker.CHAR_END, -1); - if (tmpEnd != startOffset) { - break; - } - } - - int tmpLine = marker.getAttribute(IMarker.LINE_NUMBER, -1); - if (tmpLine != line) { - break; - } - - int tmpSeverity = marker.getAttribute(IMarker.SEVERITY, -1); - if (tmpSeverity != severity) { - break; - } - - String tmpMsg = marker.getAttribute(IMarker.MESSAGE, null); - if (tmpMsg == null || tmpMsg.equals(message) == false) { - break; - } - - // if we're here, all the marker attributes are equals, we found it - // and exit - markerAlreadyExists = true; - break; - } - - } catch (CoreException e) { - // if we couldn't get the markers, then we just mark the file again - // (since markerAlreadyExists is initialized to false, we do nothing) - } - - if (markerAlreadyExists == false) { - BaseProjectHelper.markResource(f2, markerId, message, line, - startOffset, endOffset, severity); - } - - return true; - } - - /** - * Given an aapt error message in a given file and a given (initial) line number, - * return the corresponding offset range for the error, or null. - */ - private static IRegion findRange(IFile file, int line, String message) { - Matcher matcher = sValueRangePattern.matcher(message); - if (matcher.find()) { - String property = matcher.group(1); - String value = matcher.group(2); - - // First find the property. We can't just immediately look for the - // value, because there could be other attributes in this element - // earlier than the one in error, and we might accidentally pick - // up on a different occurrence of the value in a context where - // it is valid. - if (value.length() > 0) { - return findRange(file, line, property, value); - } else { - // Find first occurrence of property followed by '' or "" - IRegion region1 = findRange(file, line, property, "\"\""); //$NON-NLS-1$ - IRegion region2 = findRange(file, line, property, "''"); //$NON-NLS-1$ - if (region1 == null) { - if (region2 == null) { - // Highlight the property instead - return findRange(file, line, property, null); - } - return region2; - } else if (region2 == null) { - return region1; - } else if (region1.getOffset() < region2.getOffset()) { - return region1; - } else { - return region2; - } - } - } - - matcher = sRepeatedRangePattern.matcher(message); - if (matcher.find()) { - String property = matcher.group(2); - return findRange(file, line, property, null); - } - - matcher = sNoResourcePattern.matcher(message); - if (matcher.find()) { - String property = matcher.group(1); - return findRange(file, line, property, null); - } - - matcher = sRequiredPattern.matcher(message); - if (matcher.find()) { - String elementName = matcher.group(2); - IRegion region = findRange(file, line, '<' + elementName, null); - if (region != null && region.getLength() > 1) { - // Skip the opening < - region = new Region(region.getOffset() + 1, region.getLength() - 1); - } - return region; - } - - if (message.endsWith(ORIGINALLY_DEFINED_MSG)) { - return findLineTextRange(file, line); - } - - return null; - } - - /** - * Given a file and line number, return the range of the first match starting on the - * given line. If second is non null, also search for the second string starting at he - * location of the first string. - */ - private static IRegion findRange(IFile file, int line, String first, - String second) { - IRegion region = null; - IDocumentProvider provider = new TextFileDocumentProvider(); - try { - provider.connect(file); - IDocument document = provider.getDocument(file); - if (document != null) { - IRegion lineInfo = document.getLineInformation(line - 1); - int lineStartOffset = lineInfo.getOffset(); - // The aapt errors will be anchored on the line where the - // element starts - which means that with formatting where - // attributes end up on subsequent lines we don't find it on - // the error line indicated by aapt. - // Therefore, search forwards in the document. - FindReplaceDocumentAdapter adapter = - new FindReplaceDocumentAdapter(document); - - region = adapter.find(lineStartOffset, first, - true /*forwardSearch*/, true /*caseSensitive*/, - false /*wholeWord*/, false /*regExSearch*/); - if (region != null && second != null) { - region = adapter.find(region.getOffset() + first.length(), second, - true /*forwardSearch*/, true /*caseSensitive*/, - false /*wholeWord*/, false /*regExSearch*/); - } - } - } catch (Exception e) { - AdtPlugin.log(e, "Can't find range information for %1$s", file.getName()); - } finally { - provider.disconnect(file); - } - return region; - } - - /** Returns the non-whitespace line range at the given line number. */ - private static IRegion findLineTextRange(IFile file, int line) { - IDocumentProvider provider = new TextFileDocumentProvider(); - try { - provider.connect(file); - IDocument document = provider.getDocument(file); - if (document != null) { - IRegion lineInfo = document.getLineInformation(line - 1); - String lineContents = document.get(lineInfo.getOffset(), lineInfo.getLength()); - int lineBegin = 0; - int lineEnd = lineContents.length()-1; - - for (; lineEnd >= 0; lineEnd--) { - char c = lineContents.charAt(lineEnd); - if (!Character.isWhitespace(c)) { - break; - } - } - lineEnd++; - for (; lineBegin < lineEnd; lineBegin++) { - char c = lineContents.charAt(lineBegin); - if (!Character.isWhitespace(c)) { - break; - } - } - if (lineBegin < lineEnd) { - return new Region(lineInfo.getOffset() + lineBegin, lineEnd - lineBegin); - } - } - } catch (Exception e) { - AdtPlugin.log(e, "Can't find range information for %1$s", file.getName()); - } finally { - provider.disconnect(file); - } - - return null; - } - - /** - * Returns a matching matcher for the next line - * @param lines The array of lines - * @param nextIndex The index of the next line - * @param pattern The pattern to match - * @return null if error or no match, the matcher otherwise. - */ - private static final Matcher getNextLineMatcher(String[] lines, - int nextIndex, Pattern pattern) { - // unless we can't, because we reached the last line - if (nextIndex == lines.length) { - // we expected a 2nd line, so we flag as error - // and we bail - return null; - } - - Matcher m = pattern.matcher(lines[nextIndex]); - if (m.matches()) { - return m; - } - - return null; - } - - private static IResource getResourceFromFullPath(String filename, String root, - IProject project) { - if (filename.startsWith(root)) { - String file = filename.substring(root.length()); - - // get the resource - IResource r = project.findMember(file); - - // if the resource is valid, we add the marker - if (r != null && r.exists()) { - return r; - } - } - - return null; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java deleted file mode 100644 index 3db380832..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * 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 static com.android.SdkConstants.ANDROID_URI; -import static com.android.SdkConstants.XMLNS_ANDROID; -import static com.android.SdkConstants.XMLNS_URI; - -import com.android.ide.common.resources.ResourceUrl; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AdtUtils; -import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; -import com.android.ide.eclipse.adt.internal.resources.ResourceHelper; -import com.android.resources.ResourceType; -import com.android.utils.Pair; - -import org.eclipse.core.resources.IFile; -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.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.Region; -import org.eclipse.jface.text.contentassist.ICompletionProposal; -import org.eclipse.jface.text.contentassist.IContextInformation; -import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext; -import org.eclipse.jface.text.quickassist.IQuickAssistProcessor; -import org.eclipse.jface.text.source.Annotation; -import org.eclipse.jface.text.source.ISourceViewer; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Point; -import org.eclipse.ui.IMarkerResolution; -import org.eclipse.ui.IMarkerResolution2; -import org.eclipse.ui.IMarkerResolutionGenerator2; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.editors.text.TextFileDocumentProvider; -import org.eclipse.ui.texteditor.IDocumentProvider; -import org.eclipse.wst.sse.core.StructuredModelManager; -import org.eclipse.wst.sse.core.internal.provisional.IModelManager; -import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; -import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; -import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import java.util.List; - -/** - * Shared handler for both quick assist processors (Control key handler) and quick fix - * marker resolution (Problem view handling), since there is a lot of overlap between - * these two UI handlers. - */ -@SuppressWarnings("restriction") // XML model -public class AaptQuickFix implements IMarkerResolutionGenerator2, IQuickAssistProcessor { - - public AaptQuickFix() { - } - - /** Returns the error message from aapt that signals missing resources */ - private static String getTargetMarkerErrorMessage() { - return "No resource found that matches the given name"; - } - - /** Returns the error message from aapt that signals a missing namespace declaration */ - private static String getUnboundErrorMessage() { - return "Error parsing XML: unbound prefix"; - } - - // ---- Implements IMarkerResolution2 ---- - - @Override - public boolean hasResolutions(IMarker marker) { - String message = null; - try { - message = (String) marker.getAttribute(IMarker.MESSAGE); - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - - return message != null - && (message.contains(getTargetMarkerErrorMessage()) - || message.contains(getUnboundErrorMessage())); - } - - @Override - public IMarkerResolution[] getResolutions(IMarker marker) { - IResource markerResource = marker.getResource(); - IProject project = markerResource.getProject(); - try { - String message = (String) marker.getAttribute(IMarker.MESSAGE); - if (message.contains(getUnboundErrorMessage()) && markerResource instanceof IFile) { - return new IMarkerResolution[] { - new CreateNamespaceFix((IFile) markerResource) - }; - } - } catch (CoreException e1) { - AdtPlugin.log(e1, null); - } - - int start = marker.getAttribute(IMarker.CHAR_START, 0); - int end = marker.getAttribute(IMarker.CHAR_END, 0); - if (end > start) { - int length = end - start; - IDocumentProvider provider = new TextFileDocumentProvider(); - try { - provider.connect(markerResource); - IDocument document = provider.getDocument(markerResource); - String resource = document.get(start, length); - if (ResourceHelper.canCreateResource(resource)) { - return new IMarkerResolution[] { - new CreateResourceProposal(project, resource) - }; - } - } catch (Exception e) { - AdtPlugin.log(e, "Can't find range information for %1$s", markerResource); - } finally { - provider.disconnect(markerResource); - } - } - - return null; - } - - // ---- Implements IQuickAssistProcessor ---- - - @Override - public boolean canAssist(IQuickAssistInvocationContext invocationContext) { - return true; - } - - @Override - public boolean canFix(Annotation annotation) { - return true; - } - - @Override - public ICompletionProposal[] computeQuickAssistProposals( - IQuickAssistInvocationContext invocationContext) { - - // We have to find the corresponding project/file (so we can look up the aapt - // error markers). Unfortunately, an IQuickAssistProcessor only gets - // access to an ISourceViewer which has no hooks back to the surrounding - // editor. - // - // However, the IQuickAssistProcessor will only be used interactively by a file - // being edited, so we can cheat like the hyperlink detector and simply - // look up the currently active file in the IDE. To be on the safe side, - // we'll make sure that that editor has the same sourceViewer such that - // we are indeed looking at the right file: - ISourceViewer sourceViewer = invocationContext.getSourceViewer(); - AndroidXmlEditor editor = AndroidXmlEditor.fromTextViewer(sourceViewer); - if (editor != null) { - IFile file = editor.getInputFile(); - if (file == null) { - return null; - } - IDocument document = sourceViewer.getDocument(); - List<IMarker> markers = AdtUtils.findMarkersOnLine(AdtConstants.MARKER_AAPT_COMPILE, - file, document, invocationContext.getOffset()); - try { - for (IMarker marker : markers) { - String message = marker.getAttribute(IMarker.MESSAGE, ""); //$NON-NLS-1$ - if (message.contains(getTargetMarkerErrorMessage())) { - int start = marker.getAttribute(IMarker.CHAR_START, 0); - int end = marker.getAttribute(IMarker.CHAR_END, 0); - int length = end - start; - String resource = document.get(start, length); - // Can only offer create value for non-framework value - // resources - if (ResourceHelper.canCreateResource(resource)) { - IProject project = editor.getProject(); - return new ICompletionProposal[] { - new CreateResourceProposal(project, resource) - }; - } - } else if (message.contains(getUnboundErrorMessage())) { - return new ICompletionProposal[] { - new CreateNamespaceFix(null) - }; - } - } - } catch (BadLocationException e) { - AdtPlugin.log(e, null); - } - } - - return null; - } - - @Override - public String getErrorMessage() { - return null; - } - - /** Quick fix to insert namespace binding when missing */ - private final static class CreateNamespaceFix - implements ICompletionProposal, IMarkerResolution2 { - private IFile mFile; - - public CreateNamespaceFix(IFile file) { - mFile = file; - } - - private IndexedRegion perform(IDocument doc) { - IModelManager manager = StructuredModelManager.getModelManager(); - IStructuredModel model = manager.getExistingModelForEdit(doc); - if (model != null) { - try { - perform(model); - } finally { - model.releaseFromEdit(); - } - } - - return null; - } - - private IndexedRegion perform(IFile file) { - IModelManager manager = StructuredModelManager.getModelManager(); - IStructuredModel model; - try { - model = manager.getModelForEdit(file); - if (model != null) { - try { - perform(model); - } finally { - model.releaseFromEdit(); - } - } - } catch (Exception e) { - AdtPlugin.log(e, "Can't look up XML model"); - } - - return null; - } - - private IndexedRegion perform(IStructuredModel model) { - if (model instanceof IDOMModel) { - IDOMModel domModel = (IDOMModel) model; - Document document = domModel.getDocument(); - Element element = document.getDocumentElement(); - Attr attr = document.createAttributeNS(XMLNS_URI, XMLNS_ANDROID); - attr.setValue(ANDROID_URI); - element.getAttributes().setNamedItemNS(attr); - return (IndexedRegion) attr; - } - - return null; - } - - // ---- Implements ICompletionProposal ---- - - @Override - public void apply(IDocument document) { - perform(document); - } - - @Override - public String getAdditionalProposalInfo() { - return "Adds an Android namespace declaratiopn to the root element."; - } - - @Override - public IContextInformation getContextInformation() { - return null; - } - - @Override - public String getDisplayString() { - return "Insert namespace binding"; - } - - @Override - public Image getImage() { - return AdtPlugin.getAndroidLogo(); - } - - @Override - public Point getSelection(IDocument doc) { - return null; - } - - - // ---- Implements MarkerResolution2 ---- - - @Override - public String getLabel() { - return getDisplayString(); - } - - @Override - public void run(IMarker marker) { - try { - AdtPlugin.openFile(mFile, null); - } catch (PartInitException e) { - AdtPlugin.log(e, "Can't open file %1$s", mFile.getName()); - } - - IndexedRegion indexedRegion = perform(mFile); - if (indexedRegion != null) { - try { - IRegion region = - new Region(indexedRegion.getStartOffset(), indexedRegion.getLength()); - AdtPlugin.openFile(mFile, region); - } catch (PartInitException e) { - AdtPlugin.log(e, "Can't open file %1$s", mFile.getName()); - } - } - } - - @Override - public String getDescription() { - return getAdditionalProposalInfo(); - } - } - - private static class CreateResourceProposal - implements ICompletionProposal, IMarkerResolution2 { - private final IProject mProject; - private final String mResource; - - CreateResourceProposal(IProject project, String resource) { - super(); - mProject = project; - mResource = resource; - } - - private void perform() { - ResourceUrl resource = ResourceUrl.parse(mResource); - if (resource == null) { - return; - } - ResourceType type = resource.type; - String name = resource.name; - assert !resource.framework; - String value = ""; //$NON-NLS-1$ - - // Try to pick a reasonable first guess. The new value will be highlighted and - // selected for editing, but if we have an initial value then the new file - // won't show an error. - switch (type) { - case STRING: value = "TODO"; break; //$NON-NLS-1$ - case DIMEN: value = "1dp"; break; //$NON-NLS-1$ - case BOOL: value = "true"; break; //$NON-NLS-1$ - case COLOR: value = "#000000"; break; //$NON-NLS-1$ - case INTEGER: value = "1"; break; //$NON-NLS-1$ - case ARRAY: value = "<item>1</item>"; break; //$NON-NLS-1$ - } - - Pair<IFile, IRegion> location = - ResourceHelper.createResource(mProject, type, name, value); - if (location != null) { - IFile file = location.getFirst(); - IRegion region = location.getSecond(); - try { - AdtPlugin.openFile(file, region); - } catch (PartInitException e) { - AdtPlugin.log(e, "Can't open file %1$s", file.getName()); - } - } - } - - // ---- Implements ICompletionProposal ---- - - @Override - public void apply(IDocument document) { - perform(); - } - - @Override - public String getAdditionalProposalInfo() { - return "Creates an XML file entry for the given missing resource " - + "and opens it in the editor."; - } - - @Override - public IContextInformation getContextInformation() { - return null; - } - - @Override - public String getDisplayString() { - return String.format("Create resource %1$s", mResource); - } - - @Override - public Image getImage() { - return AdtPlugin.getAndroidLogo(); - } - - @Override - public Point getSelection(IDocument document) { - return null; - } - - // ---- Implements MarkerResolution2 ---- - - @Override - public String getLabel() { - return getDisplayString(); - } - - @Override - public void run(IMarker marker) { - perform(); - } - - @Override - public String getDescription() { - return getAdditionalProposalInfo(); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptResultException.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptResultException.java deleted file mode 100644 index 8d8fe683f..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptResultException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2010 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; - -/** - * Exception thrown when aapt reports an error in the resources. - * - */ -public final class AaptResultException extends ExecResultException { - private static final long serialVersionUID = 1L; - - AaptResultException(int errorCode, String[] output) { - super(errorCode, output); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AidlProcessor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AidlProcessor.java deleted file mode 100644 index 806fa9c40..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AidlProcessor.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * 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.SdkConstants; -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.build.builders.BaseBuilder; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.sdklib.BuildToolInfo; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.io.FileOp; - -import org.eclipse.core.resources.IContainer; -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.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -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.SubProgressMonitor; -import org.eclipse.jdt.core.IJavaProject; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A {@link SourceProcessor} for aidl files. - * - */ -public class AidlProcessor extends SourceProcessor { - - private static final String PROPERTY_COMPILE_AIDL = "compileAidl"; //$NON-NLS-1$ - - /** - * Single line aidl error<br> - * {@code <path>:<line>: <error>}<br> - * or<br> - * {@code <path>:<line> <error>}<br> - */ - private static Pattern sAidlPattern1 = Pattern.compile("^(.+?):(\\d+):?\\s(.+)$"); //$NON-NLS-1$ - - private final static Set<String> EXTENSIONS = Collections.singleton(SdkConstants.EXT_AIDL); - - private enum AidlType { - UNKNOWN, INTERFACE, PARCELABLE; - } - - // See comment in #getAidlType() -// private final static Pattern sParcelablePattern = Pattern.compile( -// "^\\s*parcelable\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*;\\s*$"); -// -// private final static Pattern sInterfacePattern = Pattern.compile( -// "^\\s*interface\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*(?:\\{.*)?$"); - - - public AidlProcessor(@NonNull IJavaProject javaProject, @NonNull BuildToolInfo buildToolInfo, - @NonNull IFolder genFolder) { - super(javaProject, buildToolInfo, genFolder); - } - - @Override - protected Set<String> getExtensions() { - return EXTENSIONS; - } - - @Override - protected String getSavePropertyName() { - return PROPERTY_COMPILE_AIDL; - } - - @Override - protected void doCompileFiles(List<IFile> sources, BaseBuilder builder, - IProject project, IAndroidTarget projectTarget, - List<IPath> sourceFolders, List<IFile> notCompiledOut, List<File> libraryProjectsOut, - IProgressMonitor monitor) throws CoreException { - // create the command line - List<String> commandList = new ArrayList<String>( - 4 + sourceFolders.size() + libraryProjectsOut.size()); - commandList.add(getBuildToolInfo().getPath(BuildToolInfo.PathId.AIDL)); - commandList.add(quote("-p" + projectTarget.getPath(IAndroidTarget.ANDROID_AIDL))); //$NON-NLS-1$ - - // since the path are relative to the workspace and not the project itself, we need - // the workspace root. - IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - for (IPath p : sourceFolders) { - IFolder f = wsRoot.getFolder(p); - if (f.exists()) { // if the resource doesn't exist, getLocation will return null. - commandList.add(quote("-I" + f.getLocation().toOSString())); //$NON-NLS-1$ - } - } - - for (File libOut : libraryProjectsOut) { - // FIXME: make folder configurable - File aidlFile = new File(libOut, SdkConstants.FD_AIDL); - if (aidlFile.isDirectory()) { - commandList.add(quote("-I" + aidlFile.getAbsolutePath())); //$NON-NLS-1$ - } - } - - // convert to array with 2 extra strings for the in/out file paths. - int index = commandList.size(); - String[] commands = commandList.toArray(new String[index + 2]); - - boolean verbose = AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE; - - // remove the generic marker from the project - builder.removeMarkersFromResource(project, AdtConstants.MARKER_AIDL); - - // prepare the two output folders. - IFolder genFolder = getGenFolder(); - IFolder projectOut = BaseProjectHelper.getAndroidOutputFolder(project); - IFolder aidlOutFolder = projectOut.getFolder(SdkConstants.FD_AIDL); - if (aidlOutFolder.exists() == false) { - aidlOutFolder.create(true /*force*/, true /*local*/, - new SubProgressMonitor(monitor, 10)); - } - - boolean success = false; - - // loop until we've compile them all - for (IFile sourceFile : sources) { - if (verbose) { - String name = sourceFile.getName(); - IPath sourceFolderPath = getSourceFolderFor(sourceFile); - if (sourceFolderPath != null) { - // make a path to the source file relative to the source folder. - IPath relative = sourceFile.getFullPath().makeRelativeTo(sourceFolderPath); - name = relative.toString(); - } - AdtPlugin.printToConsole(project, "AIDL: " + name); - } - - // Remove the AIDL error markers from the aidl file - builder.removeMarkersFromResource(sourceFile, AdtConstants.MARKER_AIDL); - - // get the path of the source file. - IPath sourcePath = sourceFile.getLocation(); - String osSourcePath = sourcePath.toOSString(); - - // look if we already know the output - SourceFileData data = getFileData(sourceFile); - if (data == null) { - data = new SourceFileData(sourceFile); - addData(data); - } - - // if there's no output file yet, compute it. - if (data.getOutput() == null) { - IFile javaFile = getAidlOutputFile(sourceFile, genFolder, - true /*replaceExt*/, true /*createFolders*/, monitor); - data.setOutputFile(javaFile); - } - - // finish to set the command line. - commands[index] = quote(osSourcePath); - commands[index + 1] = quote(data.getOutput().getLocation().toOSString()); - - // launch the process - if (execAidl(builder, project, commands, sourceFile, verbose) == false) { - // aidl failed. File should be marked. We add the file to the list - // of file that will need compilation again. - notCompiledOut.add(sourceFile); - } else { - // Success. we'll return that we generated code - setCompilationStatus(COMPILE_STATUS_CODE); - success = true; - - // Also copy the file to the bin folder. - IFile aidlOutFile = getAidlOutputFile(sourceFile, aidlOutFolder, - false /*replaceExt*/, true /*createFolders*/, monitor); - - FileOp op = new FileOp(); - try { - op.copyFile(sourceFile.getLocation().toFile(), - aidlOutFile.getLocation().toFile()); - } catch (IOException e) { - } - } - } - - if (success) { - aidlOutFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); - } - } - - @Override - protected void loadOutputAndDependencies() { - IProgressMonitor monitor = new NullProgressMonitor(); - IFolder genFolder = getGenFolder(); - - Collection<SourceFileData> dataList = getAllFileData(); - for (SourceFileData data : dataList) { - try { - IFile javaFile = getAidlOutputFile(data.getSourceFile(), genFolder, - true /*replaceExt*/, false /*createFolders*/, monitor); - data.setOutputFile(javaFile); - } catch (CoreException e) { - // ignore, we're not asking to create the folder so this won't happen anyway. - } - - } - } - - /** - * Execute the aidl command line, parse the output, and mark the aidl file - * with any reported errors. - * @param command the String array containing the command line to execute. - * @param file The IFile object representing the aidl file being - * compiled. - * @param verbose the build verbosity - * @return false if the exec failed, and build needs to be aborted. - */ - private boolean execAidl(BaseBuilder builder, IProject project, String[] command, IFile file, - boolean verbose) { - // do the exec - try { - if (verbose) { - StringBuilder sb = new StringBuilder(); - for (String c : command) { - sb.append(c); - sb.append(' '); - } - String cmd_line = sb.toString(); - AdtPlugin.printToConsole(project, cmd_line); - } - - Process p = Runtime.getRuntime().exec(command); - - // 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(project, p, stdErr); - - if (stdErr.size() > 0) { - // attempt to parse the error output - boolean parsingError = parseAidlOutput(stdErr, file); - - // 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 || verbose) { - // display the message in the console. - if (parsingError) { - AdtPlugin.printErrorToConsole(project, stdErr.toArray()); - - // mark the project - BaseProjectHelper.markResource(project, AdtConstants.MARKER_AIDL, - Messages.Unparsed_AIDL_Errors, IMarker.SEVERITY_ERROR); - } else { - AdtPlugin.printToConsole(project, stdErr.toArray()); - } - } - return false; - } - } else if (returnCode != 0) { - // no stderr output but exec failed. - String msg = String.format(Messages.AIDL_Exec_Error_d, returnCode); - - BaseProjectHelper.markResource(project, AdtConstants.MARKER_AIDL, - msg, IMarker.SEVERITY_ERROR); - - return false; - } - } catch (IOException e) { - // mark the project and exit - String msg = String.format(Messages.AIDL_Exec_Error_s, command[0]); - BaseProjectHelper.markResource(project, AdtConstants.MARKER_AIDL, msg, - IMarker.SEVERITY_ERROR); - return false; - } catch (InterruptedException e) { - // mark the project and exit - String msg = String.format(Messages.AIDL_Exec_Error_s, command[0]); - BaseProjectHelper.markResource(project, AdtConstants.MARKER_AIDL, msg, - IMarker.SEVERITY_ERROR); - return false; - } - - return true; - } - - /** - * Parse the output of aidl and mark the file with any errors. - * @param lines The output to parse. - * @param file The file to mark with error. - * @return true if the parsing failed, false if success. - */ - private boolean parseAidlOutput(ArrayList<String> lines, IFile file) { - // nothing to parse? just return false; - if (lines.size() == 0) { - return false; - } - - Matcher m; - - for (int i = 0; i < lines.size(); i++) { - String p = lines.get(i); - - m = sAidlPattern1.matcher(p); - if (m.matches()) { - // we can ignore group 1 which is the location since we already - // have a IFile object representing the aidl file. - String lineStr = m.group(2); - String msg = m.group(3); - - // 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(file, AdtConstants.MARKER_AIDL, msg, line, - IMarker.SEVERITY_ERROR); - - // success, go to the next line - continue; - } - - // invalid line format, flag as error, and bail - return true; - } - - return false; - } - - /** - * Returns the {@link IFile} handle to the destination file for a given aidl source file - * ({@link AidlData}). - * @param sourceFile The source file - * @param outputFolder the top level output folder (not including the package folders) - * @param createFolders whether or not the parent folder of the destination should be created - * if it does not exist. - * @param monitor the progress monitor - * @return the handle to the destination file. - * @throws CoreException - */ - private IFile getAidlOutputFile(IFile sourceFile, IFolder outputFolder, boolean replaceExt, - boolean createFolders, IProgressMonitor monitor) throws CoreException { - - IPath sourceFolderPath = getSourceFolderFor(sourceFile); - - // this really shouldn't happen since the sourceFile must be in a source folder - // since it comes from the delta visitor - if (sourceFolderPath != null) { - // make a path to the source file relative to the source folder. - IPath relative = sourceFile.getFullPath().makeRelativeTo(sourceFolderPath); - // remove the file name. This is now the destination folder. - relative = relative.removeLastSegments(1); - - // get an IFolder for this path. - IFolder destinationFolder = outputFolder.getFolder(relative); - - // create it if needed. - if (destinationFolder.exists() == false && createFolders) { - createFolder(destinationFolder, monitor); - } - - // Build the Java file name from the aidl name. - String javaName; - if (replaceExt) { - javaName = sourceFile.getName().replaceAll( - AdtConstants.RE_AIDL_EXT, SdkConstants.DOT_JAVA); - } else { - javaName = sourceFile.getName(); - } - - // get the resource for the java file. - IFile javaFile = destinationFolder.getFile(javaName); - return javaFile; - } - - return null; - } - - /** - * Creates the destination folder. Because - * {@link IFolder#create(boolean, boolean, IProgressMonitor)} only works if the parent folder - * already exists, this goes and ensure that all the parent folders actually exist, or it - * creates them as well. - * @param destinationFolder The folder to create - * @param monitor the {@link IProgressMonitor}, - * @throws CoreException - */ - private void createFolder(IFolder destinationFolder, IProgressMonitor monitor) - throws CoreException { - - // check the parent exist and create if necessary. - IContainer parent = destinationFolder.getParent(); - if (parent.getType() == IResource.FOLDER && parent.exists() == false) { - createFolder((IFolder)parent, monitor); - } - - // create the folder. - destinationFolder.create(true /*force*/, true /*local*/, - new SubProgressMonitor(monitor, 10)); - } - - /** - * Returns the type of the aidl file. Aidl files can either declare interfaces, or declare - * parcelables. This method will attempt to parse the file and return the type. If the type - * cannot be determined, then it will return {@link AidlType#UNKNOWN}. - * @param file The aidl file - * @return the type of the aidl. - */ - private static AidlType getAidlType(IFile file) { - // At this time, parsing isn't available, so we return UNKNOWN. This will force - // a recompilation of all aidl file as soon as one is changed. - return AidlType.UNKNOWN; - - // TODO: properly parse aidl file to determine type and generate dependency graphs. -// -// String className = file.getName().substring(0, -// file.getName().length() - SdkConstants.DOT_AIDL.length()); -// -// InputStream input = file.getContents(true /* force*/); -// try { -// BufferedReader reader = new BufferedReader(new InputStreateader(input)); -// String line; -// while ((line = reader.readLine()) != null) { -// if (line.length() == 0) { -// continue; -// } -// -// Matcher m = sParcelablePattern.matcher(line); -// if (m.matches() && m.group(1).equals(className)) { -// return AidlType.PARCELABLE; -// } -// -// m = sInterfacePattern.matcher(line); -// if (m.matches() && m.group(1).equals(className)) { -// return AidlType.INTERFACE; -// } -// } -// } catch (IOException e) { -// throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, -// "Error parsing aidl file", e)); -// } finally { -// try { -// input.close(); -// } catch (IOException e) { -// throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, -// "Error parsing aidl file", e)); -// } -// } -// -// return AidlType.UNKNOWN; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java deleted file mode 100644 index 78d9d94e4..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java +++ /dev/null @@ -1,1225 +0,0 @@ -/* - * Copyright (C) 2010 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.SdkConstants; -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AndroidPrintStream; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.prefs.AndroidLocation.AndroidLocationException; -import com.android.sdklib.BuildToolInfo; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.IAndroidTarget.IOptionalLibrary; -import com.android.sdklib.build.ApkBuilder; -import com.android.sdklib.build.ApkBuilder.JarStatus; -import com.android.sdklib.build.ApkBuilder.SigningInfo; -import com.android.sdklib.build.ApkCreationException; -import com.android.sdklib.build.DuplicateFileException; -import com.android.sdklib.build.RenderScriptProcessor; -import com.android.sdklib.build.SealedApkException; -import com.android.sdklib.internal.build.DebugKeyProvider; -import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException; -import com.android.utils.GrabProcessOutput; -import com.android.utils.GrabProcessOutput.IProcessOutput; -import com.android.utils.GrabProcessOutput.Wait; -import com.google.common.base.Charsets; -import com.google.common.hash.HashCode; -import com.google.common.hash.HashFunction; -import com.google.common.hash.Hashing; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.core.IClasspathContainer; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jface.preference.IPreferenceStore; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintStream; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -/** - * Helper with methods for the last 3 steps of the generation of an APK. - * - * {@link #packageResources(IFile, IProject[], String, int, String, String)} packages the - * application resources using aapt into a zip file that is ready to be integrated into the apk. - * - * {@link #executeDx(IJavaProject, String, String, IJavaProject[])} will convert the Java byte - * code into the Dalvik bytecode. - * - * {@link #finalPackage(String, String, String, boolean, IJavaProject, IProject[], IJavaProject[], String, boolean)} - * will make the apk from all the previous components. - * - * This class only executes the 3 above actions. It does not handle the errors, and simply sends - * them back as custom exceptions. - * - * Warnings are handled by the {@link ResourceMarker} interface. - * - * Console output (verbose and non verbose) is handled through the {@link AndroidPrintStream} passed - * to the constructor. - * - */ -public class BuildHelper { - - private static final String CONSOLE_PREFIX_DX = "Dx"; //$NON-NLS-1$ - private final static String TEMP_PREFIX = "android_"; //$NON-NLS-1$ - - private static final String COMMAND_CRUNCH = "crunch"; //$NON-NLS-1$ - private static final String COMMAND_PACKAGE = "package"; //$NON-NLS-1$ - - @NonNull - private final ProjectState mProjectState; - @NonNull - private final IProject mProject; - @NonNull - private final BuildToolInfo mBuildToolInfo; - @NonNull - private final AndroidPrintStream mOutStream; - @NonNull - private final AndroidPrintStream mErrStream; - private final boolean mForceJumbo; - private final boolean mDisableDexMerger; - private final boolean mVerbose; - private final boolean mDebugMode; - - private final Set<String> mCompiledCodePaths = new HashSet<String>(); - - public static final boolean BENCHMARK_FLAG = false; - public static long sStartOverallTime = 0; - public static long sStartJavaCTime = 0; - - private final static int MILLION = 1000000; - private String mProguardFile; - - /** - * An object able to put a marker on a resource. - */ - public interface ResourceMarker { - void setWarning(IResource resource, String message); - } - - /** - * Creates a new post-compiler helper - * @param project - * @param outStream - * @param errStream - * @param debugMode whether this is a debug build - * @param verbose - * @throws CoreException - */ - public BuildHelper(@NonNull ProjectState projectState, - @NonNull BuildToolInfo buildToolInfo, - @NonNull AndroidPrintStream outStream, - @NonNull AndroidPrintStream errStream, - boolean forceJumbo, boolean disableDexMerger, boolean debugMode, - boolean verbose, ResourceMarker resMarker) throws CoreException { - mProjectState = projectState; - mProject = projectState.getProject(); - mBuildToolInfo = buildToolInfo; - mOutStream = outStream; - mErrStream = errStream; - mDebugMode = debugMode; - mVerbose = verbose; - mForceJumbo = forceJumbo; - mDisableDexMerger = disableDexMerger; - - gatherPaths(resMarker); - } - - public void updateCrunchCache() throws AaptExecException, AaptResultException { - // Benchmarking start - long startCrunchTime = 0; - if (BENCHMARK_FLAG) { - String msg = "BENCHMARK ADT: Starting Initial Packaging (.ap_)"; //$NON-NLS-1$ - AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg); - startCrunchTime = System.nanoTime(); - } - - // Get the resources folder to crunch from - IFolder resFolder = mProject.getFolder(AdtConstants.WS_RESOURCES); - List<String> resPaths = new ArrayList<String>(); - resPaths.add(resFolder.getLocation().toOSString()); - - // Get the output folder where the cache is stored. - IFolder binFolder = BaseProjectHelper.getAndroidOutputFolder(mProject); - IFolder cacheFolder = binFolder.getFolder(AdtConstants.WS_BIN_RELATIVE_CRUNCHCACHE); - String cachePath = cacheFolder.getLocation().toOSString(); - - /* For crunching, we don't need the osManifestPath, osAssetsPath, or the configFilter - * parameters for executeAapt - */ - executeAapt(COMMAND_CRUNCH, "", resPaths, "", cachePath, "", 0); - - // Benchmarking end - if (BENCHMARK_FLAG) { - String msg = "BENCHMARK ADT: Ending Initial Package (.ap_). \nTime Elapsed: " //$NON-NLS-1$ - + ((System.nanoTime() - startCrunchTime)/MILLION) + "ms"; //$NON-NLS-1$ - AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg); - } - } - - /** - * Packages the resources of the projet into a .ap_ file. - * @param manifestFile the manifest of the project. - * @param libProjects the list of library projects that this project depends on. - * @param resFilter an optional resource filter to be used with the -c option of aapt. If null - * no filters are used. - * @param versionCode an optional versionCode to be inserted in the manifest during packaging. - * If the value is <=0, no values are inserted. - * @param outputFolder where to write the resource ap_ file. - * @param outputFilename the name of the resource ap_ file. - * @throws AaptExecException - * @throws AaptResultException - */ - public void packageResources(IFile manifestFile, List<IProject> libProjects, String resFilter, - int versionCode, String outputFolder, String outputFilename) - throws AaptExecException, AaptResultException { - - // Benchmarking start - long startPackageTime = 0; - if (BENCHMARK_FLAG) { - String msg = "BENCHMARK ADT: Starting Initial Packaging (.ap_)"; //$NON-NLS-1$ - AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg); - startPackageTime = System.nanoTime(); - } - - // need to figure out some path before we can execute aapt; - IFolder binFolder = BaseProjectHelper.getAndroidOutputFolder(mProject); - - // get the cache folder - IFolder cacheFolder = binFolder.getFolder(AdtConstants.WS_BIN_RELATIVE_CRUNCHCACHE); - - // get the BC folder - IFolder bcFolder = binFolder.getFolder(AdtConstants.WS_BIN_RELATIVE_BC); - - // get the resource folder - IFolder resFolder = mProject.getFolder(AdtConstants.WS_RESOURCES); - - // and the assets folder - IFolder assetsFolder = mProject.getFolder(AdtConstants.WS_ASSETS); - - // we need to make sure this one exists. - if (assetsFolder.exists() == false) { - assetsFolder = null; - } - - // list of res folder (main project + maybe libraries) - ArrayList<String> osResPaths = new ArrayList<String>(); - - IPath resLocation = resFolder.getLocation(); - IPath manifestLocation = manifestFile.getLocation(); - - if (resLocation != null && manifestLocation != null) { - - // png cache folder first. - addFolderToList(osResPaths, cacheFolder); - addFolderToList(osResPaths, bcFolder); - - // regular res folder next. - osResPaths.add(resLocation.toOSString()); - - // then libraries - if (libProjects != null) { - for (IProject lib : libProjects) { - // png cache folder first - IFolder libBinFolder = BaseProjectHelper.getAndroidOutputFolder(lib); - - IFolder libCacheFolder = libBinFolder.getFolder(AdtConstants.WS_BIN_RELATIVE_CRUNCHCACHE); - addFolderToList(osResPaths, libCacheFolder); - - IFolder libBcFolder = libBinFolder.getFolder(AdtConstants.WS_BIN_RELATIVE_BC); - addFolderToList(osResPaths, libBcFolder); - - // regular res folder next. - IFolder libResFolder = lib.getFolder(AdtConstants.WS_RESOURCES); - addFolderToList(osResPaths, libResFolder); - } - } - - String osManifestPath = manifestLocation.toOSString(); - - String osAssetsPath = null; - if (assetsFolder != null) { - osAssetsPath = assetsFolder.getLocation().toOSString(); - } - - // build the default resource package - executeAapt(COMMAND_PACKAGE, osManifestPath, osResPaths, osAssetsPath, - outputFolder + File.separator + outputFilename, resFilter, - versionCode); - } - - // Benchmarking end - if (BENCHMARK_FLAG) { - String msg = "BENCHMARK ADT: Ending Initial Package (.ap_). \nTime Elapsed: " //$NON-NLS-1$ - + ((System.nanoTime() - startPackageTime)/MILLION) + "ms"; //$NON-NLS-1$ - AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg); - } - } - - /** - * Adds os path of a folder to a list only if the folder actually exists. - * @param pathList - * @param folder - */ - private void addFolderToList(List<String> pathList, IFolder folder) { - // use a File instead of the IFolder API to ignore workspace refresh issue. - File testFile = new File(folder.getLocation().toOSString()); - if (testFile.isDirectory()) { - pathList.add(testFile.getAbsolutePath()); - } - } - - /** - * Makes a final package signed with the debug key. - * - * Packages the dex files, the temporary resource file into the final package file. - * - * Whether the package is a debug package is controlled with the <var>debugMode</var> parameter - * in {@link #PostCompilerHelper(IProject, PrintStream, PrintStream, boolean, boolean)} - * - * @param intermediateApk The path to the temporary resource file. - * @param dex The path to the dex file. - * @param output The path to the final package file to create. - * @param libProjects an optional list of library projects (can be null) - * @return true if success, false otherwise. - * @throws ApkCreationException - * @throws AndroidLocationException - * @throws KeytoolException - * @throws NativeLibInJarException - * @throws CoreException - * @throws DuplicateFileException - */ - public void finalDebugPackage(String intermediateApk, String dex, String output, - List<IProject> libProjects, ResourceMarker resMarker) - throws ApkCreationException, KeytoolException, AndroidLocationException, - NativeLibInJarException, DuplicateFileException, CoreException { - - AdtPlugin adt = AdtPlugin.getDefault(); - if (adt == null) { - return; - } - - // get the debug keystore to use. - IPreferenceStore store = adt.getPreferenceStore(); - String keystoreOsPath = store.getString(AdtPrefs.PREFS_CUSTOM_DEBUG_KEYSTORE); - if (keystoreOsPath == null || new File(keystoreOsPath).isFile() == false) { - keystoreOsPath = DebugKeyProvider.getDefaultKeyStoreOsPath(); - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject, - Messages.ApkBuilder_Using_Default_Key); - } else { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject, - String.format(Messages.ApkBuilder_Using_s_To_Sign, keystoreOsPath)); - } - - // from the keystore, get the signing info - SigningInfo info = ApkBuilder.getDebugKey(keystoreOsPath, mVerbose ? mOutStream : null); - - finalPackage(intermediateApk, dex, output, libProjects, - info != null ? info.key : null, info != null ? info.certificate : null, resMarker); - } - - /** - * Makes the final package. - * - * Packages the dex files, the temporary resource file into the final package file. - * - * Whether the package is a debug package is controlled with the <var>debugMode</var> parameter - * in {@link #PostCompilerHelper(IProject, PrintStream, PrintStream, boolean, boolean)} - * - * @param intermediateApk The path to the temporary resource file. - * @param dex The path to the dex file. - * @param output The path to the final package file to create. - * @param debugSign whether the apk must be signed with the debug key. - * @param libProjects an optional list of library projects (can be null) - * @param abiFilter an optional filter. If not null, then only the matching ABI is included in - * the final archive - * @return true if success, false otherwise. - * @throws NativeLibInJarException - * @throws ApkCreationException - * @throws CoreException - * @throws DuplicateFileException - */ - public void finalPackage(String intermediateApk, String dex, String output, - List<IProject> libProjects, - PrivateKey key, X509Certificate certificate, ResourceMarker resMarker) - throws NativeLibInJarException, ApkCreationException, DuplicateFileException, - CoreException { - - try { - ApkBuilder apkBuilder = new ApkBuilder(output, intermediateApk, dex, - key, certificate, - mVerbose ? mOutStream: null); - apkBuilder.setDebugMode(mDebugMode); - - // either use the full compiled code paths or just the proguard file - // if present - Collection<String> pathsCollection = mCompiledCodePaths; - if (mProguardFile != null) { - pathsCollection = Collections.singletonList(mProguardFile); - mProguardFile = null; - } - - // Now we write the standard resources from all the output paths. - for (String path : pathsCollection) { - File file = new File(path); - if (file.isFile()) { - JarStatus jarStatus = apkBuilder.addResourcesFromJar(file); - - // check if we found native libraries in the external library. This - // constitutes an error or warning depending on if they are in lib/ - if (jarStatus.getNativeLibs().size() > 0) { - String libName = file.getName(); - - String msg = String.format( - "Native libraries detected in '%1$s'. See console for more information.", - libName); - - ArrayList<String> consoleMsgs = new ArrayList<String>(); - - consoleMsgs.add(String.format( - "The library '%1$s' contains native libraries that will not run on the device.", - libName)); - - if (jarStatus.hasNativeLibsConflicts()) { - consoleMsgs.add("Additionally some of those libraries will interfer with the installation of the application because of their location in lib/"); - consoleMsgs.add("lib/ is reserved for NDK libraries."); - } - - consoleMsgs.add("The following libraries were found:"); - - for (String lib : jarStatus.getNativeLibs()) { - consoleMsgs.add(" - " + lib); - } - - String[] consoleStrings = consoleMsgs.toArray(new String[consoleMsgs.size()]); - - // if there's a conflict or if the prefs force error on any native code in jar - // files, throw an exception - if (jarStatus.hasNativeLibsConflicts() || - AdtPrefs.getPrefs().getBuildForceErrorOnNativeLibInJar()) { - throw new NativeLibInJarException(jarStatus, msg, libName, consoleStrings); - } else { - // otherwise, put a warning, and output to the console also. - if (resMarker != null) { - resMarker.setWarning(mProject, msg); - } - - for (String string : consoleStrings) { - mOutStream.println(string); - } - } - } - } else if (file.isDirectory()) { - // this is technically not a source folder (class folder instead) but since we - // only care about Java resources (ie non class/java files) this will do the - // same - apkBuilder.addSourceFolder(file); - } - } - - // now write the native libraries. - // First look if the lib folder is there. - IResource libFolder = mProject.findMember(SdkConstants.FD_NATIVE_LIBS); - if (libFolder != null && libFolder.exists() && - libFolder.getType() == IResource.FOLDER) { - // get a File for the folder. - apkBuilder.addNativeLibraries(libFolder.getLocation().toFile()); - } - - // next the native libraries for the renderscript support mode. - if (mProjectState.getRenderScriptSupportMode()) { - IFolder androidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(mProject); - IResource rsLibFolder = androidOutputFolder.getFolder( - AdtConstants.WS_BIN_RELATIVE_RS_LIBS); - File rsLibFolderFile = rsLibFolder.getLocation().toFile(); - if (rsLibFolderFile.isDirectory()) { - apkBuilder.addNativeLibraries(rsLibFolderFile); - } - - File rsLibs = RenderScriptProcessor.getSupportNativeLibFolder( - mBuildToolInfo.getLocation().getAbsolutePath()); - if (rsLibs.isDirectory()) { - apkBuilder.addNativeLibraries(rsLibs); - } - } - - // write the native libraries for the library projects. - if (libProjects != null) { - for (IProject lib : libProjects) { - libFolder = lib.findMember(SdkConstants.FD_NATIVE_LIBS); - if (libFolder != null && libFolder.exists() && - libFolder.getType() == IResource.FOLDER) { - apkBuilder.addNativeLibraries(libFolder.getLocation().toFile()); - } - } - } - - // seal the APK. - apkBuilder.sealApk(); - } catch (SealedApkException e) { - // this won't happen as we control when the apk is sealed. - } - } - - public void setProguardOutput(String proguardFile) { - mProguardFile = proguardFile; - } - - public Collection<String> getCompiledCodePaths() { - return mCompiledCodePaths; - } - - public void runProguard(List<File> proguardConfigs, File inputJar, Collection<String> jarFiles, - File obfuscatedJar, File logOutput) - throws ProguardResultException, ProguardExecException, IOException { - IAndroidTarget target = Sdk.getCurrent().getTarget(mProject); - - // prepare the command line for proguard - List<String> command = new ArrayList<String>(); - command.add(AdtPlugin.getOsAbsoluteProguard()); - - for (File configFile : proguardConfigs) { - command.add("-include"); //$NON-NLS-1$ - command.add(quotePath(configFile.getAbsolutePath())); - } - - command.add("-injars"); //$NON-NLS-1$ - StringBuilder sb = new StringBuilder(quotePath(inputJar.getAbsolutePath())); - for (String jarFile : jarFiles) { - sb.append(File.pathSeparatorChar); - sb.append(quotePath(jarFile)); - } - command.add(quoteWinArg(sb.toString())); - - command.add("-outjars"); //$NON-NLS-1$ - command.add(quotePath(obfuscatedJar.getAbsolutePath())); - - command.add("-libraryjars"); //$NON-NLS-1$ - sb = new StringBuilder(quotePath(target.getPath(IAndroidTarget.ANDROID_JAR))); - IOptionalLibrary[] libraries = target.getOptionalLibraries(); - if (libraries != null) { - for (IOptionalLibrary lib : libraries) { - sb.append(File.pathSeparatorChar); - sb.append(quotePath(lib.getJarPath())); - } - } - command.add(quoteWinArg(sb.toString())); - - if (logOutput != null) { - if (logOutput.isDirectory() == false) { - logOutput.mkdirs(); - } - - command.add("-dump"); //$NON-NLS-1$ - command.add(new File(logOutput, "dump.txt").getAbsolutePath()); //$NON-NLS-1$ - - command.add("-printseeds"); //$NON-NLS-1$ - command.add(new File(logOutput, "seeds.txt").getAbsolutePath()); //$NON-NLS-1$ - - command.add("-printusage"); //$NON-NLS-1$ - command.add(new File(logOutput, "usage.txt").getAbsolutePath()); //$NON-NLS-1$ - - command.add("-printmapping"); //$NON-NLS-1$ - command.add(new File(logOutput, "mapping.txt").getAbsolutePath()); //$NON-NLS-1$ - } - - String commandArray[] = null; - - if (SdkConstants.currentPlatform() == SdkConstants.PLATFORM_WINDOWS) { - commandArray = createWindowsProguardConfig(command); - } - - if (commandArray == null) { - // For Mac & Linux, use a regular command string array. - commandArray = command.toArray(new String[command.size()]); - } - - // Define PROGUARD_HOME to point to $SDK/tools/proguard if it's not yet defined. - // The Mac/Linux proguard.sh can infer it correctly but not the proguard.bat one. - String[] envp = null; - Map<String, String> envMap = new TreeMap<String, String>(System.getenv()); - if (!envMap.containsKey("PROGUARD_HOME")) { //$NON-NLS-1$ - envMap.put("PROGUARD_HOME", Sdk.getCurrent().getSdkOsLocation() + //$NON-NLS-1$ - SdkConstants.FD_TOOLS + File.separator + - SdkConstants.FD_PROGUARD); - envp = new String[envMap.size()]; - int i = 0; - for (Map.Entry<String, String> entry : envMap.entrySet()) { - envp[i++] = String.format("%1$s=%2$s", //$NON-NLS-1$ - entry.getKey(), - entry.getValue()); - } - } - - if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) { - sb = new StringBuilder(); - for (String c : commandArray) { - sb.append(c).append(' '); - } - AdtPlugin.printToConsole(mProject, sb.toString()); - } - - // launch - int execError = 1; - try { - // launch the command line process - Process process = Runtime.getRuntime().exec(commandArray, envp); - - // list to store each line of stderr - ArrayList<String> results = new ArrayList<String>(); - - // get the output and return code from the process - execError = grabProcessOutput(mProject, process, results); - - if (mVerbose) { - for (String resultString : results) { - mOutStream.println(resultString); - } - } - - if (execError != 0) { - throw new ProguardResultException(execError, - results.toArray(new String[results.size()])); - } - - } catch (IOException e) { - String msg = String.format(Messages.Proguard_Exec_Error, commandArray[0]); - throw new ProguardExecException(msg, e); - } catch (InterruptedException e) { - String msg = String.format(Messages.Proguard_Exec_Error, commandArray[0]); - throw new ProguardExecException(msg, e); - } - } - - /** - * For tools R8 up to R11, the proguard.bat launcher on Windows only accepts - * arguments %1..%9. Since we generally have about 15 arguments, we were working - * around this by generating a temporary config file for proguard and then using - * that. - * Starting with tools R12, the proguard.bat launcher has been fixed to take - * all arguments using %* so we no longer need this hack. - * - * @param command - * @return - * @throws IOException - */ - private String[] createWindowsProguardConfig(List<String> command) throws IOException { - - // Arg 0 is the proguard.bat path and arg 1 is the user config file - String launcher = AdtPlugin.readFile(new File(command.get(0))); - if (launcher.contains("%*")) { //$NON-NLS-1$ - // This is the launcher from Tools R12. Don't work around it. - return null; - } - - // On Windows, proguard.bat can only pass %1...%9 to the java -jar proguard.jar - // call, but we have at least 15 arguments here so some get dropped silently - // and quoting is a big issue. So instead we'll work around that by writing - // all the arguments to a temporary config file. - - String[] commandArray = new String[3]; - - commandArray[0] = command.get(0); - commandArray[1] = command.get(1); - - // Write all the other arguments to a config file - File argsFile = File.createTempFile(TEMP_PREFIX, ".pro"); //$NON-NLS-1$ - // TODO FIXME this may leave a lot of temp files around on a long session. - // Should have a better way to clean up e.g. before each build. - argsFile.deleteOnExit(); - - FileWriter fw = new FileWriter(argsFile); - - for (int i = 2; i < command.size(); i++) { - String s = command.get(i); - fw.write(s); - fw.write(s.startsWith("-") ? ' ' : '\n'); //$NON-NLS-1$ - } - - fw.close(); - - commandArray[2] = "@" + argsFile.getAbsolutePath(); //$NON-NLS-1$ - return commandArray; - } - - /** - * Quotes a single path for proguard to deal with spaces. - * - * @param path The path to quote. - * @return The original path if it doesn't contain a space. - * Or the original path surrounded by single quotes if it contains spaces. - */ - private String quotePath(String path) { - if (path.indexOf(' ') != -1) { - path = '\'' + path + '\''; - } - return path; - } - - /** - * Quotes a compound proguard argument to deal with spaces. - * <p/> - * Proguard takes multi-path arguments such as "path1;path2" for some options. - * When the {@link #quotePath} methods adds quotes for such a path if it contains spaces, - * the proguard shell wrapper will absorb the quotes, so we need to quote around the - * quotes. - * - * @param path The path to quote. - * @return The original path if it doesn't contain a single quote. - * Or on Windows the original path surrounded by double quotes if it contains a quote. - */ - private String quoteWinArg(String path) { - if (path.indexOf('\'') != -1 && - SdkConstants.currentPlatform() == SdkConstants.PLATFORM_WINDOWS) { - path = '"' + path + '"'; - } - return path; - } - - - /** - * Execute the Dx tool for dalvik code conversion. - * @param javaProject The java project - * @param inputPaths the input paths for DX - * @param osOutFilePath the path of the dex file to create. - * - * @throws CoreException - * @throws DexException - */ - public void executeDx(IJavaProject javaProject, Collection<String> inputPaths, - String osOutFilePath) - throws CoreException, DexException { - - // get the dex wrapper - Sdk sdk = Sdk.getCurrent(); - DexWrapper wrapper = sdk.getDexWrapper(mBuildToolInfo); - - if (wrapper == null) { - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - Messages.ApkBuilder_UnableBuild_Dex_Not_loaded)); - } - - try { - // set a temporary prefix on the print streams. - mOutStream.setPrefix(CONSOLE_PREFIX_DX); - mErrStream.setPrefix(CONSOLE_PREFIX_DX); - - IFolder binFolder = BaseProjectHelper.getAndroidOutputFolder(javaProject.getProject()); - File binFile = binFolder.getLocation().toFile(); - File dexedLibs = new File(binFile, "dexedLibs"); - if (dexedLibs.exists() == false) { - dexedLibs.mkdir(); - } - - // replace the libs by their dexed versions (dexing them if needed.) - List<String> finalInputPaths = new ArrayList<String>(inputPaths.size()); - if (mDisableDexMerger || inputPaths.size() == 1) { - // only one input, no need to put a pre-dexed version, even if this path is - // just a jar file (case for proguard'ed builds) - finalInputPaths.addAll(inputPaths); - } else { - - for (String input : inputPaths) { - File inputFile = new File(input); - if (inputFile.isDirectory()) { - finalInputPaths.add(input); - } else if (inputFile.isFile()) { - String fileName = getDexFileName(inputFile); - - File dexedLib = new File(dexedLibs, fileName); - String dexedLibPath = dexedLib.getAbsolutePath(); - - if (dexedLib.isFile() == false || - dexedLib.lastModified() < inputFile.lastModified()) { - - if (mVerbose) { - mOutStream.println( - String.format("Pre-Dexing %1$s -> %2$s", input, fileName)); - } - - if (dexedLib.isFile()) { - dexedLib.delete(); - } - - int res = wrapper.run(dexedLibPath, Collections.singleton(input), - mForceJumbo, mVerbose, mOutStream, mErrStream); - - if (res != 0) { - // output error message and mark the project. - String message = String.format(Messages.Dalvik_Error_d, res); - throw new DexException(message); - } - } else { - if (mVerbose) { - mOutStream.println( - String.format("Using Pre-Dexed %1$s <- %2$s", - fileName, input)); - } - } - - finalInputPaths.add(dexedLibPath); - } - } - } - - if (mVerbose) { - for (String input : finalInputPaths) { - mOutStream.println("Input: " + input); - } - } - - int res = wrapper.run(osOutFilePath, - finalInputPaths, - mForceJumbo, - mVerbose, - mOutStream, mErrStream); - - mOutStream.setPrefix(null); - mErrStream.setPrefix(null); - - if (res != 0) { - // output error message and marker the project. - String message = String.format(Messages.Dalvik_Error_d, res); - throw new DexException(message); - } - } catch (DexException e) { - throw e; - } catch (Throwable t) { - String message = t.getMessage(); - if (message == null) { - message = t.getClass().getCanonicalName(); - } - message = String.format(Messages.Dalvik_Error_s, message); - - throw new DexException(message, t); - } - } - - private String getDexFileName(File inputFile) { - // get the filename - String name = inputFile.getName(); - // remove the extension - int pos = name.lastIndexOf('.'); - if (pos != -1) { - name = name.substring(0, pos); - } - - // add a hash of the original file path - HashFunction hashFunction = Hashing.md5(); - HashCode hashCode = hashFunction.hashString(inputFile.getAbsolutePath(), Charsets.UTF_8); - - return name + "-" + hashCode.toString() + ".jar"; - } - - /** - * Executes aapt. If any error happen, files or the project will be marked. - * @param command The command for aapt to execute. Currently supported: package and crunch - * @param osManifestPath The path to the manifest file - * @param osResPath The path to the res folder - * @param osAssetsPath The path to the assets folder. This can be null. - * @param osOutFilePath The path to the temporary resource file to create, - * or in the case of crunching the path to the cache to create/update. - * @param configFilter The configuration filter for the resources to include - * (used with -c option, for example "port,en,fr" to include portrait, English and French - * resources.) - * @param versionCode optional version code to insert in the manifest during packaging. If <=0 - * then no value is inserted - * @throws AaptExecException - * @throws AaptResultException - */ - private void executeAapt(String aaptCommand, String osManifestPath, - List<String> osResPaths, String osAssetsPath, String osOutFilePath, - String configFilter, int versionCode) throws AaptExecException, AaptResultException { - IAndroidTarget target = Sdk.getCurrent().getTarget(mProject); - - String aapt = mBuildToolInfo.getPath(BuildToolInfo.PathId.AAPT); - - // Create the command line. - ArrayList<String> commandArray = new ArrayList<String>(); - commandArray.add(aapt); - commandArray.add(aaptCommand); - if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) { - commandArray.add("-v"); //$NON-NLS-1$ - } - - // Common to all commands - for (String path : osResPaths) { - commandArray.add("-S"); //$NON-NLS-1$ - commandArray.add(path); - } - - if (aaptCommand.equals(COMMAND_PACKAGE)) { - commandArray.add("-f"); //$NON-NLS-1$ - commandArray.add("--no-crunch"); //$NON-NLS-1$ - - // if more than one res, this means there's a library (or more) and we need - // to activate the auto-add-overlay - if (osResPaths.size() > 1) { - commandArray.add("--auto-add-overlay"); //$NON-NLS-1$ - } - - if (mDebugMode) { - commandArray.add("--debug-mode"); //$NON-NLS-1$ - } - - if (versionCode > 0) { - commandArray.add("--version-code"); //$NON-NLS-1$ - commandArray.add(Integer.toString(versionCode)); - } - - if (configFilter != null) { - commandArray.add("-c"); //$NON-NLS-1$ - commandArray.add(configFilter); - } - - // never compress apks. - commandArray.add("-0"); - commandArray.add("apk"); - - commandArray.add("-M"); //$NON-NLS-1$ - commandArray.add(osManifestPath); - - if (osAssetsPath != null) { - commandArray.add("-A"); //$NON-NLS-1$ - commandArray.add(osAssetsPath); - } - - commandArray.add("-I"); //$NON-NLS-1$ - commandArray.add(target.getPath(IAndroidTarget.ANDROID_JAR)); - - commandArray.add("-F"); //$NON-NLS-1$ - commandArray.add(osOutFilePath); - } else if (aaptCommand.equals(COMMAND_CRUNCH)) { - commandArray.add("-C"); //$NON-NLS-1$ - commandArray.add(osOutFilePath); - } - - String command[] = commandArray.toArray( - new String[commandArray.size()]); - - if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) { - StringBuilder sb = new StringBuilder(); - for (String c : command) { - sb.append(c); - sb.append(' '); - } - AdtPlugin.printToConsole(mProject, sb.toString()); - } - - // Benchmarking start - long startAaptTime = 0; - if (BENCHMARK_FLAG) { - String msg = "BENCHMARK ADT: Starting " + aaptCommand //$NON-NLS-1$ - + " call to Aapt"; //$NON-NLS-1$ - AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg); - startAaptTime = System.nanoTime(); - } - - // launch - try { - // launch the command line process - Process process = Runtime.getRuntime().exec(command); - - // list to store each line of stderr - ArrayList<String> stdErr = new ArrayList<String>(); - - // get the output and return code from the process - int returnCode = grabProcessOutput(mProject, process, stdErr); - - if (mVerbose) { - for (String stdErrString : stdErr) { - mOutStream.println(stdErrString); - } - } - if (returnCode != 0) { - throw new AaptResultException(returnCode, - stdErr.toArray(new String[stdErr.size()])); - } - } catch (IOException e) { - String msg = String.format(Messages.AAPT_Exec_Error_s, command[0]); - throw new AaptExecException(msg, e); - } catch (InterruptedException e) { - String msg = String.format(Messages.AAPT_Exec_Error_s, command[0]); - throw new AaptExecException(msg, e); - } - - // Benchmarking end - if (BENCHMARK_FLAG) { - String msg = "BENCHMARK ADT: Ending " + aaptCommand //$NON-NLS-1$ - + " call to Aapt.\nBENCHMARK ADT: Time Elapsed: " //$NON-NLS-1$ - + ((System.nanoTime() - startAaptTime)/MILLION) + "ms"; //$NON-NLS-1$ - AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg); - } - } - - /** - * Computes all the project output and dependencies that must go into building the apk. - * - * @param resMarker - * @throws CoreException - */ - private void gatherPaths(ResourceMarker resMarker) - throws CoreException { - IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - - // get a java project for the project. - IJavaProject javaProject = JavaCore.create(mProject); - - - // get the output of the main project - IPath path = javaProject.getOutputLocation(); - IResource outputResource = wsRoot.findMember(path); - if (outputResource != null && outputResource.getType() == IResource.FOLDER) { - mCompiledCodePaths.add(outputResource.getLocation().toOSString()); - } - - // we could use IJavaProject.getResolvedClasspath directly, but we actually - // want to see the containers themselves. - IClasspathEntry[] classpaths = javaProject.readRawClasspath(); - if (classpaths != null) { - for (IClasspathEntry e : classpaths) { - // ignore non exported entries, unless they're in the DEPEDENCIES container, - // in which case we always want it (there may be some older projects that - // have it as non exported). - if (e.isExported() || - (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER && - e.getPath().toString().equals(AdtConstants.CONTAINER_DEPENDENCIES))) { - handleCPE(e, javaProject, wsRoot, resMarker); - } - } - } - } - - private void handleCPE(IClasspathEntry entry, IJavaProject javaProject, - IWorkspaceRoot wsRoot, ResourceMarker resMarker) { - - // if this is a classpath variable reference, we resolve it. - if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - entry = JavaCore.getResolvedClasspathEntry(entry); - } - - if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { - IProject refProject = wsRoot.getProject(entry.getPath().lastSegment()); - try { - // ignore if it's an Android project, or if it's not a Java Project - if (refProject.hasNature(JavaCore.NATURE_ID) && - refProject.hasNature(AdtConstants.NATURE_DEFAULT) == false) { - IJavaProject refJavaProject = JavaCore.create(refProject); - - // get the output folder - IPath path = refJavaProject.getOutputLocation(); - IResource outputResource = wsRoot.findMember(path); - if (outputResource != null && outputResource.getType() == IResource.FOLDER) { - mCompiledCodePaths.add(outputResource.getLocation().toOSString()); - } - } - } catch (CoreException exception) { - // can't query the project nature? ignore - } - - } else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { - handleClasspathLibrary(entry, wsRoot, resMarker); - } else if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { - // get the container - try { - IClasspathContainer container = JavaCore.getClasspathContainer( - entry.getPath(), javaProject); - // ignore the system and default_system types as they represent - // libraries that are part of the runtime. - if (container != null && container.getKind() == IClasspathContainer.K_APPLICATION) { - IClasspathEntry[] entries = container.getClasspathEntries(); - for (IClasspathEntry cpe : entries) { - handleCPE(cpe, javaProject, wsRoot, resMarker); - } - } - } catch (JavaModelException jme) { - // can't resolve the container? ignore it. - AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", entry.getPath()); - } - } - } - - private void handleClasspathLibrary(IClasspathEntry e, IWorkspaceRoot wsRoot, - ResourceMarker resMarker) { - // get the IPath - IPath path = e.getPath(); - - IResource resource = wsRoot.findMember(path); - - if (resource != null && resource.getType() == IResource.PROJECT) { - // if it's a project we should just ignore it because it's going to be added - // later when we add all the referenced projects. - - } else if (SdkConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) { - // case of a jar file (which could be relative to the workspace or a full path) - if (resource != null && resource.exists() && - resource.getType() == IResource.FILE) { - mCompiledCodePaths.add(resource.getLocation().toOSString()); - } else { - // if the jar path doesn't match a workspace resource, - // then we get an OSString and check if this links to a valid file. - String osFullPath = path.toOSString(); - - File f = new File(osFullPath); - if (f.isFile()) { - mCompiledCodePaths.add(osFullPath); - } else { - String message = String.format( Messages.Couldnt_Locate_s_Error, - path); - // always output to the console - mOutStream.println(message); - - // put a marker - if (resMarker != null) { - resMarker.setWarning(mProject, message); - } - } - } - } else { - // this can be the case for a class folder. - if (resource != null && resource.exists() && - resource.getType() == IResource.FOLDER) { - mCompiledCodePaths.add(resource.getLocation().toOSString()); - } else { - // if the path doesn't match a workspace resource, - // then we get an OSString and check if this links to a valid folder. - String osFullPath = path.toOSString(); - - File f = new File(osFullPath); - if (f.isDirectory()) { - mCompiledCodePaths.add(osFullPath); - } - } - } - } - - /** - * Checks a {@link IFile} to make sure it should be packaged as standard resources. - * @param file the IFile representing the file. - * @return true if the file should be packaged as standard java resources. - */ - public static boolean checkFileForPackaging(IFile file) { - String name = file.getName(); - - String ext = file.getFileExtension(); - return ApkBuilder.checkFileForPackaging(name, ext); - } - - /** - * Checks whether an {@link IFolder} and its content is valid for packaging into the .apk as - * standard Java resource. - * @param folder the {@link IFolder} to check. - */ - public static boolean checkFolderForPackaging(IFolder folder) { - String name = folder.getName(); - return ApkBuilder.checkFolderForPackaging(name); - } - - /** - * Returns a list of {@link IJavaProject} matching the provided {@link IProject} objects. - * @param projects the IProject objects. - * @return a new list object containing the IJavaProject object for the given IProject objects. - * @throws CoreException - */ - public static List<IJavaProject> getJavaProjects(List<IProject> projects) throws CoreException { - ArrayList<IJavaProject> list = new ArrayList<IJavaProject>(); - - for (IProject p : projects) { - if (p.isOpen() && p.hasNature(JavaCore.NATURE_ID)) { - - list.add(JavaCore.create(p)); - } - } - - return list; - } - - /** - * Get the stderr output of a process and return when the process is done. - * @param process The process to get the output from - * @param stderr The array to store the stderr output - * @return the process return code. - * @throws InterruptedException - */ - public final static int grabProcessOutput( - final IProject project, - final Process process, - final ArrayList<String> stderr) - throws InterruptedException { - - return GrabProcessOutput.grabProcessOutput( - process, - Wait.WAIT_FOR_READERS, // we really want to make sure we get all the output! - new IProcessOutput() { - - @SuppressWarnings("unused") - @Override - public void out(@Nullable String line) { - if (line != null) { - // If benchmarking always print the lines that - // correspond to benchmarking info returned by ADT - if (BENCHMARK_FLAG && line.startsWith("BENCHMARK:")) { //$NON-NLS-1$ - AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, - project, line); - } else { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, - project, line); - } - } - } - - @Override - public void err(@Nullable String line) { - if (line != null) { - stderr.add(line); - if (BuildVerbosity.VERBOSE == AdtPrefs.getPrefs().getBuildVerbosity()) { - AdtPlugin.printErrorToConsole(project, line); - } - } - } - }); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchDialog.java deleted file mode 100644 index 20bee5dac..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchDialog.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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.ide.eclipse.adt.internal.editors.IconFactory; - -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.dialogs.TitleAreaDialog; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Link; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.browser.IWebBrowser; - -import java.net.URL; - -/** - * Dialog shown by the {@link ConvertSwitchQuickFixProcessor}. This is a custom - * dialog rather than a plain {@link MessageDialog} such that we can show a link - * and point to a web page for more info. - */ -class ConvertSwitchDialog extends TitleAreaDialog implements SelectionListener { - /** URL containing more info */ - private static final String URL = "http://tools.android.com/tips/non-constant-fields"; //$NON-NLS-1$ - - private final String mField; - - private Link mLink; - - /** - * Create the dialog. - * @param parentShell the parent shell - * @param field the field name we're warning about - */ - public ConvertSwitchDialog(Shell parentShell, String field) { - super(parentShell); - mField = field; - Image image = IconFactory.getInstance().getIcon("android-64"); //$NON-NLS-1$ - setTitleImage(image); - } - - @Override - protected Control createDialogArea(Composite parent) { - String text = String.format( - "As of ADT 14, the resource fields (such as %1$s) are no longer constants " + - "when defined in library projects. This is necessary to make library " + - "projects reusable without recompiling them.\n" + - "\n" + - "One consequence of this is that you can no longer use the fields directly " + - "in switch statements. You must use an if-else chain instead.\n" + - "\n" + - "Eclipse can automatically convert from a switch statement to an if-else " + - "statement. Just place the caret on the switch keyword and invoke " + - "Quick Fix (Ctrl-1 on Windows and Linux, Cmd-1 on Mac), then select " + - "\"Convert 'switch' to 'if-else'\".\n" + - "\n" + - "For more information, see <a href=\"" + URL + "\">" + URL + "</a>", - mField); - - Composite area = (Composite) super.createDialogArea(parent); - Composite container = new Composite(area, SWT.NONE); - container.setLayout(new GridLayout(1, false)); - container.setLayoutData(new GridData(GridData.FILL_BOTH)); - - mLink = new Link(container, SWT.NONE); - mLink.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true, 1, 1)); - mLink.setText(text); - mLink.addSelectionListener(this); - - setMessage("Non-Constant Expressions: Migration Necessary", IMessageProvider.INFORMATION); - - return area; - } - - @Override - protected void createButtonsForButtonBar(Composite parent) { - createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); - createButton(parent, IDialogConstants.HELP_ID, IDialogConstants.HELP_LABEL, false); - } - - @Override - protected Point getInitialSize() { - return new Point(500, 400); - } - - private void showWebPage() { - try { - IWorkbench workbench = PlatformUI.getWorkbench(); - IWebBrowser browser = workbench.getBrowserSupport().getExternalBrowser(); - browser.openURL(new URL(URL)); - } catch (Exception e) { - String message = String.format("Could not open browser. Vist\n%1$s\ninstead.", - URL); - MessageDialog.openError(getShell(), "Browser Error", message); - } - - } - - @Override - protected void buttonPressed(int buttonId) { - if (buttonId == IDialogConstants.HELP_ID) { - showWebPage(); - } else { - super.buttonPressed(buttonId); - } - } - - // ---- Implements SelectionListener ---- - - @Override - public void widgetSelected(SelectionEvent e) { - if (e.getSource() == mLink) { - showWebPage(); - } - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchQuickFixProcessor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchQuickFixProcessor.java deleted file mode 100644 index a99dc7601..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchQuickFixProcessor.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AdtUtils; - -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jdt.core.IBuffer; -import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.QualifiedName; -import org.eclipse.jdt.ui.text.java.IInvocationContext; -import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; -import org.eclipse.jdt.ui.text.java.IProblemLocation; -import org.eclipse.jdt.ui.text.java.IQuickFixProcessor; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.contentassist.IContextInformation; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.editors.text.TextFileDocumentProvider; -import org.eclipse.ui.texteditor.IDocumentProvider; - -import java.util.List; - -/** - * A quickfix processor which looks for "case expressions must be constant - * expressions" errors, and if they apply to fields in a class named R, it - * assumes this is code related to library projects that are no longer final and - * will need to be rewritten to use if-else chains instead. - */ -public class ConvertSwitchQuickFixProcessor implements IQuickFixProcessor { - /** Constructs a new {@link ConvertSwitchQuickFixProcessor} */ - public ConvertSwitchQuickFixProcessor() { - } - - @Override - public boolean hasCorrections(ICompilationUnit cu, int problemId) { - return problemId == IProblem.NonConstantExpression; - } - - @Override - public IJavaCompletionProposal[] getCorrections(IInvocationContext context, - IProblemLocation[] location) throws CoreException { - if (location == null || location.length == 0) { - return null; - } - ASTNode coveringNode = context.getCoveringNode(); - if (coveringNode == null) { - return null; - } - - // Look up the fully qualified name of the non-constant expression, if any, and - // make sure it's R-something. - if (coveringNode.getNodeType() == ASTNode.SIMPLE_NAME) { - coveringNode = coveringNode.getParent(); - if (coveringNode == null) { - return null; - } - } - if (coveringNode.getNodeType() != ASTNode.QUALIFIED_NAME) { - return null; - } - QualifiedName name = (QualifiedName) coveringNode; - if (!name.getFullyQualifiedName().startsWith("R.")) { //$NON-NLS-1$ - return null; - } - - IProblemLocation error = location[0]; - int errorStart = error.getOffset(); - int errorLength = error.getLength(); - int caret = context.getSelectionOffset(); - - // Even though the hasCorrections() method above will return false for everything - // other than non-constant expression errors, it turns out this getCorrections() - // method will ALSO be called on lines where there is no such error. In particular, - // if you have an invalid cast expression like this: - // Button button = findViewById(R.id.textView); - // then this method will be called, and the expression will pass all of the above - // checks. However, we -don't- want to show a migrate code suggestion in that case! - // Therefore, we'll need to check if we're *actually* on a line with the given - // problem. - // - // Unfortunately, we don't get passed the problemId again, and there's no access - // to it. So instead we'll need to look up the markers on the line, and see - // if we actually have a constant expression warning. This is not pretty!! - - boolean foundError = false; - ICompilationUnit compilationUnit = context.getCompilationUnit(); - IResource file = compilationUnit.getResource(); - if (file != null) { - IDocumentProvider provider = new TextFileDocumentProvider(); - try { - provider.connect(file); - IDocument document = provider.getDocument(file); - if (document != null) { - List<IMarker> markers = AdtUtils.findMarkersOnLine(IMarker.PROBLEM, - file, document, errorStart); - for (IMarker marker : markers) { - String message = marker.getAttribute(IMarker.MESSAGE, ""); - // There are no other attributes in the marker we can use to identify - // the exact error, so we'll need to resort to the actual message - // text even though that would not work if the messages had been - // localized... This can also break if the error messages change. Yuck. - if (message.contains("constant expressions")) { //$NON-NLS-1$ - foundError = true; - } - } - } - } catch (Exception e) { - AdtPlugin.log(e, "Can't validate error message in %1$s", file.getName()); - } finally { - provider.disconnect(file); - } - } - if (!foundError) { - // Not a constant-expression warning, so do nothing - return null; - } - - IBuffer buffer = compilationUnit.getBuffer(); - boolean sameLine = false; - // See if the caret is on the same line as the error - if (caret <= errorStart) { - // Search backwards to beginning of line - for (int i = errorStart; i >= 0; i--) { - if (i <= caret) { - sameLine = true; - break; - } - char c = buffer.getChar(i); - if (c == '\n') { - break; - } - } - } else { - // Search forwards to the end of the line - for (int i = errorStart + errorLength, n = buffer.getLength(); i < n; i++) { - if (i >= caret) { - sameLine = true; - break; - } - char c = buffer.getChar(i); - if (c == '\n') { - break; - } - } - } - - if (sameLine) { - String expression = buffer.getText(errorStart, errorLength); - return new IJavaCompletionProposal[] { - new MigrateProposal(expression) - }; - } - - return null; - } - - /** Proposal for the quick fix which displays an explanation message to the user */ - private class MigrateProposal implements IJavaCompletionProposal { - private String mExpression; - - private MigrateProposal(String expression) { - mExpression = expression; - } - - @Override - public void apply(IDocument document) { - Shell shell = AdtPlugin.getShell(); - ConvertSwitchDialog dialog = new ConvertSwitchDialog(shell, mExpression); - dialog.open(); - } - - @Override - public Point getSelection(IDocument document) { - return null; - } - - @Override - public String getAdditionalProposalInfo() { - return "As of ADT 14, resource fields cannot be used as switch cases. Invoke this " + - "fix to get more information."; - } - - @Override - public String getDisplayString() { - return "Migrate Android Code"; - } - - @Override - public Image getImage() { - return AdtPlugin.getAndroidLogo(); - } - - @Override - public IContextInformation getContextInformation() { - return null; - } - - @Override - public int getRelevance() { - return 50; - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DefaultSourceChangeHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DefaultSourceChangeHandler.java deleted file mode 100644 index ea0d695d1..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DefaultSourceChangeHandler.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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 org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResourceDelta; - -import java.util.HashSet; -import java.util.Set; - -/** - * Base source change handler for the {@link SourceProcessor} classes. - * - * It can be used as is, as long as the matching {@link SourceProcessor} properly implements - * its abstract methods, and the processor does not output resource files, - * or can be extended to provide custom implementation for: - * {@link #handleSourceFile(IFile, int)} - * {@link #handleGeneratedFile(IFile, int)} - * {@link #handleResourceFile(IFile, int)} - * {@link #filterResourceFolder(IContainer)} - * - */ -public class DefaultSourceChangeHandler implements SourceChangeHandler { - - private SourceProcessor mProcessor; - - /** List of source files found that are modified or new. */ - private final Set<IFile> mToCompile = new HashSet<IFile>(); - - /** List of source files that have been removed. */ - private final Set<IFile> mRemoved = new HashSet<IFile>(); - - @Override - public boolean handleGeneratedFile(IFile file, int kind) { - if (kind == IResourceDelta.REMOVED || kind == IResourceDelta.CHANGED) { - IFile sourceFile = mProcessor.isOutput(file); - if (sourceFile != null) { - mToCompile.add(sourceFile); - return true; - } - } - - return false; - } - - @Override - public void handleSourceFile(IFile file, int kind) { - // first the file itself if this is a match for the processor's extension - if (mProcessor.getExtensions().contains(file.getFileExtension())) { - if (kind == IResourceDelta.REMOVED) { - mRemoved.add(file); - } else { - mToCompile.add(file); - } - } - - // now the dependencies. In all case we compile the files that depend on the - // added/changed/removed file. - mToCompile.addAll(mProcessor.isDependency(file)); - } - - protected void addFileToCompile(IFile file) { - mToCompile.add(file); - } - - Set<IFile> getFilesToCompile() { - return mToCompile; - } - - protected void addRemovedFile(IFile file) { - mRemoved.add(file); - } - - Set<IFile> getRemovedFiles() { - return mRemoved; - } - - public void reset() { - mToCompile.clear(); - mRemoved.clear(); - } - - protected SourceProcessor getProcessor() { - return mProcessor; - } - - void init(SourceProcessor processor) { - mProcessor = processor; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexException.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexException.java deleted file mode 100644 index 032e5e646..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010 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; - -/** - * Exception throw when dx fails. - * - */ -public final class DexException extends Exception { - private static final long serialVersionUID = 1L; - - DexException(String message) { - super(message); - } - - DexException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java deleted file mode 100644 index 3f882842b..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2008 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.SdkConstants; -import com.android.ide.eclipse.adt.AdtPlugin; - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; - -import java.io.File; -import java.io.PrintStream; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Collection; - -/** - * Wrapper to access dx.jar through reflection. - * <p/>Since there is no proper api to call the method in the dex library, this wrapper is going - * to access it through reflection. - */ -public final class DexWrapper { - - private final static String DEX_MAIN = "com.android.dx.command.dexer.Main"; //$NON-NLS-1$ - private final static String DEX_CONSOLE = "com.android.dx.command.DxConsole"; //$NON-NLS-1$ - private final static String DEX_ARGS = "com.android.dx.command.dexer.Main$Arguments"; //$NON-NLS-1$ - - private final static String MAIN_RUN = "run"; //$NON-NLS-1$ - - private Method mRunMethod; - - private Constructor<?> mArgConstructor; - private Field mArgOutName; - private Field mArgVerbose; - private Field mArgJarOutput; - private Field mArgFileNames; - private Field mArgForceJumbo; - - private Field mConsoleOut; - private Field mConsoleErr; - - /** - * Loads the dex library from a file path. - * - * The loaded library can be used via - * {@link DexWrapper#run(String, String[], boolean, PrintStream, PrintStream)}. - * - * @param osFilepath the location of the dx.jar file. - * @return an IStatus indicating the result of the load. - */ - public synchronized IStatus loadDex(String osFilepath) { - try { - File f = new File(osFilepath); - if (f.isFile() == false) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format( - Messages.DexWrapper_s_does_not_exists, osFilepath)); - } - URL url = f.toURI().toURL(); - - @SuppressWarnings("resource") - URLClassLoader loader = new URLClassLoader(new URL[] { url }, - DexWrapper.class.getClassLoader()); - - // get the classes. - Class<?> mainClass = loader.loadClass(DEX_MAIN); - Class<?> consoleClass = loader.loadClass(DEX_CONSOLE); - Class<?> argClass = loader.loadClass(DEX_ARGS); - - try { - // now get the fields/methods we need - mRunMethod = mainClass.getMethod(MAIN_RUN, argClass); - - mArgConstructor = argClass.getConstructor(); - mArgOutName = argClass.getField("outName"); //$NON-NLS-1$ - mArgJarOutput = argClass.getField("jarOutput"); //$NON-NLS-1$ - mArgFileNames = argClass.getField("fileNames"); //$NON-NLS-1$ - mArgVerbose = argClass.getField("verbose"); //$NON-NLS-1$ - mArgForceJumbo = argClass.getField("forceJumbo"); //$NON-NLS-1$ - - mConsoleOut = consoleClass.getField("out"); //$NON-NLS-1$ - mConsoleErr = consoleClass.getField("err"); //$NON-NLS-1$ - - } catch (SecurityException e) { - return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_API, e); - } catch (NoSuchMethodException e) { - return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Method, e); - } catch (NoSuchFieldException e) { - return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Field, e); - } - - return Status.OK_STATUS; - } catch (MalformedURLException e) { - // really this should not happen. - return createErrorStatus( - String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e); - } catch (ClassNotFoundException e) { - return createErrorStatus( - String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e); - } - } - - /** - * Removes any reference to the dex library. - * <p/> - * {@link #loadDex(String)} must be called on the wrapper - * before {@link #run(String, String[], boolean, PrintStream, PrintStream)} can - * be used again. - */ - public synchronized void unload() { - mRunMethod = null; - mArgConstructor = null; - mArgOutName = null; - mArgJarOutput = null; - mArgFileNames = null; - mArgVerbose = null; - mConsoleOut = null; - mConsoleErr = null; - System.gc(); - } - - /** - * Runs the dex command. - * The wrapper must have been initialized via {@link #loadDex(String)} first. - * - * @param osOutFilePath the OS path to the outputfile (classes.dex - * @param osFilenames list of input source files (.class and .jar files) - * @param forceJumbo force jumbo mode. - * @param verbose verbose mode. - * @param outStream the stdout console - * @param errStream the stderr console - * @return the integer return code of com.android.dx.command.dexer.Main.run() - * @throws CoreException - */ - public synchronized int run(String osOutFilePath, Collection<String> osFilenames, - boolean forceJumbo, boolean verbose, - PrintStream outStream, PrintStream errStream) throws CoreException { - - assert mRunMethod != null; - assert mArgConstructor != null; - assert mArgOutName != null; - assert mArgJarOutput != null; - assert mArgFileNames != null; - assert mArgForceJumbo != null; - assert mArgVerbose != null; - assert mConsoleOut != null; - assert mConsoleErr != null; - - if (mRunMethod == null) { - throw new CoreException(createErrorStatus( - String.format(Messages.DexWrapper_Unable_To_Execute_Dex_s, - "wrapper was not properly loaded first"), - null /*exception*/)); - } - - try { - // set the stream - mConsoleErr.set(null /* obj: static field */, errStream); - mConsoleOut.set(null /* obj: static field */, outStream); - - // create the Arguments object. - Object args = mArgConstructor.newInstance(); - mArgOutName.set(args, osOutFilePath); - mArgFileNames.set(args, osFilenames.toArray(new String[osFilenames.size()])); - mArgJarOutput.set(args, osOutFilePath.endsWith(SdkConstants.DOT_JAR)); - mArgForceJumbo.set(args, forceJumbo); - mArgVerbose.set(args, verbose); - - // call the run method - Object res = mRunMethod.invoke(null /* obj: static method */, args); - - if (res instanceof Integer) { - return ((Integer)res).intValue(); - } - - return -1; - } catch (Exception e) { - Throwable t = e; - while (t.getCause() != null) { - t = t.getCause(); - } - - String msg = t.getMessage(); - if (msg == null) { - msg = String.format("%s. Check the Eclipse log for stack trace.", - t.getClass().getName()); - } - - throw new CoreException(createErrorStatus( - String.format(Messages.DexWrapper_Unable_To_Execute_Dex_s, msg), t)); - } - } - - private static IStatus createErrorStatus(String message, Throwable e) { - AdtPlugin.log(e, message); - AdtPlugin.printErrorToConsole(Messages.DexWrapper_Dex_Loader, message); - - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, message, e); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ExecResultException.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ExecResultException.java deleted file mode 100644 index 63a7a6946..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ExecResultException.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2010 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; - -/** - * Base exception class containing the error code and output of an external tool failed exec. - * - */ -class ExecResultException extends Exception { - private static final long serialVersionUID = 1L; - - private final int mErrorCode; - private final String[] mOutput; - - protected ExecResultException(int errorCode, String[] output) { - mErrorCode = errorCode; - mOutput = output; - } - - /** - * Returns the full output of aapt. - */ - public String[] getOutput() { - return mOutput; - } - - /** - * Returns the aapt return code. - */ - public int getErrorCode() { - return mErrorCode; - } - - public String getLabel() { - return "Command-line"; - } - - @Override - public String toString() { - String result = String.format("%1$s Error %2$d", getLabel(), mErrorCode); - if (mOutput != null && mOutput.length > 0) { - // Note : the "error detail" window in Eclipse seem to ignore the \n, - // so we prefix them with a space. It's not optimal but it's slightly readable. - result += " \nOutput:"; - for (String o : mOutput) { - if (o != null) { - result += " \n" + o; - } - } - } - return result; - } - - @Override - public String getMessage() { - return toString(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/Messages.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/Messages.java deleted file mode 100644 index 9ceba205d..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/Messages.java +++ /dev/null @@ -1,150 +0,0 @@ - -package com.android.ide.eclipse.adt.internal.build; - -import org.eclipse.osgi.util.NLS; - -public class Messages extends NLS { - private static final String BUNDLE_NAME = "com.android.ide.eclipse.adt.internal.build.build_messages"; //$NON-NLS-1$ - - public static String AAPT_Error; - - public static String AAPT_Exec_Error_s; - - public static String AAPT_Exec_Error_d; - - public static String AAPT_Exec_Error_Other_s; - - public static String Added_s_s_Needs_Updating; - - public static String AIDL_Exec_Error_s; - - public static String AIDL_Exec_Error_d; - - public static String AIDL_Java_Conflict; - - public static String ApkBuilder_Certificate_Expired_on_s; - - public static String ApkBuilder_JAVA_HOME_is_s; - - public static String ApkBuilder_Packaging_s; - - public static String ApkBuilder_Packaging_s_into_s; - - public static String ApkBuilder_s_Conflict_with_file_s; - - public static String ApkBuilder_Signing_Key_Creation_s; - - public static String ApkBuilder_Unable_To_Gey_Key; - - public static String ApkBuilder_UnableBuild_Dex_Not_loaded; - - public static String ApkBuilder_Update_or_Execute_manually_s; - - public static String ApkBuilder_Using_Default_Key; - - public static String ApkBuilder_Using_s_To_Sign; - - public static String Checking_Package_Change; - - public static String Compiler_Compliance_Error; - - public static String Couldnt_Locate_s_Error; - - public static String Dalvik_Error_d; - - public static String Dalvik_Error_s; - - public static String Delete_Obsolete_Error; - - public static String DexWrapper_Dex_Loader; - - public static String DexWrapper_Failed_to_load_s; - - public static String DexWrapper_s_does_not_exists; - - public static String DexWrapper_SecuryEx_Unable_To_Find_API; - - public static String DexWrapper_SecuryEx_Unable_To_Find_Field; - - public static String DexWrapper_SecuryEx_Unable_To_Find_Method; - - public static String DexWrapper_Unable_To_Execute_Dex_s; - - public static String DX_Jar_Error; - - public static String Failed_To_Get_Output; - - public static String Final_Archive_Error_s; - - public static String Incompatible_VM_Warning; - - public static String Marker_Delete_Error; - - public static String No_SDK_Setup_Error; - - public static String Nothing_To_Compile; - - public static String Output_Missing; - - public static String Package_s_Doesnt_Exist_Error; - - public static String Preparing_Generated_Files; - - public static String Project_Has_Errors; - - public static String Refreshing_Res; - - public static String Removing_Generated_Classes; - - public static String Requires_1_5_Error; - - public static String Requires_Class_Compatibility_s; - - public static String Requires_Compiler_Compliance_s; - - public static String Requires_Source_Compatibility_s; - - public static String s_Contains_Xml_Error; - - public static String s_Doesnt_Declare_Package_Error; - - public static String s_File_Missing; - - public static String s_Missing_Repackaging; - - public static String s_Modified_Manually_Recreating_s; - - public static String s_Modified_Recreating_s; - - public static String s_Removed_Recreating_s; - - public static String s_Removed_s_Needs_Updating; - - public static String Start_Full_Apk_Build; - - public static String Start_Full_Pre_Compiler; - - public static String Skip_Post_Compiler; - - public static String Start_Full_Post_Compiler; - - public static String Start_Inc_Apk_Build; - - public static String Start_Inc_Pre_Compiler; - - public static String Unparsed_AAPT_Errors; - - public static String Unparsed_AIDL_Errors; - - public static String Xml_Error; - - public static String Proguard_Exec_Error; - - static { - // initialize resource bundle - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } - - private Messages() { - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/NativeLibInJarException.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/NativeLibInJarException.java deleted file mode 100644 index 18f4ae7aa..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/NativeLibInJarException.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010 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.sdklib.build.ApkBuilder.JarStatus; - -/** - * Exception throw when native libraries are detected in jar file. - * - */ -public final class NativeLibInJarException extends Exception { - private static final long serialVersionUID = 1L; - - private final JarStatus mStatus; - private final String mLibName; - private final String[] mConsoleMsgs; - - NativeLibInJarException(JarStatus status, String message, String libName, - String[] consoleMsgs) { - super(message); - mStatus = status; - mLibName = libName; - mConsoleMsgs = consoleMsgs; - } - - /** - * Returns the {@link JarStatus} object containing the information about the libraries that - * were found. - */ - public JarStatus getStatus() { - return mStatus; - } - - /** - * Returns the name of the jar file containing the native libraries. - */ - public String getJarName() { - return mLibName; - } - - /** - * Returns additional information that should be shown to the user. - */ - public String[] getAdditionalInfo() { - return mConsoleMsgs; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ProguardExecException.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ProguardExecException.java deleted file mode 100644 index 3eb688b3e..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ProguardExecException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2010 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; - -/** - * Exception thrown when the execution of proguard fails. - * - */ -public final class ProguardExecException extends Exception { - private static final long serialVersionUID = 1L; - - ProguardExecException(String message, Throwable cause) { - super(message, cause); - } -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ProguardResultException.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ProguardResultException.java deleted file mode 100644 index 54246b337..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ProguardResultException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2010 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; - -/** - * Exception thrown when aapt reports an error in the resources. - * - */ -public final class ProguardResultException extends ExecResultException { - private static final long serialVersionUID = 1L; - - ProguardResultException(int errorCode, String[] output) { - super(errorCode, output); - } - - @Override - public String getLabel() { - return "Proguard"; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/RenderScriptLauncher.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/RenderScriptLauncher.java deleted file mode 100644 index 1d3c7bd3a..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/RenderScriptLauncher.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * 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; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/RsSourceChangeHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/RsSourceChangeHandler.java deleted file mode 100644 index 715895a0c..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/RsSourceChangeHandler.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2013 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.SdkConstants; -import com.android.annotations.NonNull; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.sdklib.build.RenderScriptChecker; - -import org.eclipse.core.resources.IFile; - -import java.io.File; -import java.io.IOException; -import java.util.Set; - -public class RsSourceChangeHandler implements SourceChangeHandler { - - private final RenderScriptChecker mChecker; - private boolean mIsCheckerLoaded = false; - - private boolean mMustCompile = false; - - public RsSourceChangeHandler(@NonNull RenderScriptChecker checker) { - mChecker = checker; - } - - @Override - public boolean handleGeneratedFile(IFile file, int kind) { - if (mMustCompile) { - return false; - } - - if (!mIsCheckerLoaded) { - try { - mChecker.loadDependencies(); - } catch (IOException e) { - // failed to load the dependency files, force a compilation, log the error. - AdtPlugin.log(e, "Failed to read dependency files"); - mMustCompile = true; - return false; - } - } - - Set<File> oldOutputs = mChecker.getOldOutputs(); - // mustCompile is always false here. - mMustCompile = oldOutputs.contains(file.getLocation().toFile()); - return mMustCompile; - } - - @Override - public void handleSourceFile(IFile file, int kind) { - if (mMustCompile) { - return; - } - - String ext = file.getFileExtension(); - if (SdkConstants.EXT_RS.equals(ext) || - SdkConstants.EXT_FS.equals(ext) || - SdkConstants.EXT_RSH.equals(ext)) { - mMustCompile = true; - } - } - - public boolean mustCompile() { - return mMustCompile; - } - - @NonNull - public RenderScriptChecker getChecker() { - return mChecker; - } - - public void prepareFullBuild() { - mMustCompile = true; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/SourceChangeHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/SourceChangeHandler.java deleted file mode 100644 index 12a055106..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/SourceChangeHandler.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 org.eclipse.core.resources.IFile; - -public interface SourceChangeHandler { - - boolean handleGeneratedFile(IFile file, int kind); - void handleSourceFile(IFile file, int kind); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/SourceFileData.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/SourceFileData.java deleted file mode 100644 index d06bf1613..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/SourceFileData.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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 org.eclipse.core.resources.IFile; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Data for Android-specific source files. It contains a list of output files and a list - * of dependencies. - * The source file itself is a implied dependency and is not meant to be in the dependency list. - */ -public class SourceFileData { - - private final IFile mSourceFile; - private final List<IFile> mOutputFiles = new ArrayList<IFile>(); - private final List<IFile> mDependencyFiles = new ArrayList<IFile>(); - - public SourceFileData(IFile sourceFile) { - this(sourceFile, null, null); - } - - SourceFileData(IFile sourceFile, - List<IFile> outputFiles, List<IFile> dependencyFiles) { - mSourceFile = sourceFile; - if (outputFiles != null) { - mOutputFiles.addAll(outputFiles); - } - if (dependencyFiles != null) { - mDependencyFiles.addAll(dependencyFiles); - } - } - - SourceFileData(IFile sourceFile, IFile outputFile) { - mSourceFile = sourceFile; - if (outputFile != null) { - mOutputFiles.add(outputFile); - } - } - - /** - * Returns the source file as an {@link IFile} - */ - public IFile getSourceFile() { - return mSourceFile; - } - - /** - * Returns whether the given file is a dependency for this source file. - * <p/>Note that the source file itself is not tested against. Therefore if - * {@code file.equals(getSourceFile()} returns {@code true}, this method will return - * {@code false}. - * @param file the file to check against - * @return true if the given file is a dependency for this source file. - */ - public boolean dependsOn(IFile file) { - return mDependencyFiles.contains(file); - } - - /** - * Returns whether the given file is an ouput of this source file. - * @param file the file to test. - * @return true if the file is an output file. - */ - public boolean generated(IFile file) { - return mOutputFiles.contains(file); - } - - void setOutputFiles(List<IFile> outputFiles) { - mOutputFiles.clear(); - if (outputFiles != null) { - mOutputFiles.addAll(outputFiles); - } - } - - void setOutputFile(IFile outputFile) { - mOutputFiles.clear(); - if (outputFile != null) { - mOutputFiles.add(outputFile); - } - } - - void setDependencyFiles(List<IFile> depFiles) { - mDependencyFiles.clear(); - if (depFiles != null) { - mDependencyFiles.addAll(depFiles); - } - } - - public List<IFile> getDependencyFiles() { - return mDependencyFiles; - } - - /** - * Shortcut access to the first output file. This is useful for generator that only output - * one file. - */ - public IFile getOutput() { - if (mOutputFiles.size() > 0) { - return mOutputFiles.get(0); - } - - return null; - } - - public List<IFile> getOutputFiles() { - return Collections.unmodifiableList(mOutputFiles); - } - - @Override - public String toString() { - return "NonJavaFileBundle [mSourceFile=" + mSourceFile + ", mGeneratedFiles=" - + mOutputFiles + ", mDependencies=" + mDependencyFiles + "]"; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/SourceProcessor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/SourceProcessor.java deleted file mode 100644 index 1fc3e4e53..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/SourceProcessor.java +++ /dev/null @@ -1,454 +0,0 @@ -/* - * 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.SdkConstants; -import com.android.annotations.NonNull; -import com.android.ide.eclipse.adt.internal.build.builders.BaseBuilder; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.sdklib.BuildToolInfo; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.core.IJavaProject; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -/** - * Base class to handle generated java code. - * - * It provides management for modified source file list, deleted source file list, reconciliation - * of previous lists, storing the current state of the build. - * - */ -public abstract class SourceProcessor { - - public final static int COMPILE_STATUS_NONE = 0; - public final static int COMPILE_STATUS_CODE = 0x1; - public final static int COMPILE_STATUS_RES = 0x2; - - /** List of all source files, their dependencies, and their output. */ - private final Map<IFile, SourceFileData> mFiles = new HashMap<IFile, SourceFileData>(); - - private final IJavaProject mJavaProject; - private BuildToolInfo mBuildToolInfo; - private final IFolder mGenFolder; - private final DefaultSourceChangeHandler mDeltaVisitor; - - /** List of source files pending compilation at the next build */ - private final List<IFile> mToCompile = new ArrayList<IFile>(); - - /** List of removed source files pending cleaning at the next build. */ - private final List<IFile> mRemoved = new ArrayList<IFile>(); - - private int mLastCompilationStatus = COMPILE_STATUS_NONE; - - /** - * Quotes a path inside "". If the platform is not windows, the path is returned as is. - * @param path the path to quote - * @return the quoted path. - */ - public static String quote(String path) { - if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) { - if (path.endsWith(File.separator)) { - path = path.substring(0, path.length() -1); - } - return "\"" + path + "\""; - } - - return path; - } - - protected SourceProcessor( - @NonNull IJavaProject javaProject, - @NonNull BuildToolInfo buildToolInfo, - @NonNull IFolder genFolder, - @NonNull DefaultSourceChangeHandler deltaVisitor) { - mJavaProject = javaProject; - mBuildToolInfo = buildToolInfo; - mGenFolder = genFolder; - mDeltaVisitor = deltaVisitor; - - mDeltaVisitor.init(this); - - IProject project = javaProject.getProject(); - - // get all the source files - buildSourceFileList(); - - // load the known dependencies - loadOutputAndDependencies(); - - boolean mustCompile = loadState(project); - - // if we stored that we have to compile some files, we build the list that will compile them - // all. For now we have to reuse the full list since we don't know which files needed - // compilation. - if (mustCompile) { - mToCompile.addAll(mFiles.keySet()); - } - } - - protected SourceProcessor( - @NonNull IJavaProject javaProject, - @NonNull BuildToolInfo buildToolInfo, - @NonNull IFolder genFolder) { - this(javaProject, buildToolInfo, genFolder, new DefaultSourceChangeHandler()); - } - - public void setBuildToolInfo(BuildToolInfo buildToolInfo) { - mBuildToolInfo = buildToolInfo; - } - - - /** - * Returns whether the given file is an output of this processor by return the source - * file that generated it. - * @param file the file to test. - * @return the source file that generated the given file or null. - */ - IFile isOutput(IFile file) { - for (SourceFileData data : mFiles.values()) { - if (data.generated(file)) { - return data.getSourceFile(); - } - } - - return null; - } - - /** - * Returns whether the given file is a dependency for other files by returning a list - * of file depending on the given file. - * @param file the file to test. - * @return a list of files that depend on the given file or an empty list if there - * are no matches. - */ - List<IFile> isDependency(IFile file) { - ArrayList<IFile> files = new ArrayList<IFile>(); - for (SourceFileData data : mFiles.values()) { - if (data.dependsOn(file)) { - files.add(data.getSourceFile()); - } - } - - return files; - } - - void addData(SourceFileData data) { - mFiles.put(data.getSourceFile(), data); - } - - SourceFileData getFileData(IFile file) { - return mFiles.get(file); - } - - Collection<SourceFileData> getAllFileData() { - return mFiles.values(); - } - - public final DefaultSourceChangeHandler getChangeHandler() { - return mDeltaVisitor; - } - - final IJavaProject getJavaProject() { - return mJavaProject; - } - - final BuildToolInfo getBuildToolInfo() { - return mBuildToolInfo; - } - - final IFolder getGenFolder() { - return mGenFolder; - } - - final List<IFile> getToCompile() { - return mToCompile; - } - - final List<IFile> getRemovedFile() { - return mRemoved; - } - - final void addFileToCompile(IFile file) { - mToCompile.add(file); - } - - public final void prepareFullBuild(IProject project) { - mDeltaVisitor.reset(); - - mToCompile.clear(); - mRemoved.clear(); - - // get all the source files - buildSourceFileList(); - - mToCompile.addAll(mFiles.keySet()); - - saveState(project); - } - - public final void doneVisiting(IProject project) { - // merge the previous file modification lists and the new one. - mergeFileModifications(mDeltaVisitor); - - mDeltaVisitor.reset(); - - saveState(project); - } - - /** - * Returns the extension of the source files handled by this processor. - * @return - */ - protected abstract Set<String> getExtensions(); - - protected abstract String getSavePropertyName(); - - /** - * Compiles the source files and return a status bitmask of the type of file that was generated. - * - */ - public final int compileFiles(BaseBuilder builder, - IProject project, IAndroidTarget projectTarget, - List<IPath> sourceFolders, List<File> libraryProjectsOut, IProgressMonitor monitor) - throws CoreException { - - mLastCompilationStatus = COMPILE_STATUS_NONE; - - if (mToCompile.size() == 0 && mRemoved.size() == 0) { - return mLastCompilationStatus; - } - - // if a source file is being removed before we managed to compile it, it'll be in - // both list. We *need* to remove it from the compile list or it'll never go away. - for (IFile sourceFile : mRemoved) { - int pos = mToCompile.indexOf(sourceFile); - if (pos != -1) { - mToCompile.remove(pos); - } - } - - // list of files that have failed compilation. - List<IFile> stillNeedCompilation = new ArrayList<IFile>(); - - doCompileFiles(mToCompile, builder, project, projectTarget, sourceFolders, - stillNeedCompilation, libraryProjectsOut, monitor); - - mToCompile.clear(); - mToCompile.addAll(stillNeedCompilation); - - // Remove the files created from source files that have been removed. - for (IFile sourceFile : mRemoved) { - // look if we already know the output - SourceFileData data = getFileData(sourceFile); - if (data != null) { - doRemoveFiles(data); - } - } - - // remove the associated file data. - for (IFile removedFile : mRemoved) { - mFiles.remove(removedFile); - } - - mRemoved.clear(); - - // store the build state. If there are any files that failed to compile, we will - // force a full aidl compile on the next project open. (unless a full compilation succeed - // before the project is closed/re-opened.) - saveState(project); - - return mLastCompilationStatus; - } - - protected abstract void doCompileFiles( - List<IFile> filesToCompile, BaseBuilder builder, - IProject project, IAndroidTarget projectTarget, - List<IPath> sourceFolders, List<IFile> notCompiledOut, - List<File> libraryProjectsOut, IProgressMonitor monitor) throws CoreException; - - /** - * Adds a compilation status. It can be any of (in combination too): - * <p/> - * {@link #COMPILE_STATUS_CODE} means this processor created source code files. - * {@link #COMPILE_STATUS_RES} means this process created resources. - */ - protected void setCompilationStatus(int status) { - mLastCompilationStatus |= status; - } - - protected void doRemoveFiles(SourceFileData data) throws CoreException { - List<IFile> outputFiles = data.getOutputFiles(); - for (IFile outputFile : outputFiles) { - if (outputFile.exists()) { - outputFile.getLocation().toFile().delete(); - } - } - } - - public final boolean loadState(IProject project) { - return ProjectHelper.loadBooleanProperty(project, getSavePropertyName(), - true /*defaultValue*/); - } - - public final void saveState(IProject project) { - // TODO: Optimize by saving only the files that need compilation - ProjectHelper.saveStringProperty(project, getSavePropertyName(), - Boolean.toString(mToCompile.size() > 0)); - } - - protected abstract void loadOutputAndDependencies(); - - - protected IPath getSourceFolderFor(IFile file) { - // find the source folder for the class so that we can infer the package from the - // difference between the file and its source folder. - List<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(getJavaProject()); - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - - for (IPath sourceFolderPath : sourceFolders) { - IFolder sourceFolder = root.getFolder(sourceFolderPath); - // we don't look in the 'gen' source folder as there will be no source in there. - if (sourceFolder.exists() && sourceFolder.equals(getGenFolder()) == false) { - // look for the source file parent, until we find this source folder. - IResource parent = file; - while ((parent = parent.getParent()) != null) { - if (parent.equals(sourceFolder)) { - return sourceFolderPath; - } - } - } - } - - return null; - } - - /** - * Goes through the build paths and fills the list of files to compile. - * - * @param project The project. - * @param sourceFolderPathList The list of source folder paths. - */ - private final void buildSourceFileList() { - mFiles.clear(); - - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - List<IPath> sourceFolderPathList = BaseProjectHelper.getSourceClasspaths(mJavaProject); - - for (IPath sourceFolderPath : sourceFolderPathList) { - IFolder sourceFolder = root.getFolder(sourceFolderPath); - // we don't look in the 'gen' source folder as there will be no source in there. - if (sourceFolder.exists() && sourceFolder.equals(getGenFolder()) == false) { - scanFolderForSourceFiles(sourceFolder, sourceFolder); - } - } - } - - /** - * Scans a folder and fills the list of files to compile. - * @param sourceFolder the root source folder. - * @param folder The folder to scan. - */ - private void scanFolderForSourceFiles(IFolder sourceFolder, IFolder folder) { - try { - IResource[] members = folder.members(); - for (IResource r : members) { - // get the type of the resource - switch (r.getType()) { - case IResource.FILE: { - // if this a file, check that the file actually exist - // and that it's the type of of file that's used in this processor - String extension = r.exists() ? r.getFileExtension() : null; - if (extension != null && - getExtensions().contains(extension.toLowerCase(Locale.US))) { - mFiles.put((IFile) r, new SourceFileData((IFile) r)); - } - break; - } - case IResource.FOLDER: - // recursively go through children - scanFolderForSourceFiles(sourceFolder, (IFolder)r); - break; - default: - // this would mean it's a project or the workspace root - // which is unlikely to happen. we do nothing - break; - } - } - } catch (CoreException e) { - // Couldn't get the members list for some reason. Just return. - } - } - - - /** - * Merge the current list of source file to compile/remove with the one coming from the - * delta visitor - * @param visitor the delta visitor. - */ - private void mergeFileModifications(DefaultSourceChangeHandler visitor) { - Set<IFile> toRemove = visitor.getRemovedFiles(); - Set<IFile> toCompile = visitor.getFilesToCompile(); - - // loop through the new toRemove list, and add it to the old one, - // plus remove any file that was still to compile and that are now - // removed - for (IFile r : toRemove) { - if (mRemoved.indexOf(r) == -1) { - mRemoved.add(r); - } - - int index = mToCompile.indexOf(r); - if (index != -1) { - mToCompile.remove(index); - } - } - - // now loop through the new files to compile and add it to the list. - // Also look for them in the remove list, this would mean that they - // were removed, then added back, and we shouldn't remove them, just - // recompile them. - for (IFile r : toCompile) { - if (mToCompile.indexOf(r) == -1) { - mToCompile.add(r); - } - - int index = mRemoved.indexOf(r); - if (index != -1) { - mRemoved.remove(index); - } - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/build_messages.properties b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/build_messages.properties deleted file mode 100644 index f387ab5a9..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/build_messages.properties +++ /dev/null @@ -1,67 +0,0 @@ -Start_Full_Apk_Build=Starting full Package build. -Start_Full_Pre_Compiler=Starting full Pre Compiler. -Skip_Post_Compiler=Skipping over Post Compiler. -Start_Full_Post_Compiler=Starting full Post Compiler. -Start_Inc_Apk_Build=Starting incremental Package build: Checking resource changes. -Start_Inc_Pre_Compiler=Starting incremental Pre Compiler: Checking resource changes. -Xml_Error=Error in an XML file: aborting build. -s_Missing_Repackaging=%1$s missing. Repackaging. -Project_Has_Errors=Project contains error(s). Package Builder aborted. -Failed_To_Get_Output=Failed to get project output folder\! -Output_Missing=Output folder missing\! Make sure your project is configured properly. -s_File_Missing=%1$s file missing\! -Unparsed_AAPT_Errors=Unparsed aapt error(s)\! Check the console for output. -Unparsed_AIDL_Errors=Unparsed aidl error\! Check the console for output. -AAPT_Exec_Error_s=Error executing aapt. Please check aapt is present at %1$s -AAPT_Exec_Error_d=Error executing aapt: Return code %1$d -AAPT_Exec_Error_Other_s=Error executing aapt: %1$s -Dalvik_Error_d=Conversion to Dalvik format failed with error %1$d -DX_Jar_Error=Dx.jar is not found inside the plugin. Reinstall ADT\! -Dalvik_Error_s=Conversion to Dalvik format failed: %1$s -Incompatible_VM_Warning=Note: You may be using an incompatible virtual machine or class library. -Requires_1_5_Error=This program requires JDK 1.5 compatibility. -Final_Archive_Error_s=Error generating final archive: %1$s -Marker_Delete_Error=Failed to delete marker '%1$s' for %2$s -Couldnt_Locate_s_Error=Could not locate '%1$s'. This will not be added to the package. -Compiler_Compliance_Error=Compiler compliance level not compatible: Build aborted. -No_SDK_Setup_Error=SDK directory has not been setup. Please go to the Android preferences and enter the location of the SDK. -s_Contains_Xml_Error=%1$s contains XML error: Build aborted. -s_Doesnt_Declare_Package_Error=%1$s does not declare a Java package: Build aborted. -Checking_Package_Change=Checking Java package value did not change... -Package_s_Doesnt_Exist_Error=Package '%1$s' does not exist\! -Preparing_Generated_Files=Preparing generated java files for update/creation. -AAPT_Error='aapt' error. Pre Compiler Build aborted. -Nothing_To_Compile=Nothing to pre compile\! -Removing_Generated_Classes=Removing generated java classes. -Delete_Obsolete_Error=Failed to delete obsolete %1$s, please delete it manually -DexWrapper_Dex_Loader=Dex Loader -AIDL_Java_Conflict=%1$s is in the way of %2$s, remove it or rename of one the files. -AIDL_Exec_Error_d=Error executing aidl: Return code %1$d -AIDL_Exec_Error_s=Error executing aidl. Please check aidl is present at %1$s -s_Removed_Recreating_s=%1$s was removed\! Recreating %1$s\! -s_Modified_Manually_Recreating_s=%1$s was modified manually\! Reverting to generated version\! -s_Modified_Recreating_s='%1$s' was modified. -Added_s_s_Needs_Updating=New resource file: '%1$s', %2$s needs to be updated. -s_Removed_s_Needs_Updating='%1$s' was removed, %2$s needs to be updated. -Requires_Compiler_Compliance_s=Android requires compiler compliance level 5.0 or 6.0. Found '%1$s' instead. Please use Android Tools > Fix Project Properties. -Requires_Source_Compatibility_s=Android requires source compatibility set to 5.0 or 6.0. Found '%1$s' instead. Please use Android Tools > Fix Project Properties. -Requires_Class_Compatibility_s=Android requires .class compatibility set to 5.0 or 6.0. Found '%1$s' instead. Please use Android Tools > Fix Project Properties. -Refreshing_Res=Refreshing resource folders. -DexWrapper_s_does_not_exists=%1$s does not exist or is not a file -DexWrapper_Failed_to_load_s=Failed to load %1$s -DexWrapper_Unable_To_Execute_Dex_s=Unable to execute dex: %1$s -DexWrapper_SecuryEx_Unable_To_Find_API=SecurityException: Unable to find API for dex.jar -DexWrapper_SecuryEx_Unable_To_Find_Method=SecurityException: Unable to find method for dex.jar -DexWrapper_SecuryEx_Unable_To_Find_Field=SecurityException: Unable to find field for dex.jar -ApkBuilder_UnableBuild_Dex_Not_loaded=Unable to build: the file dx.jar was not loaded from the SDK folder\! -ApkBuilder_Using_Default_Key=Using default debug key to sign package -ApkBuilder_Using_s_To_Sign=Using '%1$s' to sign package -ApkBuilder_Signing_Key_Creation_s=Signing Key Creation: -ApkBuilder_Unable_To_Gey_Key=Unable to get debug signature key -ApkBuilder_Certificate_Expired_on_s=Debug certificate expired on %1$s\! -ApkBuilder_Packaging_s=Packaging %1$s -ApkBuilder_JAVA_HOME_is_s=The Java VM Home used is: %1$s -ApkBuilder_Update_or_Execute_manually_s=Update it if necessary, or manually execute the following command: -ApkBuilder_s_Conflict_with_file_s=%1$s conflicts with another file already put at %2$s -ApkBuilder_Packaging_s_into_s=Packaging %1$s into %2$s -Proguard_Exec_Error=Error executing Proguard. Please check Proguard is present at %1$s diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/BaseBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/BaseBuilder.java deleted file mode 100644 index 162591406..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/BaseBuilder.java +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright (C) 2007 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.builders; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.common.sdk.LoadStatus; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.build.BuildHelper; -import com.android.ide.eclipse.adt.internal.build.Messages; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.project.XmlErrorHandler; -import com.android.ide.eclipse.adt.internal.project.XmlErrorHandler.XmlErrorListener; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.io.IFileWrapper; -import com.android.io.IAbstractFile; -import com.android.io.StreamException; -import com.android.sdklib.BuildToolInfo; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.repository.FullRevision; - -import org.eclipse.core.resources.IContainer; -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.resources.IncrementalProjectBuilder; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.IJavaProject; -import org.xml.sax.SAXException; - -import java.util.ArrayList; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -/** - * Base builder for XML files. This class allows for basic XML parsing with - * error checking and marking the files for errors/warnings. - */ -public abstract class BaseBuilder extends IncrementalProjectBuilder { - - protected static final boolean DEBUG_LOG = "1".equals( //$NON-NLS-1$ - System.getenv("ANDROID_BUILD_DEBUG")); //$NON-NLS-1$ - - /** SAX Parser factory. */ - private SAXParserFactory mParserFactory; - - /** - * The build tool to use to build. This is guaranteed to be non null after a call to - * {@link #abortOnBadSetup(IJavaProject, ProjectState)} since this will throw if it can't be - * queried. - */ - protected BuildToolInfo mBuildToolInfo; - - /** - * Base Resource Delta Visitor to handle XML error - */ - protected static class BaseDeltaVisitor implements XmlErrorListener { - - /** The Xml builder used to validate XML correctness. */ - protected BaseBuilder mBuilder; - - /** - * XML error flag. if true, we keep parsing the ResourceDelta but the - * compilation will not happen (we're putting markers) - */ - public boolean mXmlError = false; - - public BaseDeltaVisitor(BaseBuilder builder) { - mBuilder = builder; - } - - /** - * Finds a matching Source folder for the current path. This checks if the current path - * leads to, or is a source folder. - * @param sourceFolders The list of source folders - * @param pathSegments The segments of the current path - * @return The segments of the source folder, or null if no match was found - */ - protected static String[] findMatchingSourceFolder(ArrayList<IPath> sourceFolders, - String[] pathSegments) { - - for (IPath p : sourceFolders) { - // check if we are inside one of those source class path - - // get the segments - String[] srcSegments = p.segments(); - - // compare segments. We want the path of the resource - // we're visiting to be - boolean valid = true; - int segmentCount = pathSegments.length; - - for (int i = 0 ; i < segmentCount; i++) { - String s1 = pathSegments[i]; - String s2 = srcSegments[i]; - - if (s1.equalsIgnoreCase(s2) == false) { - valid = false; - break; - } - } - - if (valid) { - // this folder, or one of this children is a source - // folder! - // we return its segments - return srcSegments; - } - } - - return null; - } - - /** - * Sent when an XML error is detected. - * @see XmlErrorListener - */ - @Override - public void errorFound() { - mXmlError = true; - } - } - - protected static class AbortBuildException extends Exception { - private static final long serialVersionUID = 1L; - } - - public BaseBuilder() { - super(); - mParserFactory = SAXParserFactory.newInstance(); - - // FIXME when the compiled XML support for namespace is in, set this to true. - mParserFactory.setNamespaceAware(false); - } - - /** - * Checks an Xml file for validity. Errors/warnings will be marked on the - * file - * @param resource the resource to check - * @param visitor a valid resource delta visitor - */ - protected final void checkXML(IResource resource, BaseDeltaVisitor visitor) { - - // first make sure this is an xml file - if (resource instanceof IFile) { - IFile file = (IFile)resource; - - // remove previous markers - removeMarkersFromResource(file, AdtConstants.MARKER_XML); - - // create the error handler - XmlErrorHandler reporter = new XmlErrorHandler(file, visitor); - try { - // parse - getParser().parse(file.getContents(), reporter); - } catch (Exception e1) { - } - } - } - - /** - * Returns the SAXParserFactory, instantiating it first if it's not already - * created. - * @return the SAXParserFactory object - * @throws ParserConfigurationException - * @throws SAXException - */ - protected final SAXParser getParser() throws ParserConfigurationException, - SAXException { - return mParserFactory.newSAXParser(); - } - - /** - * Adds a marker to the current project. This methods catches thrown {@link CoreException}, - * and returns null instead. - * - * @param markerId The id of the marker to add. - * @param message the message associated with the mark - * @param severity the severity of the marker. - * @return the marker that was created (or null if failure) - * @see IMarker - */ - protected final IMarker markProject(String markerId, String message, int severity) { - return BaseProjectHelper.markResource(getProject(), markerId, message, severity); - } - - /** - * Removes markers from a resource and only the resource (not its children). - * @param file The file from which to delete the markers. - * @param markerId The id of the markers to remove. If null, all marker of - * type <code>IMarker.PROBLEM</code> will be removed. - */ - public final void removeMarkersFromResource(IResource resource, String markerId) { - try { - if (resource.exists()) { - resource.deleteMarkers(markerId, true, IResource.DEPTH_ZERO); - } - } catch (CoreException ce) { - String msg = String.format(Messages.Marker_Delete_Error, markerId, resource.toString()); - AdtPlugin.printErrorToConsole(getProject(), msg); - } - } - - /** - * Removes markers from a container and its children. - * @param folder The container from which to delete the markers. - * @param markerId The id of the markers to remove. If null, all marker of - * type <code>IMarker.PROBLEM</code> will be removed. - */ - protected final void removeMarkersFromContainer(IContainer folder, String markerId) { - try { - if (folder.exists()) { - folder.deleteMarkers(markerId, true, IResource.DEPTH_INFINITE); - } - } catch (CoreException ce) { - String msg = String.format(Messages.Marker_Delete_Error, markerId, folder.toString()); - AdtPlugin.printErrorToConsole(getProject(), msg); - } - } - - /** - * Get the stderr output of a process and return when the process is done. - * @param process The process to get the ouput from - * @param stdErr The array to store the stderr output - * @return the process return code. - * @throws InterruptedException - */ - protected final int grabProcessOutput(final Process process, - final ArrayList<String> stdErr) throws InterruptedException { - return BuildHelper.grabProcessOutput(getProject(), process, stdErr); - } - - - - /** - * Saves a String property into the persistent storage of the project. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @param value the value to save - * @return true if the save succeeded. - */ - protected boolean saveProjectStringProperty(String propertyName, String value) { - IProject project = getProject(); - return ProjectHelper.saveStringProperty(project, propertyName, value); - } - - - /** - * Loads a String property from the persistent storage of the project. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @return the property value or null if it was not found. - */ - protected String loadProjectStringProperty(String propertyName) { - IProject project = getProject(); - return ProjectHelper.loadStringProperty(project, propertyName); - } - - /** - * Saves a property into the persistent storage of the project. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @param value the value to save - * @return true if the save succeeded. - */ - protected boolean saveProjectBooleanProperty(String propertyName, boolean value) { - IProject project = getProject(); - return ProjectHelper.saveStringProperty(project, propertyName, Boolean.toString(value)); - } - - /** - * Loads a boolean property from the persistent storage of the project. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @param defaultValue The default value to return if the property was not found. - * @return the property value or the default value if the property was not found. - */ - protected boolean loadProjectBooleanProperty(String propertyName, boolean defaultValue) { - IProject project = getProject(); - return ProjectHelper.loadBooleanProperty(project, propertyName, defaultValue); - } - - /** - * Aborts the build if the SDK/project setups are broken. This does not - * display any errors. - * - * @param javaProject The {@link IJavaProject} being compiled. - * @param projectState the project state, optional. will be queried if null. - * @throws CoreException - */ - protected void abortOnBadSetup(@NonNull IJavaProject javaProject, - @Nullable ProjectState projectState) throws AbortBuildException, CoreException { - IProject iProject = javaProject.getProject(); - // check if we have finished loading the project target. - Sdk sdk = Sdk.getCurrent(); - if (sdk == null) { - throw new AbortBuildException(); - } - - if (projectState == null) { - projectState = Sdk.getProjectState(javaProject.getProject()); - } - - // get the target for the project - IAndroidTarget target = projectState.getTarget(); - - if (target == null) { - throw new AbortBuildException(); - } - - // check on the target data. - if (sdk.checkAndLoadTargetData(target, javaProject) != LoadStatus.LOADED) { - throw new AbortBuildException(); - } - - mBuildToolInfo = projectState.getBuildToolInfo(); - if (mBuildToolInfo == null) { - mBuildToolInfo = sdk.getLatestBuildTool(); - - if (mBuildToolInfo == null) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, iProject, - "No \"Build Tools\" package available; use SDK Manager to install one."); - throw new AbortBuildException(); - } else { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, iProject, - String.format("Using default Build Tools revision %s", - mBuildToolInfo.getRevision()) - ); - } - } - - // abort if there are TARGET or ADT type markers - stopOnMarker(iProject, AdtConstants.MARKER_TARGET, IResource.DEPTH_ZERO, - false /*checkSeverity*/); - stopOnMarker(iProject, AdtConstants.MARKER_ADT, IResource.DEPTH_ZERO, - false /*checkSeverity*/); - } - - protected void stopOnMarker(IProject project, String markerType, int depth, - boolean checkSeverity) - throws AbortBuildException { - try { - IMarker[] markers = project.findMarkers(markerType, false /*includeSubtypes*/, depth); - - if (markers.length > 0) { - if (checkSeverity == false) { - throw new AbortBuildException(); - } else { - for (IMarker marker : markers) { - int severity = marker.getAttribute(IMarker.SEVERITY, -1 /*defaultValue*/); - if (severity == IMarker.SEVERITY_ERROR) { - throw new AbortBuildException(); - } - } - } - } - } catch (CoreException e) { - // don't stop, something's really screwed up and the build will break later with - // a better error message. - } - } - - /** - * Handles a {@link StreamException} by logging the info and marking the project. - * This should generally be followed by exiting the build process. - * - * @param e the exception - */ - protected void handleStreamException(StreamException e) { - IAbstractFile file = e.getFile(); - - String msg; - - IResource target = getProject(); - if (file instanceof IFileWrapper) { - target = ((IFileWrapper) file).getIFile(); - - if (e.getError() == StreamException.Error.OUTOFSYNC) { - msg = "File is Out of sync"; - } else { - msg = "Error reading file. Read log for details"; - } - - } else { - if (e.getError() == StreamException.Error.OUTOFSYNC) { - msg = String.format("Out of sync file: %s", file.getOsLocation()); - } else { - msg = String.format("Error reading file %s. Read log for details", - file.getOsLocation()); - } - } - - AdtPlugin.logAndPrintError(e, getProject().getName(), msg); - BaseProjectHelper.markResource(target, AdtConstants.MARKER_ADT, msg, - IMarker.SEVERITY_ERROR); - } - - /** - * Handles a generic {@link Throwable} by logging the info and marking the project. - * This should generally be followed by exiting the build process. - * - * @param t the {@link Throwable}. - * @param message the message to log and to associate with the marker. - */ - protected void handleException(Throwable t, String message) { - AdtPlugin.logAndPrintError(t, getProject().getName(), message); - markProject(AdtConstants.MARKER_ADT, message, IMarker.SEVERITY_ERROR); - } - - /** - * Recursively delete all the derived resources from a root resource. The root resource is not - * deleted. - * @param rootResource the root resource - * @param monitor a progress monitor. - * @throws CoreException - * - */ - protected void removeDerivedResources(IResource rootResource, IProgressMonitor monitor) - throws CoreException { - removeDerivedResources(rootResource, false, monitor); - } - - /** - * delete a resource and its children. returns true if the root resource was deleted. All - * sub-folders *will* be deleted if they were emptied (not if they started empty). - * @param rootResource the root resource - * @param deleteRoot whether to delete the root folder. - * @param monitor a progress monitor. - * @throws CoreException - */ - private void removeDerivedResources(IResource rootResource, boolean deleteRoot, - IProgressMonitor monitor) throws CoreException { - if (rootResource.exists()) { - // if it's a folder, delete derived member. - if (rootResource.getType() == IResource.FOLDER) { - IFolder folder = (IFolder)rootResource; - IResource[] members = folder.members(); - boolean wasNotEmpty = members.length > 0; - for (IResource member : members) { - removeDerivedResources(member, true /*deleteRoot*/, monitor); - } - - // if the folder had content that is now all removed, delete the folder. - if (deleteRoot && wasNotEmpty && folder.members().length == 0) { - rootResource.getLocation().toFile().delete(); - } - } - - // if the root resource is derived, delete it. - if (rootResource.isDerived()) { - rootResource.getLocation().toFile().delete(); - } - } - } - - protected void launchJob(Job newJob) { - newJob.setPriority(Job.BUILD); - newJob.setRule(ResourcesPlugin.getWorkspace().getRoot()); - newJob.schedule(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSet.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSet.java deleted file mode 100644 index 4f5b47f6d..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSet.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2012 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.builders; - -import com.android.annotations.NonNull; - -import org.apache.tools.ant.types.selectors.SelectorUtils; -import org.eclipse.core.runtime.IPath; - -/** - * Collection of file path or path patterns to be checked for changes. - * - * All paths should be relative to the project they belong to. - * Patterns can use Ant-type glob patterns. - * - * This is an immutable class that does not store any info beyond the list of paths. This is to - * be used in conjunction with {@link PatternBasedDeltaVisitor}. - */ -class ChangedFileSet { - - private final String mLogName; - - private final String[] mInputs; - private String mOutput; - - ChangedFileSet(String logName, String... inputs) { - mLogName = logName; - mInputs = inputs; - } - - public void setOutput(@NonNull String output) { - mOutput = output; - } - - public boolean isInput(@NonNull String path, @NonNull IPath iPath) { - for (String i : mInputs) { - if (SelectorUtils.matchPath(i, path)) { - return true; - } - } - - return false; - } - - public boolean isOutput(@NonNull String path, @NonNull IPath iPath) { - if (mOutput != null) { - return SelectorUtils.matchPath(mOutput, path); - } - - return false; - } - - public String getLogName() { - return mLogName; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSetHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSetHelper.java deleted file mode 100644 index 9fc19a7a6..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ChangedFileSetHelper.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2012 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.builders; - -import com.android.SdkConstants; -import com.android.annotations.NonNull; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; - -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IPath; - -import java.util.ArrayList; -import java.util.List; - -/** - * Helper class to generate {@link ChangedFileSet} for given projects. - * - * Also contains non project specific {@link ChangedFileSet} such as {@link #MANIFEST} - * and {@link #NATIVE_LIBS} - */ -class ChangedFileSetHelper { - - final static ChangedFileSet MANIFEST; - final static ChangedFileSet NATIVE_LIBS; - - static { - MANIFEST = new ChangedFileSet("manifest", //$NON-NLS-1$ - SdkConstants.FN_ANDROID_MANIFEST_XML); - - // FIXME: move compiled native libs to bin/libs/ - NATIVE_LIBS = new ChangedFileSet( - "nativeLibs", - SdkConstants.FD_NATIVE_LIBS + "/*/*.so", //$NON-NLS-1$ - SdkConstants.FD_NATIVE_LIBS + "/*/" + SdkConstants.FN_GDBSERVER); //$NON-NLS-1$ - } - - /** - * Returns a ChangedFileSet for Java resources inside a given project's source folders. - * @param project the project. - * @return a ChangedFileSet - */ - static ChangedFileSet getJavaResCfs(@NonNull IProject project) { - - // get the source folder for the given project. - IPath projectPath = project.getFullPath(); - - // get the source folders. - List<IPath> srcPaths = BaseProjectHelper.getSourceClasspaths(project); - List<String> paths = new ArrayList<String>(srcPaths.size()); - - // create a pattern for each of them. - for (IPath path : srcPaths) { - paths.add(path.makeRelativeTo(projectPath).toString() + "/**"); //$NON-NLS-1$ - } - - // custom ChangedFileSet to ignore .java files. - return new JavaResChangedSet("javaRes", //$NON-NLS-1$ - paths.toArray(new String[paths.size()])); - } - - /** - * Returns a {@link ChangedFileSet} for all the resources (included assets), and the output - * file (compiled resources - * @param project the project - * @return a ChangeFileSet - */ - static ChangedFileSet getResCfs(@NonNull IProject project) { - // generated res is inside the project's android output folder - String path = getRelativeAndroidOut(project); - - ChangedFileSet set = new ChangedFileSet( - "resources", //$NON-NLS-1$ - SdkConstants.FD_RES + "/**", //$NON-NLS-1$ - SdkConstants.FD_ASSETS + "/**", //$NON-NLS-1$ - path + '/' + AdtConstants.WS_BIN_RELATIVE_BC + "/**"); //$NON-NLS-1$ - - // output file is based on the project's android output folder - set.setOutput(path + '/' + AdtConstants.FN_RESOURCES_AP_); - - return set; - } - - /** - * Returns a {@link ChangedFileSet} for all the resources (included assets), and the output - * file (compiled resources - * @param project the project - * @return a ChangeFileSet - */ - static ChangedFileSet getMergedManifestCfs(@NonNull IProject project) { - // input path is inside the project's android output folder - String path = getRelativeAndroidOut(project); - - ChangedFileSet set = new ChangedFileSet( - "mergedManifest", //$NON-NLS-1$ - path + '/' + SdkConstants.FN_ANDROID_MANIFEST_XML); - - return set; - } - - /** - * Returns a {@link ChangedFileSet} for the generated R.txt file - * @param project the project - * @return a ChangeFileSet - */ - static ChangedFileSet getTextSymbols(@NonNull IProject project) { - // input path is inside the project's android output folder - String path = getRelativeAndroidOut(project); - - ChangedFileSet set = new ChangedFileSet( - "textSymbols", //$NON-NLS-1$ - path + '/' + SdkConstants.FN_RESOURCE_TEXT); - - return set; - } - - /** - * Returns a {@link ChangedFileSet} for a project's javac output. - * @param project the project - * @return a ChangedFileSet - */ - static ChangedFileSet getByteCodeCfs(@NonNull IProject project) { - // input pattern is based on the project's Java compiler's output folder - String path = getRelativeJavaCOut(project); - - ChangedFileSet set = new ChangedFileSet("compiledCode", //$NON-NLS-1$ - path + "/**/*" + SdkConstants.DOT_CLASS); //$NON-NLS-1$ - - return set; - } - - /** - * Returns a {@link ChangedFileSet} for a project's complete resources, including - * generated resources and crunch cache. - * @param project the project - * @return a ChangeFileSet - */ - static ChangedFileSet getFullResCfs(@NonNull IProject project) { - // generated res are in the project's android output folder - String path = getRelativeAndroidOut(project); - - ChangedFileSet set = new ChangedFileSet("libResources", //$NON-NLS-1$ - SdkConstants.FD_RES + "/**", //$NON-NLS-1$ - path + '/' + SdkConstants.FD_RES + "/**"); //$NON-NLS-1$ - - return set; - } - - /** - * Returns a {@link ChangedFileSet} for a project's whole code, including - * compiled bytecode, 3rd party libs, and the output file containing the Dalvik - * bytecode file. - * @param project the project - * @return a ChangeFileSet - */ - static ChangedFileSet getCodeCfs(@NonNull IProject project) { - // input pattern is based on the project's Java compiler's output folder - String path = getRelativeJavaCOut(project); - - ChangedFileSet set = new ChangedFileSet("classAndJars", //$NON-NLS-1$ - path + "/**/*" + SdkConstants.DOT_CLASS, //$NON-NLS-1$ - SdkConstants.FD_NATIVE_LIBS + "/*" + SdkConstants.DOT_JAR); //$NON-NLS-1$ - - // output file is based on the project's android output folder - path = getRelativeAndroidOut(project); - set.setOutput(path + '/' + SdkConstants.FN_APK_CLASSES_DEX); - - return set; - } - - private static String getRelativePath(@NonNull IProject project, @NonNull IResource resource) { - return resource.getFullPath().makeRelativeTo(project.getFullPath()).toString(); - } - - private static String getRelativeAndroidOut(@NonNull IProject project) { - IFolder folder = BaseProjectHelper.getAndroidOutputFolder(project); - return getRelativePath(project, folder); - } - - private static String getRelativeJavaCOut(@NonNull IProject project) { - IFolder folder = BaseProjectHelper.getJavaOutputFolder(project); - return getRelativePath(project, folder); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/JavaResChangedSet.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/JavaResChangedSet.java deleted file mode 100644 index 6b257efbf..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/JavaResChangedSet.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2012 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.builders; - -import com.android.annotations.NonNull; -import com.android.sdklib.build.ApkBuilder; - -import org.eclipse.core.runtime.IPath; - -/** - * Custom {@link ChangedFileSet} for java resources. - * - * This builds the set of inputs to be all the source folders of the given project, - * and excludes files that won't be packaged. - * This exclusion can't be easily described as a glob-pattern so it's overriding the default - * behavior instead. - * - */ -class JavaResChangedSet extends ChangedFileSet { - - JavaResChangedSet(String logName, String... inputs) { - super(logName, inputs); - } - - @Override - public boolean isInput(@NonNull String path, @NonNull IPath iPath) { - if (!ApkBuilder.checkFileForPackaging(iPath.lastSegment(), iPath.getFileExtension())) { - return false; - } - return super.isInput(path, iPath); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PatternBasedDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PatternBasedDeltaVisitor.java deleted file mode 100644 index b52ede90c..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PatternBasedDeltaVisitor.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2012 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.builders; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.build.BuildHelper; - -import org.eclipse.core.resources.IFolder; -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.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; - -import java.util.ArrayList; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; - -/** - * Delta visitor checking changed files against given glob-patterns. - * - * The visitor is given {@link ChangedFileSet} objects which contains patterns to detect change - * in input and output files. (Output files are only tested if the delta indicate the file - * was removed). - * - * After the visitor has visited the whole delta, it can be queried to see which ChangedFileSet - * recognized a file change. (ChangedFileSet are immutable and do not record this info). - */ -class PatternBasedDeltaVisitor implements IResourceDeltaVisitor { - - private final static boolean DEBUG_LOG = "1".equals( //$NON-NLS-1$ - System.getenv("ANDROID_VISITOR_DEBUG")); //$NON-NLS-1$ - - private final IProject mMainProject; - private final IProject mDeltaProject; - - private final List<ChangedFileSet> mSets = new ArrayList<ChangedFileSet>(); - private final Map<ChangedFileSet, Boolean> mResults = - new IdentityHashMap<ChangedFileSet, Boolean>(); - - private final String mLogName; - - PatternBasedDeltaVisitor(IProject mainProject, IProject deltaProject, String logName) { - mMainProject = mainProject; - mDeltaProject = deltaProject; - mLogName = logName; - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s (%s): Delta for %s", //$NON-NLS-1$ - mMainProject.getName(), mLogName, mDeltaProject.getName()); - } - } - - void addSet(ChangedFileSet bundle) { - mSets.add(bundle); - } - - boolean checkSet(ChangedFileSet bundle) { - Boolean r = mResults.get(bundle); - if (r != null) { - return r.booleanValue(); - } - - return false; - } - - @Override - public boolean visit(IResourceDelta delta) throws CoreException { - IResource resource = delta.getResource(); - - if (resource.getType() == IResource.FOLDER) { - // always visit the subfolders, unless the folder is not to be included - return BuildHelper.checkFolderForPackaging((IFolder)resource); - - } else if (resource.getType() == IResource.FILE) { - IPath path = resource.getFullPath().makeRelativeTo(mDeltaProject.getFullPath()); - String pathStr = path.toString(); - - // FIXME: no need to loop through all the sets once they have all said they need something (return false below and above) - for (ChangedFileSet set : mSets) { - // FIXME: should ignore sets that have already returned true. - - if (set.isInput(pathStr, path)) { - mResults.put(set, Boolean.TRUE); - - if (DEBUG_LOG) { - String cfs_logName = set.getLogName(); - - if (cfs_logName != null) { - AdtPlugin.log(IStatus.INFO, "%s (%s:%s): %s", //$NON-NLS-1$ - mMainProject.getName(), mLogName, cfs_logName, - resource.getFullPath().toString()); - } else { - AdtPlugin.log(IStatus.INFO, "%s (%s): %s", //$NON-NLS-1$ - mMainProject.getName(), mLogName, - resource.getFullPath().toString()); - } - } - - } else if (delta.getKind() == IResourceDelta.REMOVED && - set.isOutput(pathStr, path)) { - mResults.put(set, Boolean.TRUE); - - if (DEBUG_LOG) { - String cfs_logName = set.getLogName(); - - if (cfs_logName != null) { - AdtPlugin.log(IStatus.INFO, "%s (%s:%s): %s", //$NON-NLS-1$ - mMainProject.getName(), mLogName, cfs_logName, - resource.getFullPath().toString()); - } else { - AdtPlugin.log(IStatus.INFO, "%s (%s): %s", //$NON-NLS-1$ - mMainProject.getName(), mLogName, - resource.getFullPath().toString()); - } - } - } - } - } - - return true; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java deleted file mode 100644 index 8aacb44ef..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java +++ /dev/null @@ -1,946 +0,0 @@ -/* - * Copyright (C) 2007 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.builders; - -import com.android.SdkConstants; -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AndroidPrintStream; -import com.android.ide.eclipse.adt.internal.build.AaptExecException; -import com.android.ide.eclipse.adt.internal.build.AaptParser; -import com.android.ide.eclipse.adt.internal.build.AaptResultException; -import com.android.ide.eclipse.adt.internal.build.BuildHelper; -import com.android.ide.eclipse.adt.internal.build.BuildHelper.ResourceMarker; -import com.android.ide.eclipse.adt.internal.build.DexException; -import com.android.ide.eclipse.adt.internal.build.Messages; -import com.android.ide.eclipse.adt.internal.build.NativeLibInJarException; -import com.android.ide.eclipse.adt.internal.lint.LintDeltaProcessor; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; -import com.android.ide.eclipse.adt.internal.project.ApkInstallManager; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.LibraryClasspathContainerInitializer; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.io.IFileWrapper; -import com.android.prefs.AndroidLocation.AndroidLocationException; -import com.android.sdklib.build.ApkBuilder; -import com.android.sdklib.build.ApkCreationException; -import com.android.sdklib.build.DuplicateFileException; -import com.android.sdklib.build.IArchiveBuilder; -import com.android.sdklib.build.SealedApkException; -import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException; -import com.android.xml.AndroidManifest; - -import org.eclipse.core.resources.IContainer; -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.resources.IResourceDelta; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.jdt.core.IJavaModelMarker; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.jar.Attributes; -import java.util.jar.JarEntry; -import java.util.jar.JarOutputStream; -import java.util.jar.Manifest; -import java.util.regex.Pattern; - -public class PostCompilerBuilder extends BaseBuilder { - - /** This ID is used in plugin.xml and in each project's .project file. - * It cannot be changed even if the class is renamed/moved */ - public static final String ID = "com.android.ide.eclipse.adt.ApkBuilder"; //$NON-NLS-1$ - - private static final String PROPERTY_CONVERT_TO_DEX = "convertToDex"; //$NON-NLS-1$ - private static final String PROPERTY_PACKAGE_RESOURCES = "packageResources"; //$NON-NLS-1$ - private static final String PROPERTY_BUILD_APK = "buildApk"; //$NON-NLS-1$ - - /** Flag to pass to PostCompiler builder that sets if it runs or not. - * Set this flag whenever calling build if PostCompiler is to run - */ - public final static String POST_C_REQUESTED = "RunPostCompiler"; //$NON-NLS-1$ - - /** - * Dex conversion flag. This is set to true if one of the changed/added/removed - * file is a .class file. Upon visiting all the delta resource, if this - * flag is true, then we know we'll have to make the "classes.dex" file. - */ - private boolean mConvertToDex = false; - - /** - * Package resources flag. This is set to true if one of the changed/added/removed - * file is a resource file. Upon visiting all the delta resource, if - * this flag is true, then we know we'll have to repackage the resources. - */ - private boolean mPackageResources = false; - - /** - * Final package build flag. - */ - private boolean mBuildFinalPackage = false; - - private AndroidPrintStream mOutStream = null; - private AndroidPrintStream mErrStream = null; - - - private ResourceMarker mResourceMarker = new ResourceMarker() { - @Override - public void setWarning(IResource resource, String message) { - BaseProjectHelper.markResource(resource, AdtConstants.MARKER_PACKAGING, - message, IMarker.SEVERITY_WARNING); - } - }; - - - public PostCompilerBuilder() { - super(); - } - - @Override - protected void clean(IProgressMonitor monitor) throws CoreException { - super.clean(monitor); - - // Get the project. - IProject project = getProject(); - - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s CLEAN(POST)", project.getName()); - } - - // Clear the project of the generic markers - removeMarkersFromContainer(project, AdtConstants.MARKER_AAPT_PACKAGE); - removeMarkersFromContainer(project, AdtConstants.MARKER_PACKAGING); - - // also remove the files in the output folder (but not the Eclipse output folder). - IFolder javaOutput = BaseProjectHelper.getJavaOutputFolder(project); - IFolder androidOutput = BaseProjectHelper.getAndroidOutputFolder(project); - - if (javaOutput.equals(androidOutput) == false) { - // get the content - IResource[] members = androidOutput.members(); - for (IResource member : members) { - if (member.equals(javaOutput) == false) { - member.delete(true /*force*/, monitor); - } - } - } - } - - // build() returns a list of project from which this project depends for future compilation. - @Override - protected IProject[] build( - int kind, - @SuppressWarnings("rawtypes") Map args, - IProgressMonitor monitor) - throws CoreException { - // get a project object - IProject project = getProject(); - - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s BUILD(POST)", project.getName()); - } - - // Benchmarking start - long startBuildTime = 0; - if (BuildHelper.BENCHMARK_FLAG) { - // End JavaC Timer - String msg = "BENCHMARK ADT: Ending Compilation \n BENCHMARK ADT: Time Elapsed: " + //$NON-NLS-1$ - (System.nanoTime() - BuildHelper.sStartJavaCTime)/Math.pow(10, 6) + "ms"; //$NON-NLS-1$ - AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, project, msg); - msg = "BENCHMARK ADT: Starting PostCompilation"; //$NON-NLS-1$ - AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, project, msg); - startBuildTime = System.nanoTime(); - } - - // list of referenced projects. This is a mix of java projects and library projects - // and is computed below. - IProject[] allRefProjects = null; - - try { - // get the project info - ProjectState projectState = Sdk.getProjectState(project); - - // this can happen if the project has no project.properties. - if (projectState == null) { - return null; - } - - boolean isLibrary = projectState.isLibrary(); - - // get the libraries - List<IProject> libProjects = projectState.getFullLibraryProjects(); - - IJavaProject javaProject = JavaCore.create(project); - - // get the list of referenced projects. - List<IProject> javaProjects = ProjectHelper.getReferencedProjects(project); - List<IJavaProject> referencedJavaProjects = BuildHelper.getJavaProjects( - javaProjects); - - // mix the java project and the library projects - final int size = libProjects.size() + javaProjects.size(); - ArrayList<IProject> refList = new ArrayList<IProject>(size); - refList.addAll(libProjects); - refList.addAll(javaProjects); - allRefProjects = refList.toArray(new IProject[size]); - - // get the android output folder - IFolder androidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(project); - IFolder resOutputFolder = androidOutputFolder.getFolder(SdkConstants.FD_RES); - - // First thing we do is go through the resource delta to not - // lose it if we have to abort the build for any reason. - if (args.containsKey(POST_C_REQUESTED) - && AdtPrefs.getPrefs().getBuildSkipPostCompileOnFileSave()) { - // Skip over flag setting - } else if (kind == FULL_BUILD) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Start_Full_Apk_Build); - - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s full build!", project.getName()); - } - - // Full build: we do all the steps. - mPackageResources = true; - mConvertToDex = true; - mBuildFinalPackage = true; - } else { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Start_Inc_Apk_Build); - - // go through the resources and see if something changed. - IResourceDelta delta = getDelta(project); - if (delta == null) { - // no delta? Same as full build: we do all the steps. - mPackageResources = true; - mConvertToDex = true; - mBuildFinalPackage = true; - } else { - - if (ResourceManager.isAutoBuilding() && AdtPrefs.getPrefs().isLintOnSave()) { - // Check for errors on save/build, if enabled - LintDeltaProcessor.create().process(delta); - } - - PatternBasedDeltaVisitor dv = new PatternBasedDeltaVisitor( - project, project, - "POST:Main"); - - ChangedFileSet manifestCfs = ChangedFileSetHelper.getMergedManifestCfs(project); - dv.addSet(manifestCfs); - - ChangedFileSet resCfs = ChangedFileSetHelper.getResCfs(project); - dv.addSet(resCfs); - - ChangedFileSet androidCodeCfs = ChangedFileSetHelper.getCodeCfs(project); - dv.addSet(androidCodeCfs); - - ChangedFileSet javaResCfs = ChangedFileSetHelper.getJavaResCfs(project); - dv.addSet(javaResCfs); - dv.addSet(ChangedFileSetHelper.NATIVE_LIBS); - - delta.accept(dv); - - // save the state - mPackageResources |= dv.checkSet(manifestCfs) || dv.checkSet(resCfs); - - mConvertToDex |= dv.checkSet(androidCodeCfs); - - mBuildFinalPackage |= dv.checkSet(javaResCfs) || - dv.checkSet(ChangedFileSetHelper.NATIVE_LIBS); - } - - // check the libraries - if (libProjects.size() > 0) { - for (IProject libProject : libProjects) { - delta = getDelta(libProject); - if (delta != null) { - PatternBasedDeltaVisitor visitor = new PatternBasedDeltaVisitor( - project, libProject, - "POST:Lib"); - - ChangedFileSet libResCfs = ChangedFileSetHelper.getFullResCfs( - libProject); - visitor.addSet(libResCfs); - visitor.addSet(ChangedFileSetHelper.NATIVE_LIBS); - // FIXME: add check on the library.jar? - - delta.accept(visitor); - - mPackageResources |= visitor.checkSet(libResCfs); - mBuildFinalPackage |= visitor.checkSet( - ChangedFileSetHelper.NATIVE_LIBS); - } - } - } - - // also go through the delta for all the referenced projects - final int referencedCount = referencedJavaProjects.size(); - for (int i = 0 ; i < referencedCount; i++) { - IJavaProject referencedJavaProject = referencedJavaProjects.get(i); - delta = getDelta(referencedJavaProject.getProject()); - if (delta != null) { - IProject referencedProject = referencedJavaProject.getProject(); - PatternBasedDeltaVisitor visitor = new PatternBasedDeltaVisitor( - project, referencedProject, - "POST:RefedProject"); - - ChangedFileSet javaResCfs = ChangedFileSetHelper.getJavaResCfs(referencedProject); - visitor.addSet(javaResCfs); - - ChangedFileSet bytecodeCfs = ChangedFileSetHelper.getByteCodeCfs(referencedProject); - visitor.addSet(bytecodeCfs); - - delta.accept(visitor); - - // save the state - mConvertToDex |= visitor.checkSet(bytecodeCfs); - mBuildFinalPackage |= visitor.checkSet(javaResCfs); - } - } - } - - // store the build status in the persistent storage - saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, mConvertToDex); - saveProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, mPackageResources); - saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage); - - // Top level check to make sure the build can move forward. Only do this after recording - // delta changes. - abortOnBadSetup(javaProject, projectState); - - // Get the output stream. Since the builder is created for the life of the - // project, they can be kept around. - if (mOutStream == null) { - mOutStream = new AndroidPrintStream(project, null /*prefix*/, - AdtPlugin.getOutStream()); - mErrStream = new AndroidPrintStream(project, null /*prefix*/, - AdtPlugin.getOutStream()); - } - - // remove older packaging markers. - removeMarkersFromContainer(javaProject.getProject(), AdtConstants.MARKER_PACKAGING); - - // finished with the common init and tests. Special case of the library. - if (isLibrary) { - // check the jar output file is present, if not create it. - IFile jarIFile = androidOutputFolder.getFile( - project.getName().toLowerCase() + SdkConstants.DOT_JAR); - if (mConvertToDex == false && jarIFile.exists() == false) { - mConvertToDex = true; - } - - // also update the crunch cache always since aapt does it smartly only - // on the files that need it. - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s running crunch!", project.getName()); - } - BuildHelper helper = new BuildHelper( - projectState, - mBuildToolInfo, - mOutStream, mErrStream, - false /*jumbo mode doesn't matter here*/, - false /*dex merger doesn't matter here*/, - true /*debugMode*/, - AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE, - mResourceMarker); - updateCrunchCache(project, helper); - - // refresh recursively bin/res folder - resOutputFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); - - if (mConvertToDex) { // in this case this means some class files changed and - // we need to update the jar file. - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s updating jar!", project.getName()); - } - - // resource to the AndroidManifest.xml file - IFile manifestFile = project.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML); - String appPackage = AndroidManifest.getPackage(new IFileWrapper(manifestFile)); - - IFolder javaOutputFolder = BaseProjectHelper.getJavaOutputFolder(project); - - writeLibraryPackage(jarIFile, project, appPackage, javaOutputFolder); - saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, mConvertToDex = false); - - // refresh the bin folder content with no recursion to update the library - // jar file. - androidOutputFolder.refreshLocal(IResource.DEPTH_ONE, monitor); - - // Also update the projects. The only way to force recompile them is to - // reset the library container. - List<ProjectState> parentProjects = projectState.getParentProjects(); - LibraryClasspathContainerInitializer.updateProject(parentProjects); - } - - return allRefProjects; - } - - // Check to see if we're going to launch or export. If not, we can skip - // the packaging and dexing process. - if (!args.containsKey(POST_C_REQUESTED) - && AdtPrefs.getPrefs().getBuildSkipPostCompileOnFileSave()) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Skip_Post_Compiler); - return allRefProjects; - } else { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Start_Full_Post_Compiler); - } - - // first thing we do is check that the SDK directory has been setup. - String osSdkFolder = AdtPlugin.getOsSdkFolder(); - - if (osSdkFolder.length() == 0) { - // this has already been checked in the precompiler. Therefore, - // while we do have to cancel the build, we don't have to return - // any error or throw anything. - return allRefProjects; - } - - // do some extra check, in case the output files are not present. This - // will force to recreate them. - IResource tmp = null; - - if (mPackageResources == false) { - // check the full resource package - tmp = androidOutputFolder.findMember(AdtConstants.FN_RESOURCES_AP_); - if (tmp == null || tmp.exists() == false) { - mPackageResources = true; - } - } - - // check classes.dex is present. If not we force to recreate it. - if (mConvertToDex == false) { - tmp = androidOutputFolder.findMember(SdkConstants.FN_APK_CLASSES_DEX); - if (tmp == null || tmp.exists() == false) { - mConvertToDex = true; - } - } - - // also check the final file(s)! - String finalPackageName = ProjectHelper.getApkFilename(project, null /*config*/); - if (mBuildFinalPackage == false) { - tmp = androidOutputFolder.findMember(finalPackageName); - if (tmp == null || (tmp instanceof IFile && - tmp.exists() == false)) { - String msg = String.format(Messages.s_Missing_Repackaging, finalPackageName); - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, msg); - mBuildFinalPackage = true; - } - } - - // at this point we know if we need to recreate the temporary apk - // or the dex file, but we don't know if we simply need to recreate them - // because they are missing - - // refresh the output directory first - IContainer ic = androidOutputFolder.getParent(); - if (ic != null) { - ic.refreshLocal(IResource.DEPTH_ONE, monitor); - } - - // we need to test all three, as we may need to make the final package - // but not the intermediary ones. - if (mPackageResources || mConvertToDex || mBuildFinalPackage) { - String forceJumboStr = projectState.getProperty( - AdtConstants.DEX_OPTIONS_FORCEJUMBO); - Boolean jumbo = Boolean.valueOf(forceJumboStr); - - String dexMergerStr = projectState.getProperty( - AdtConstants.DEX_OPTIONS_DISABLE_MERGER); - Boolean dexMerger = Boolean.valueOf(dexMergerStr); - - BuildHelper helper = new BuildHelper( - projectState, - mBuildToolInfo, - mOutStream, mErrStream, - jumbo.booleanValue(), - dexMerger.booleanValue(), - true /*debugMode*/, - AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE, - mResourceMarker); - - IPath androidBinLocation = androidOutputFolder.getLocation(); - if (androidBinLocation == null) { - markProject(AdtConstants.MARKER_PACKAGING, Messages.Output_Missing, - IMarker.SEVERITY_ERROR); - return allRefProjects; - } - String osAndroidBinPath = androidBinLocation.toOSString(); - - // resource to the AndroidManifest.xml file - IFile manifestFile = androidOutputFolder.getFile( - SdkConstants.FN_ANDROID_MANIFEST_XML); - - if (manifestFile == null || manifestFile.exists() == false) { - // mark project and exit - String msg = String.format(Messages.s_File_Missing, - SdkConstants.FN_ANDROID_MANIFEST_XML); - markProject(AdtConstants.MARKER_PACKAGING, msg, IMarker.SEVERITY_ERROR); - return allRefProjects; - } - - // Remove the old .apk. - // This make sure that if the apk is corrupted, then dx (which would attempt - // to open it), will not fail. - String osFinalPackagePath = osAndroidBinPath + File.separator + finalPackageName; - File finalPackage = new File(osFinalPackagePath); - - // if delete failed, this is not really a problem, as the final package generation - // handle already present .apk, and if that one failed as well, the user will be - // notified. - finalPackage.delete(); - - // Check if we need to package the resources. - if (mPackageResources) { - // also update the crunch cache always since aapt does it smartly only - // on the files that need it. - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s running crunch!", project.getName()); - } - if (updateCrunchCache(project, helper) == false) { - return allRefProjects; - } - - // refresh recursively bin/res folder - resOutputFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); - - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s packaging resources!", project.getName()); - } - // remove some aapt_package only markers. - removeMarkersFromContainer(project, AdtConstants.MARKER_AAPT_PACKAGE); - - try { - helper.packageResources(manifestFile, libProjects, null /*resfilter*/, - 0 /*versionCode */, osAndroidBinPath, - AdtConstants.FN_RESOURCES_AP_); - } catch (AaptExecException e) { - BaseProjectHelper.markResource(project, AdtConstants.MARKER_PACKAGING, - e.getMessage(), IMarker.SEVERITY_ERROR); - return allRefProjects; - } catch (AaptResultException e) { - // attempt to parse the error output - String[] aaptOutput = e.getOutput(); - boolean parsingError = AaptParser.parseOutput(aaptOutput, project); - - // if we couldn't parse the output we display it in the console. - if (parsingError) { - AdtPlugin.printErrorToConsole(project, (Object[]) aaptOutput); - - // if the exec failed, and we couldn't parse the error output (and - // therefore not all files that should have been marked, were marked), - // we put a generic marker on the project and abort. - BaseProjectHelper.markResource(project, - AdtConstants.MARKER_PACKAGING, - Messages.Unparsed_AAPT_Errors, - IMarker.SEVERITY_ERROR); - } - } - - // build has been done. reset the state of the builder - mPackageResources = false; - - // and store it - saveProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, mPackageResources); - } - - String classesDexPath = osAndroidBinPath + File.separator + - SdkConstants.FN_APK_CLASSES_DEX; - - // then we check if we need to package the .class into classes.dex - if (mConvertToDex) { - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s running dex!", project.getName()); - } - try { - Collection<String> dxInputPaths = helper.getCompiledCodePaths(); - - helper.executeDx(javaProject, dxInputPaths, classesDexPath); - } catch (DexException e) { - String message = e.getMessage(); - - AdtPlugin.printErrorToConsole(project, message); - BaseProjectHelper.markResource(project, AdtConstants.MARKER_PACKAGING, - message, IMarker.SEVERITY_ERROR); - - Throwable cause = e.getCause(); - - if (cause instanceof NoClassDefFoundError - || cause instanceof NoSuchMethodError) { - AdtPlugin.printErrorToConsole(project, Messages.Incompatible_VM_Warning, - Messages.Requires_1_5_Error); - } - - // dx failed, we return - return allRefProjects; - } - - // build has been done. reset the state of the builder - mConvertToDex = false; - - // and store it - saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, mConvertToDex); - } - - // now we need to make the final package from the intermediary apk - // and classes.dex. - // This is the default package with all the resources. - - try { - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s making final package!", project.getName()); - } - helper.finalDebugPackage( - osAndroidBinPath + File.separator + AdtConstants.FN_RESOURCES_AP_, - classesDexPath, osFinalPackagePath, libProjects, mResourceMarker); - } catch (KeytoolException e) { - String eMessage = e.getMessage(); - - // mark the project with the standard message - String msg = String.format(Messages.Final_Archive_Error_s, eMessage); - BaseProjectHelper.markResource(project, AdtConstants.MARKER_PACKAGING, msg, - IMarker.SEVERITY_ERROR); - - // output more info in the console - AdtPlugin.printErrorToConsole(project, - msg, - String.format(Messages.ApkBuilder_JAVA_HOME_is_s, e.getJavaHome()), - Messages.ApkBuilder_Update_or_Execute_manually_s, - e.getCommandLine()); - - AdtPlugin.log(e, msg); - - return allRefProjects; - } catch (ApkCreationException e) { - String eMessage = e.getMessage(); - - // mark the project with the standard message - String msg = String.format(Messages.Final_Archive_Error_s, eMessage); - BaseProjectHelper.markResource(project, AdtConstants.MARKER_PACKAGING, msg, - IMarker.SEVERITY_ERROR); - - AdtPlugin.log(e, msg); - } catch (AndroidLocationException e) { - String eMessage = e.getMessage(); - - // mark the project with the standard message - String msg = String.format(Messages.Final_Archive_Error_s, eMessage); - BaseProjectHelper.markResource(project, AdtConstants.MARKER_PACKAGING, msg, - IMarker.SEVERITY_ERROR); - AdtPlugin.log(e, msg); - } catch (NativeLibInJarException e) { - String msg = e.getMessage(); - - BaseProjectHelper.markResource(project, AdtConstants.MARKER_PACKAGING, - msg, IMarker.SEVERITY_ERROR); - - AdtPlugin.printErrorToConsole(project, (Object[]) e.getAdditionalInfo()); - } catch (CoreException e) { - // mark project and return - String msg = String.format(Messages.Final_Archive_Error_s, e.getMessage()); - AdtPlugin.printErrorToConsole(project, msg); - BaseProjectHelper.markResource(project, AdtConstants.MARKER_PACKAGING, msg, - IMarker.SEVERITY_ERROR); - AdtPlugin.log(e, msg); - } catch (DuplicateFileException e) { - String msg1 = String.format( - "Found duplicate file for APK: %1$s\nOrigin 1: %2$s\nOrigin 2: %3$s", - e.getArchivePath(), e.getFile1(), e.getFile2()); - String msg2 = String.format(Messages.Final_Archive_Error_s, msg1); - AdtPlugin.printErrorToConsole(project, msg2); - BaseProjectHelper.markResource(project, AdtConstants.MARKER_PACKAGING, msg2, - IMarker.SEVERITY_ERROR); - } - - // we are done. - - // refresh the bin folder content with no recursion. - androidOutputFolder.refreshLocal(IResource.DEPTH_ONE, monitor); - - // build has been done. reset the state of the builder - mBuildFinalPackage = false; - - // and store it - saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage); - - // reset the installation manager to force new installs of this project - ApkInstallManager.getInstance().resetInstallationFor(project); - - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, getProject(), - "Build Success!"); - } - } catch (AbortBuildException e) { - return allRefProjects; - } catch (Exception exception) { - // try to catch other exception to actually display an error. This will be useful - // if we get an NPE or something so that we can at least notify the user that something - // went wrong. - - // first check if this is a CoreException we threw to cancel the build. - if (exception instanceof CoreException) { - if (((CoreException)exception).getStatus().getSeverity() == IStatus.CANCEL) { - // Project is already marked with an error. Nothing to do - return allRefProjects; - } - } - - String msg = exception.getMessage(); - if (msg == null) { - msg = exception.getClass().getCanonicalName(); - } - - msg = String.format("Unknown error: %1$s", msg); - AdtPlugin.logAndPrintError(exception, project.getName(), msg); - markProject(AdtConstants.MARKER_PACKAGING, msg, IMarker.SEVERITY_ERROR); - } - - // Benchmarking end - if (BuildHelper.BENCHMARK_FLAG) { - String msg = "BENCHMARK ADT: Ending PostCompilation. \n BENCHMARK ADT: Time Elapsed: " + //$NON-NLS-1$ - ((System.nanoTime() - startBuildTime)/Math.pow(10, 6)) + "ms"; //$NON-NLS-1$ - AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, project, msg); - // End Overall Timer - msg = "BENCHMARK ADT: Done with everything! \n BENCHMARK ADT: Time Elapsed: " + //$NON-NLS-1$ - (System.nanoTime() - BuildHelper.sStartOverallTime)/Math.pow(10, 6) + "ms"; //$NON-NLS-1$ - AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, project, msg); - } - - return allRefProjects; - } - - private static class JarBuilder implements IArchiveBuilder { - - private static Pattern R_PATTERN = Pattern.compile("R(\\$.*)?\\.class"); //$NON-NLS-1$ - private static String BUILD_CONFIG_CLASS = "BuildConfig.class"; //$NON-NLS-1$ - - private final byte[] buffer = new byte[1024]; - private final JarOutputStream mOutputStream; - private final String mAppPackage; - - JarBuilder(JarOutputStream outputStream, String appPackage) { - mOutputStream = outputStream; - mAppPackage = appPackage.replace('.', '/'); - } - - public void addFile(IFile file, IFolder rootFolder) throws ApkCreationException { - // we only package class file from the output folder - if (SdkConstants.EXT_CLASS.equals(file.getFileExtension()) == false) { - return; - } - - IPath packageApp = file.getParent().getFullPath().makeRelativeTo( - rootFolder.getFullPath()); - - String name = file.getName(); - // Ignore the library's R/Manifest/BuildConfig classes. - if (mAppPackage.equals(packageApp.toString()) && - (BUILD_CONFIG_CLASS.equals(name) || - R_PATTERN.matcher(name).matches())) { - return; - } - - IPath path = file.getFullPath().makeRelativeTo(rootFolder.getFullPath()); - try { - addFile(file.getContents(), file.getLocalTimeStamp(), path.toString()); - } catch (ApkCreationException e) { - throw e; - } catch (Exception e) { - throw new ApkCreationException(e, "Failed to add %s", file); - } - } - - @Override - public void addFile(File file, String archivePath) throws ApkCreationException, - SealedApkException, DuplicateFileException { - try { - FileInputStream inputStream = new FileInputStream(file); - long lastModified = file.lastModified(); - addFile(inputStream, lastModified, archivePath); - } catch (ApkCreationException e) { - throw e; - } catch (Exception e) { - throw new ApkCreationException(e, "Failed to add %s", file); - } - } - - private void addFile(InputStream content, long lastModified, String archivePath) - throws IOException, ApkCreationException { - // create the jar entry - JarEntry entry = new JarEntry(archivePath); - entry.setTime(lastModified); - - try { - // add the entry to the jar archive - mOutputStream.putNextEntry(entry); - - // read the content of the entry from the input stream, and write - // it into the archive. - int count; - while ((count = content.read(buffer)) != -1) { - mOutputStream.write(buffer, 0, count); - } - } finally { - try { - if (content != null) { - content.close(); - } - } catch (Exception e) { - throw new ApkCreationException(e, "Failed to close stream"); - } - } - } - } - - /** - * Updates the crunch cache if needed and return true if the build must continue. - */ - private boolean updateCrunchCache(IProject project, BuildHelper helper) { - try { - helper.updateCrunchCache(); - } catch (AaptExecException e) { - BaseProjectHelper.markResource(project, AdtConstants.MARKER_PACKAGING, - e.getMessage(), IMarker.SEVERITY_ERROR); - return false; - } catch (AaptResultException e) { - // attempt to parse the error output - String[] aaptOutput = e.getOutput(); - boolean parsingError = AaptParser.parseOutput(aaptOutput, project); - // if we couldn't parse the output we display it in the console. - if (parsingError) { - AdtPlugin.printErrorToConsole(project, (Object[]) aaptOutput); - } - } - - return true; - } - - /** - * Writes the library jar file. - * @param jarIFile the destination file - * @param project the library project - * @param appPackage the library android package - * @param javaOutputFolder the JDT output folder. - */ - private void writeLibraryPackage(IFile jarIFile, IProject project, String appPackage, - IFolder javaOutputFolder) { - - JarOutputStream jos = null; - try { - Manifest manifest = new Manifest(); - Attributes mainAttributes = manifest.getMainAttributes(); - mainAttributes.put(Attributes.Name.CLASS_PATH, "Android ADT"); //$NON-NLS-1$ - mainAttributes.putValue("Created-By", "1.0 (Android)"); //$NON-NLS-1$ //$NON-NLS-2$ - jos = new JarOutputStream( - new FileOutputStream(jarIFile.getLocation().toFile()), manifest); - - JarBuilder jarBuilder = new JarBuilder(jos, appPackage); - - // write the class files - writeClassFilesIntoJar(jarBuilder, javaOutputFolder, javaOutputFolder); - - // now write the standard Java resources from the output folder - ApkBuilder.addSourceFolder(jarBuilder, javaOutputFolder.getLocation().toFile()); - - saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, mConvertToDex); - } catch (Exception e) { - AdtPlugin.log(e, "Failed to write jar file %s", jarIFile.getLocation().toOSString()); - } finally { - if (jos != null) { - try { - jos.close(); - } catch (IOException e) { - // pass - } - } - } - } - - private void writeClassFilesIntoJar(JarBuilder builder, IFolder folder, IFolder rootFolder) - throws CoreException, IOException, ApkCreationException { - IResource[] members = folder.members(); - for (IResource member : members) { - if (member.getType() == IResource.FOLDER) { - writeClassFilesIntoJar(builder, (IFolder) member, rootFolder); - } else if (member.getType() == IResource.FILE) { - IFile file = (IFile) member; - builder.addFile(file, rootFolder); - } - } - } - - @Override - protected void startupOnInitialize() { - super.startupOnInitialize(); - - // load the build status. We pass true as the default value to - // force a recompile in case the property was not found - mConvertToDex = loadProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, true); - mPackageResources = loadProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, true); - mBuildFinalPackage = loadProjectBooleanProperty(PROPERTY_BUILD_APK, true); - } - - @Override - protected void abortOnBadSetup( - @NonNull IJavaProject javaProject, - @Nullable ProjectState projectState) throws AbortBuildException, CoreException { - super.abortOnBadSetup(javaProject, projectState); - - IProject iProject = getProject(); - - // do a (hopefully quick) search for Precompiler type markers. Those are always only - // errors. - stopOnMarker(iProject, AdtConstants.MARKER_AAPT_COMPILE, IResource.DEPTH_INFINITE, - false /*checkSeverity*/); - stopOnMarker(iProject, AdtConstants.MARKER_AIDL, IResource.DEPTH_INFINITE, - false /*checkSeverity*/); - stopOnMarker(iProject, AdtConstants.MARKER_RENDERSCRIPT, IResource.DEPTH_INFINITE, - false /*checkSeverity*/); - stopOnMarker(iProject, AdtConstants.MARKER_ANDROID, IResource.DEPTH_ZERO, - false /*checkSeverity*/); - - // do a search for JDT markers. Those can be errors or warnings - stopOnMarker(iProject, IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, - IResource.DEPTH_INFINITE, true /*checkSeverity*/); - stopOnMarker(iProject, IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, - IResource.DEPTH_INFINITE, true /*checkSeverity*/); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java deleted file mode 100644 index 0d9ee4897..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java +++ /dev/null @@ -1,1401 +0,0 @@ -/* - * Copyright (C) 2007 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.builders; - -import com.android.SdkConstants; -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.common.xml.ManifestData; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.build.AaptParser; -import com.android.ide.eclipse.adt.internal.build.AidlProcessor; -import com.android.ide.eclipse.adt.internal.build.Messages; -import com.android.ide.eclipse.adt.internal.build.RenderScriptLauncher; -import com.android.ide.eclipse.adt.internal.build.RsSourceChangeHandler; -import com.android.ide.eclipse.adt.internal.build.SourceProcessor; -import com.android.ide.eclipse.adt.internal.build.builders.BaseBuilder.AbortBuildException; -import com.android.ide.eclipse.adt.internal.lint.EclipseLintClient; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; -import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.FixLaunchConfig; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.project.XmlErrorHandler.BasicXmlErrorListener; -import com.android.ide.eclipse.adt.internal.resources.manager.IdeScanningContext; -import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; -import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; -import com.android.ide.eclipse.adt.internal.sdk.AdtManifestMergeCallback; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.io.IFileWrapper; -import com.android.ide.eclipse.adt.io.IFolderWrapper; -import com.android.io.StreamException; -import com.android.manifmerger.ManifestMerger; -import com.android.manifmerger.MergerLog; -import com.android.sdklib.AndroidVersion; -import com.android.sdklib.BuildToolInfo; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.build.RenderScriptChecker; -import com.android.sdklib.build.RenderScriptProcessor; -import com.android.sdklib.internal.build.BuildConfigGenerator; -import com.android.sdklib.internal.build.SymbolLoader; -import com.android.sdklib.internal.build.SymbolWriter; -import com.android.sdklib.internal.project.ProjectProperties; -import com.android.sdklib.io.FileOp; -import com.android.sdklib.repository.FullRevision; -import com.android.utils.ILogger; -import com.android.utils.Pair; -import com.android.xml.AndroidManifest; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; - -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.resources.IResourceDelta; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Path; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.xml.sax.SAXException; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import javax.xml.parsers.ParserConfigurationException; - -/** - * Pre Java Compiler. - * This incremental builder performs 2 tasks: - * <ul> - * <li>compiles the resources located in the res/ folder, along with the - * AndroidManifest.xml file into the R.java class.</li> - * <li>compiles any .aidl files into a corresponding java file.</li> - * </ul> - * - */ -public class PreCompilerBuilder extends BaseBuilder { - - /** This ID is used in plugin.xml and in each project's .project file. - * It cannot be changed even if the class is renamed/moved */ - public static final String ID = "com.android.ide.eclipse.adt.PreCompilerBuilder"; //$NON-NLS-1$ - - /** Flag to pass to PreCompiler builder that the build is a release build. - */ - public final static String RELEASE_REQUESTED = "android.releaseBuild"; //$NON-NLS-1$ - - private static final String PROPERTY_PACKAGE = "manifestPackage"; //$NON-NLS-1$ - private static final String PROPERTY_MERGE_MANIFEST = "mergeManifest"; //$NON-NLS-1$ - private static final String PROPERTY_COMPILE_RESOURCES = "compileResources"; //$NON-NLS-1$ - private static final String PROPERTY_COMPILE_BUILDCONFIG = "createBuildConfig"; //$NON-NLS-1$ - private static final String PROPERTY_BUILDCONFIG_MODE = "buildConfigMode"; //$NON-NLS-1$ - - private static final boolean MANIFEST_MERGER_ENABLED_DEFAULT = false; - private static final String MANIFEST_MERGER_PROPERTY = "manifestmerger.enabled"; //$NON-NLS-1$ - - /** Merge Manifest Flag. Computed from resource delta, reset after action is taken. - * Stored persistently in the project. */ - private boolean mMustMergeManifest = false; - /** Resource compilation Flag. Computed from resource delta, reset after action is taken. - * Stored persistently in the project. */ - private boolean mMustCompileResources = false; - /** BuildConfig Flag. Computed from resource delta, reset after action is taken. - * Stored persistently in the project. */ - private boolean mMustCreateBuildConfig = false; - /** BuildConfig last more Flag. Computed from resource delta, reset after action is taken. - * Stored persistently in the project. */ - private boolean mLastBuildConfigMode; - - /** cache of the java package defined in the manifest */ - private String mManifestPackage; - - /** Output folder for generated Java File. Created on the Builder init - * @see #startupOnInitialize() - */ - private IFolder mGenFolder; - - /** - * Progress monitor used at the end of every build to refresh the content of the 'gen' folder - * and set the generated files as derived. - */ - private DerivedProgressMonitor mDerivedProgressMonitor; - - private AidlProcessor mAidlProcessor; - private RsSourceChangeHandler mRenderScriptSourceChangeHandler; - - /** - * Progress monitor waiting the end of the process to set a persistent value - * in a file. This is typically used in conjunction with <code>IResource.refresh()</code>, - * since this call is asynchronous, and we need to wait for it to finish for the file - * to be known by eclipse, before we can call <code>resource.setPersistentProperty</code> on - * a new file. - */ - private static class DerivedProgressMonitor implements IProgressMonitor { - private boolean mCancelled = false; - private boolean mDone = false; - private final IFolder mGenFolder; - - public DerivedProgressMonitor(IFolder genFolder) { - mGenFolder = genFolder; - } - - void reset() { - mDone = false; - } - - @Override - public void beginTask(String name, int totalWork) { - } - - @Override - public void done() { - if (mDone == false) { - mDone = true; - processChildrenOf(mGenFolder); - } - } - - private void processChildrenOf(IFolder folder) { - IResource[] list; - try { - list = folder.members(); - } catch (CoreException e) { - return; - } - - for (IResource member : list) { - if (member.exists()) { - if (member.getType() == IResource.FOLDER) { - processChildrenOf((IFolder) member); - } - - try { - member.setDerived(true, new NullProgressMonitor()); - } catch (CoreException e) { - // This really shouldn't happen since we check that the resource - // exist. - // Worst case scenario, the resource isn't marked as derived. - } - } - } - } - - @Override - public void internalWorked(double work) { - } - - @Override - public boolean isCanceled() { - return mCancelled; - } - - @Override - public void setCanceled(boolean value) { - mCancelled = value; - } - - @Override - public void setTaskName(String name) { - } - - @Override - public void subTask(String name) { - } - - @Override - public void worked(int work) { - } - } - - public PreCompilerBuilder() { - super(); - } - - // build() returns a list of project from which this project depends for future compilation. - @Override - protected IProject[] build( - int kind, - @SuppressWarnings("rawtypes") Map args, - IProgressMonitor monitor) - throws CoreException { - // get a project object - IProject project = getProject(); - - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s BUILD(PRE)", project.getName()); - } - - // For the PreCompiler, only the library projects are considered Referenced projects, - // as only those projects have an impact on what is generated by this builder. - IProject[] result = null; - - IFolder resOutFolder = null; - - try { - assert mDerivedProgressMonitor != null; - - mDerivedProgressMonitor.reset(); - - // get the project info - ProjectState projectState = Sdk.getProjectState(project); - - // this can happen if the project has no project.properties. - if (projectState == null) { - return null; - } - - boolean isLibrary = projectState.isLibrary(); - - IAndroidTarget projectTarget = projectState.getTarget(); - - // get the libraries - List<IProject> libProjects = projectState.getFullLibraryProjects(); - result = libProjects.toArray(new IProject[libProjects.size()]); - - IJavaProject javaProject = JavaCore.create(project); - - // Top level check to make sure the build can move forward. - abortOnBadSetup(javaProject, projectState); - - // now we need to get the classpath list - List<IPath> sourceFolderPathList = BaseProjectHelper.getSourceClasspaths(javaProject); - - IFolder androidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(project); - - resOutFolder = getResOutFolder(androidOutputFolder); - - setupSourceProcessors(javaProject, projectState, sourceFolderPathList, - androidOutputFolder); - - PreCompilerDeltaVisitor dv = null; - String javaPackage = null; - String minSdkVersion = null; - - if (kind == FULL_BUILD) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Start_Full_Pre_Compiler); - - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s full build!", project.getName()); - } - - // do some clean up. - doClean(project, monitor); - - mMustMergeManifest = true; - mMustCompileResources = true; - mMustCreateBuildConfig = true; - - mAidlProcessor.prepareFullBuild(project); - mRenderScriptSourceChangeHandler.prepareFullBuild(); - } else { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Start_Inc_Pre_Compiler); - - // Go through the resources and see if something changed. - // Even if the mCompileResources flag is true from a previously aborted - // build, we need to go through the Resource delta to get a possible - // list of aidl files to compile/remove. - IResourceDelta delta = getDelta(project); - if (delta == null) { - mMustCompileResources = true; - - mAidlProcessor.prepareFullBuild(project); - mRenderScriptSourceChangeHandler.prepareFullBuild(); - } else { - dv = new PreCompilerDeltaVisitor(this, sourceFolderPathList, - mAidlProcessor.getChangeHandler(), - mRenderScriptSourceChangeHandler); - delta.accept(dv); - - // Check to see if Manifest.xml, Manifest.java, or R.java have changed: - mMustCompileResources |= dv.getCompileResources(); - mMustMergeManifest |= dv.hasManifestChanged(); - - // Notify the ResourceManager: - ResourceManager resManager = ResourceManager.getInstance(); - - if (ResourceManager.isAutoBuilding()) { - ProjectResources projectResources = resManager.getProjectResources(project); - - IdeScanningContext context = new IdeScanningContext(projectResources, - project, true); - - boolean wasCleared = projectResources.ensureInitialized(); - - if (!wasCleared) { - resManager.processDelta(delta, context); - } - - // Check whether this project or its dependencies (libraries) have - // resources that need compilation - if (wasCleared || context.needsFullAapt()) { - mMustCompileResources = true; - - // Must also call markAaptRequested on the project to not just - // store "aapt required" on this project, but also on any projects - // depending on this project if it's a library project - ResourceManager.markAaptRequested(project); - } - - // Update error markers in the source editor - if (!mMustCompileResources) { - context.updateMarkers(false /* async */); - } - } // else: already processed the deltas in ResourceManager's IRawDeltaListener - - mAidlProcessor.doneVisiting(project); - - // get the java package from the visitor - javaPackage = dv.getManifestPackage(); - minSdkVersion = dv.getMinSdkVersion(); - } - } - - // Has anyone marked this project as needing aapt? Typically done when - // one of the library projects this project depends on has changed - mMustCompileResources |= ResourceManager.isAaptRequested(project); - - // if the main manifest didn't change, then we check for the library - // ones (will trigger manifest merging too) - if (libProjects.size() > 0) { - for (IProject libProject : libProjects) { - IResourceDelta delta = getDelta(libProject); - if (delta != null) { - PatternBasedDeltaVisitor visitor = new PatternBasedDeltaVisitor( - project, libProject, - "PRE:LibManifest"); //$NON-NLS-1$ - visitor.addSet(ChangedFileSetHelper.MANIFEST); - - ChangedFileSet textSymbolCFS = null; - if (isLibrary == false) { - textSymbolCFS = ChangedFileSetHelper.getTextSymbols( - libProject); - visitor.addSet(textSymbolCFS); - } - - delta.accept(visitor); - - mMustMergeManifest |= visitor.checkSet(ChangedFileSetHelper.MANIFEST); - - if (textSymbolCFS != null) { - mMustCompileResources |= visitor.checkSet(textSymbolCFS); - } - - // no need to test others if we have all flags at true. - if (mMustMergeManifest && - (mMustCompileResources || textSymbolCFS == null)) { - break; - } - } - } - } - - // store the build status in the persistent storage - saveProjectBooleanProperty(PROPERTY_MERGE_MANIFEST, mMustMergeManifest); - saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, mMustCompileResources); - saveProjectBooleanProperty(PROPERTY_COMPILE_BUILDCONFIG, mMustCreateBuildConfig); - - // if there was some XML errors, we just return w/o doing - // anything since we've put some markers in the files anyway. - if (dv != null && dv.mXmlError) { - AdtPlugin.printErrorToConsole(project, Messages.Xml_Error); - - return result; - } - - if (projectState.getRenderScriptSupportMode()) { - FullRevision minBuildToolsRev = new FullRevision(19,0,3); - if (mBuildToolInfo.getRevision().compareTo(minBuildToolsRev) == -1) { - String msg = "RenderScript support mode requires Build-Tools 19.0.3 or later."; - AdtPlugin.printErrorToConsole(project, msg); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - return result; - } - } - - // get the manifest file - IFile manifestFile = ProjectHelper.getManifest(project); - - if (manifestFile == null) { - String msg = String.format(Messages.s_File_Missing, - SdkConstants.FN_ANDROID_MANIFEST_XML); - AdtPlugin.printErrorToConsole(project, msg); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - return result; - - // TODO: document whether code below that uses manifest (which is now guaranteed - // to be null) will actually be executed or not. - } - - // lets check the XML of the manifest first, if that hasn't been done by the - // resource delta visitor yet. - if (dv == null || dv.getCheckedManifestXml() == false) { - BasicXmlErrorListener errorListener = new BasicXmlErrorListener(); - try { - ManifestData parser = AndroidManifestHelper.parseUnchecked( - new IFileWrapper(manifestFile), - true /*gather data*/, - errorListener); - - if (errorListener.mHasXmlError == true) { - // There was an error in the manifest, its file has been marked - // by the XmlErrorHandler. The stopBuild() call below will abort - // this with an exception. - String msg = String.format(Messages.s_Contains_Xml_Error, - SdkConstants.FN_ANDROID_MANIFEST_XML); - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, msg); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - return result; - } - - // Get the java package from the parser. - // This can be null if the parsing failed because the resource is out of sync, - // in which case the error will already have been logged anyway. - if (parser != null) { - javaPackage = parser.getPackage(); - minSdkVersion = parser.getMinSdkVersionString(); - } - } catch (StreamException e) { - handleStreamException(e); - - return result; - } catch (ParserConfigurationException e) { - String msg = String.format( - "Bad parser configuration for %s: %s", - manifestFile.getFullPath(), - e.getMessage()); - - handleException(e, msg); - return result; - - } catch (SAXException e) { - String msg = String.format( - "Parser exception for %s: %s", - manifestFile.getFullPath(), - e.getMessage()); - - handleException(e, msg); - return result; - } catch (IOException e) { - String msg = String.format( - "I/O error for %s: %s", - manifestFile.getFullPath(), - e.getMessage()); - - handleException(e, msg); - return result; - } - } - - int minSdkValue = -1; - - if (minSdkVersion != null) { - try { - minSdkValue = Integer.parseInt(minSdkVersion); - } catch (NumberFormatException e) { - // it's ok, it means minSdkVersion contains a (hopefully) valid codename. - } - - AndroidVersion targetVersion = projectTarget.getVersion(); - - // remove earlier marker from the manifest - removeMarkersFromResource(manifestFile, AdtConstants.MARKER_ADT); - - if (minSdkValue != -1) { - String codename = targetVersion.getCodename(); - if (codename != null) { - // integer minSdk when the target is a preview => fatal error - String msg = String.format( - "Platform %1$s is a preview and requires application manifest to set %2$s to '%1$s'", - codename, AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION); - AdtPlugin.printErrorToConsole(project, msg); - BaseProjectHelper.markResource(manifestFile, AdtConstants.MARKER_ADT, - msg, IMarker.SEVERITY_ERROR); - return result; - } else if (minSdkValue > targetVersion.getApiLevel()) { - // integer minSdk is too high for the target => warning - String msg = String.format( - "Attribute %1$s (%2$d) is higher than the project target API level (%3$d)", - AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, - minSdkValue, targetVersion.getApiLevel()); - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, msg); - BaseProjectHelper.markResource(manifestFile, AdtConstants.MARKER_ADT, - msg, IMarker.SEVERITY_WARNING); - } - } else { - // looks like the min sdk is a codename, check it matches the codename - // of the platform - String codename = targetVersion.getCodename(); - if (codename == null) { - // platform is not a preview => fatal error - String msg = String.format( - "Manifest attribute '%1$s' is set to '%2$s'. Integer is expected.", - AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, minSdkVersion); - AdtPlugin.printErrorToConsole(project, msg); - BaseProjectHelper.markResource(manifestFile, AdtConstants.MARKER_ADT, - msg, IMarker.SEVERITY_ERROR); - return result; - } else if (codename.equals(minSdkVersion) == false) { - // platform and manifest codenames don't match => fatal error. - String msg = String.format( - "Value of manifest attribute '%1$s' does not match platform codename '%2$s'", - AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, codename); - AdtPlugin.printErrorToConsole(project, msg); - BaseProjectHelper.markResource(manifestFile, AdtConstants.MARKER_ADT, - msg, IMarker.SEVERITY_ERROR); - return result; - } - - // if we get there, the minSdkVersion is a codename matching the target - // platform codename. In this case we set minSdkValue to the previous API - // level, as it's used by source processors. - minSdkValue = targetVersion.getApiLevel(); - } - } else if (projectTarget.getVersion().isPreview()) { - // else the minSdkVersion is not set but we are using a preview target. - // Display an error - String codename = projectTarget.getVersion().getCodename(); - String msg = String.format( - "Platform %1$s is a preview and requires application manifests to set %2$s to '%1$s'", - codename, AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION); - AdtPlugin.printErrorToConsole(project, msg); - BaseProjectHelper.markResource(manifestFile, AdtConstants.MARKER_ADT, msg, - IMarker.SEVERITY_ERROR); - return result; - } - - if (javaPackage == null || javaPackage.length() == 0) { - // looks like the AndroidManifest file isn't valid. - String msg = String.format(Messages.s_Doesnt_Declare_Package_Error, - SdkConstants.FN_ANDROID_MANIFEST_XML); - AdtPlugin.printErrorToConsole(project, msg); - BaseProjectHelper.markResource(manifestFile, AdtConstants.MARKER_ADT, - msg, IMarker.SEVERITY_ERROR); - - return result; - } else if (javaPackage.indexOf('.') == -1) { - // The application package name does not contain 2+ segments! - String msg = String.format( - "Application package '%1$s' must have a minimum of 2 segments.", - SdkConstants.FN_ANDROID_MANIFEST_XML); - AdtPlugin.printErrorToConsole(project, msg); - BaseProjectHelper.markResource(manifestFile, AdtConstants.MARKER_ADT, - msg, IMarker.SEVERITY_ERROR); - - return result; - } - - // at this point we have the java package. We need to make sure it's not a different - // package than the previous one that were built. - if (javaPackage.equals(mManifestPackage) == false) { - // The manifest package has changed, the user may want to update - // the launch configuration - if (mManifestPackage != null) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Checking_Package_Change); - - FixLaunchConfig flc = new FixLaunchConfig(project, mManifestPackage, - javaPackage); - flc.start(); - } - - // record the new manifest package, and save it. - mManifestPackage = javaPackage; - saveProjectStringProperty(PROPERTY_PACKAGE, mManifestPackage); - - // force a clean - doClean(project, monitor); - mMustMergeManifest = true; - mMustCompileResources = true; - mMustCreateBuildConfig = true; - mAidlProcessor.prepareFullBuild(project); - mRenderScriptSourceChangeHandler.prepareFullBuild(); - - saveProjectBooleanProperty(PROPERTY_MERGE_MANIFEST, mMustMergeManifest); - saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, mMustCompileResources); - saveProjectBooleanProperty(PROPERTY_COMPILE_BUILDCONFIG, mMustCreateBuildConfig); - } - - try { - handleBuildConfig(args); - } catch (IOException e) { - handleException(e, "Failed to create BuildConfig class"); - return result; - } - - // merge the manifest - if (mMustMergeManifest) { - boolean enabled = MANIFEST_MERGER_ENABLED_DEFAULT; - String propValue = projectState.getProperty(MANIFEST_MERGER_PROPERTY); - if (propValue != null) { - enabled = Boolean.valueOf(propValue); - } - - if (mergeManifest(androidOutputFolder, libProjects, enabled) == false) { - return result; - } - } - - List<File> libProjectsOut = new ArrayList<File>(libProjects.size()); - for (IProject libProject : libProjects) { - libProjectsOut.add( - BaseProjectHelper.getAndroidOutputFolder(libProject) - .getLocation().toFile()); - } - - // run the source processors - int processorStatus = SourceProcessor.COMPILE_STATUS_NONE; - - - try { - processorStatus |= mAidlProcessor.compileFiles(this, - project, projectTarget, sourceFolderPathList, - libProjectsOut, monitor); - } catch (Throwable t) { - handleException(t, "Failed to run aidl. Check workspace log for detail."); - return result; - } - - try { - processorStatus |= compileRs(minSdkValue, projectState, androidOutputFolder, - resOutFolder, monitor); - } catch (Throwable t) { - handleException(t, "Failed to run renderscript. Check workspace log for detail."); - return result; - } - - // if a processor created some resources file, force recompilation of the resources. - if ((processorStatus & SourceProcessor.COMPILE_STATUS_RES) != 0) { - mMustCompileResources = true; - // save the current state before attempting the compilation - saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, mMustCompileResources); - } - - // handle the resources, after the processors are run since some (renderscript) - // generate resources. - boolean compiledTheResources = mMustCompileResources; - if (mMustCompileResources) { - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s compiling resources!", project.getName()); - } - - IFile proguardFile = null; - if (projectState.getProperty(ProjectProperties.PROPERTY_PROGUARD_CONFIG) != null) { - proguardFile = androidOutputFolder.getFile(AdtConstants.FN_AAPT_PROGUARD); - } - - handleResources(project, javaPackage, projectTarget, manifestFile, resOutFolder, - libProjects, isLibrary, proguardFile); - } - - if (processorStatus == SourceProcessor.COMPILE_STATUS_NONE && - compiledTheResources == false) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Nothing_To_Compile); - } - } catch (AbortBuildException e) { - return result; - } finally { - // refresh the 'gen' source folder. Once this is done with the custom progress - // monitor to mark all new files as derived - mGenFolder.refreshLocal(IResource.DEPTH_INFINITE, mDerivedProgressMonitor); - if (resOutFolder != null) { - resOutFolder.refreshLocal(IResource.DEPTH_INFINITE, mDerivedProgressMonitor); - } - } - - return result; - } - - private IFolder getResOutFolder(IFolder androidOutputFolder) { - return androidOutputFolder.getFolder(AdtConstants.WS_BIN_RELATIVE_BC); - } - - @Override - protected void clean(IProgressMonitor monitor) throws CoreException { - super.clean(monitor); - - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s CLEAN(PRE)", getProject().getName()); - } - - doClean(getProject(), monitor); - if (mGenFolder != null) { - mGenFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); - } - } - - private void doClean(IProject project, IProgressMonitor monitor) throws CoreException { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Removing_Generated_Classes); - - // remove all the derived resources from the 'gen' source folder. - if (mGenFolder != null && mGenFolder.exists()) { - // gen folder should not be derived, but previous version could set it to derived - // so we make sure this isn't the case (or it'll get deleted by the clean) - mGenFolder.setDerived(false, monitor); - - removeDerivedResources(mGenFolder, monitor); - } - - // Clear the project of the generic markers - removeMarkersFromContainer(project, AdtConstants.MARKER_AAPT_COMPILE); - removeMarkersFromContainer(project, AdtConstants.MARKER_XML); - removeMarkersFromContainer(project, AdtConstants.MARKER_AIDL); - removeMarkersFromContainer(project, AdtConstants.MARKER_RENDERSCRIPT); - removeMarkersFromContainer(project, AdtConstants.MARKER_MANIFMERGER); - removeMarkersFromContainer(project, AdtConstants.MARKER_ANDROID); - - // Also clean up lint - EclipseLintClient.clearMarkers(project); - - // clean the project repo - ProjectResources res = ResourceManager.getInstance().getProjectResources(project); - res.clear(); - } - - @Override - protected void startupOnInitialize() { - try { - super.startupOnInitialize(); - - IProject project = getProject(); - - // load the previous IFolder and java package. - mManifestPackage = loadProjectStringProperty(PROPERTY_PACKAGE); - - // get the source folder in which all the Java files are created - mGenFolder = project.getFolder(SdkConstants.FD_GEN_SOURCES); - mDerivedProgressMonitor = new DerivedProgressMonitor(mGenFolder); - - // Load the current compile flags. We ask for true if not found to force a recompile. - mMustMergeManifest = loadProjectBooleanProperty(PROPERTY_MERGE_MANIFEST, true); - mMustCompileResources = loadProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, true); - mMustCreateBuildConfig = loadProjectBooleanProperty(PROPERTY_COMPILE_BUILDCONFIG, true); - Boolean v = ProjectHelper.loadBooleanProperty(project, PROPERTY_BUILDCONFIG_MODE); - if (v == null) { - // no previous build config mode? force regenerate - mMustCreateBuildConfig = true; - } else { - mLastBuildConfigMode = v; - } - - } catch (Throwable throwable) { - AdtPlugin.log(throwable, "Failed to finish PrecompilerBuilder#startupOnInitialize()"); - } - } - - private void setupSourceProcessors(@NonNull IJavaProject javaProject, - @NonNull ProjectState projectState, - @NonNull List<IPath> sourceFolderPathList, - @NonNull IFolder androidOutputFolder) { - if (mAidlProcessor == null) { - mAidlProcessor = new AidlProcessor(javaProject, mBuildToolInfo, mGenFolder); - } else { - mAidlProcessor.setBuildToolInfo(mBuildToolInfo); - } - - List<File> sourceFolders = Lists.newArrayListWithCapacity(sourceFolderPathList.size()); - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - - for (IPath path : sourceFolderPathList) { - IResource resource = root.findMember(path); - if (resource != null && resource.exists() && resource.getType() == IResource.FOLDER) { - IPath fullPath = resource.getLocation(); - if (fullPath != null) { - sourceFolders.add(fullPath.toFile()); - } - } - } - - RenderScriptChecker checker = new RenderScriptChecker(sourceFolders, - androidOutputFolder.getLocation().toFile()); - mRenderScriptSourceChangeHandler = new RsSourceChangeHandler(checker); - } - - private int compileRs(int minSdkValue, - @NonNull ProjectState projectState, - @NonNull IFolder androidOutputFolder, - @NonNull IFolder resOutFolder, - @NonNull IProgressMonitor monitor) - throws IOException, InterruptedException { - if (!mRenderScriptSourceChangeHandler.mustCompile()) { - return SourceProcessor.COMPILE_STATUS_NONE; - } - - RenderScriptChecker checker = mRenderScriptSourceChangeHandler.getChecker(); - - List<File> inputs = checker.findInputFiles(); - List<File> importFolders = checker.getSourceFolders(); - File buildFolder = androidOutputFolder.getLocation().toFile(); - - - // get the renderscript target - int rsTarget = minSdkValue == -1 ? 11 : minSdkValue; - String rsTargetStr = projectState.getProperty(ProjectProperties.PROPERTY_RS_TARGET); - if (rsTargetStr != null) { - try { - rsTarget = Integer.parseInt(rsTargetStr); - } catch (NumberFormatException e) { - handleException(e, String.format( - "Property %s is not an integer.", - ProjectProperties.PROPERTY_RS_TARGET)); - return SourceProcessor.COMPILE_STATUS_NONE; - } - } - - RenderScriptProcessor processor = new RenderScriptProcessor( - inputs, - importFolders, - buildFolder, - mGenFolder.getLocation().toFile(), - resOutFolder.getLocation().toFile(), - new File(buildFolder, SdkConstants.FD_RS_OBJ), - new File(buildFolder, SdkConstants.FD_RS_LIBS), - mBuildToolInfo, - rsTarget, - false /*debugBuild, always false for now*/, - 3, - projectState.getRenderScriptSupportMode()); - - // clean old dependency files fiest - checker.cleanDependencies(); - - // then clean old output files - processor.cleanOldOutput(checker.getOldOutputs()); - - RenderScriptLauncher launcher = new RenderScriptLauncher( - getProject(), - mGenFolder, - resOutFolder, - monitor, - AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE /*verbose*/); - - // and run the build - processor.build(launcher); - - return SourceProcessor.COMPILE_STATUS_CODE | SourceProcessor.COMPILE_STATUS_RES; - } - - @SuppressWarnings("deprecation") - private void handleBuildConfig(@SuppressWarnings("rawtypes") Map args) - throws IOException, CoreException { - boolean debugMode = !args.containsKey(RELEASE_REQUESTED); - - BuildConfigGenerator generator = new BuildConfigGenerator( - mGenFolder.getLocation().toOSString(), mManifestPackage, debugMode); - - if (mMustCreateBuildConfig == false) { - // check the file is present. - IFolder folder = getGenManifestPackageFolder(); - if (folder.exists(new Path(BuildConfigGenerator.BUILD_CONFIG_NAME)) == false) { - mMustCreateBuildConfig = true; - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, getProject(), - String.format("Class %1$s is missing!", - BuildConfigGenerator.BUILD_CONFIG_NAME)); - } else if (debugMode != mLastBuildConfigMode) { - // else if the build mode changed, force creation - mMustCreateBuildConfig = true; - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, getProject(), - String.format("Different build mode, must update %1$s!", - BuildConfigGenerator.BUILD_CONFIG_NAME)); - } - } - - if (mMustCreateBuildConfig) { - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s generating BuilderConfig!", getProject().getName()); - } - - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, getProject(), - String.format("Generating %1$s...", BuildConfigGenerator.BUILD_CONFIG_NAME)); - generator.generate(); - - mMustCreateBuildConfig = false; - saveProjectBooleanProperty(PROPERTY_COMPILE_BUILDCONFIG, mMustCreateBuildConfig); - saveProjectBooleanProperty(PROPERTY_BUILDCONFIG_MODE, mLastBuildConfigMode = debugMode); - } - } - - private boolean mergeManifest(IFolder androidOutFolder, List<IProject> libProjects, - boolean enabled) throws CoreException { - if (DEBUG_LOG) { - AdtPlugin.log(IStatus.INFO, "%s merging manifests!", getProject().getName()); - } - - IFile outFile = androidOutFolder.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML); - IFile manifest = getProject().getFile(SdkConstants.FN_ANDROID_MANIFEST_XML); - - // remove existing markers from the manifest. - // FIXME: only remove from manifest once the markers are put there. - removeMarkersFromResource(getProject(), AdtConstants.MARKER_MANIFMERGER); - - // If the merging is not enabled or if there's no library then we simply copy the - // manifest over. - if (enabled == false || libProjects.size() == 0) { - try { - new FileOp().copyFile(manifest.getLocation().toFile(), - outFile.getLocation().toFile()); - - outFile.refreshLocal(IResource.DEPTH_INFINITE, mDerivedProgressMonitor); - - saveProjectBooleanProperty(PROPERTY_MERGE_MANIFEST, mMustMergeManifest = false); - } catch (IOException e) { - handleException(e, "Failed to copy Manifest"); - return false; - } - } else { - final ArrayList<String> errors = new ArrayList<String>(); - - // TODO change MergerLog.wrapSdkLog by a custom IMergerLog that will create - // and maintain error markers. - ManifestMerger merger = new ManifestMerger( - MergerLog.wrapSdkLog(new ILogger() { - @Override - public void warning(@NonNull String warningFormat, Object... args) { - AdtPlugin.printToConsole(getProject(), String.format(warningFormat, args)); - } - - @Override - public void info(@NonNull String msgFormat, Object... args) { - AdtPlugin.printToConsole(getProject(), String.format(msgFormat, args)); - } - - @Override - public void verbose(@NonNull String msgFormat, Object... args) { - info(msgFormat, args); - } - - @Override - public void error(@Nullable Throwable t, @Nullable String errorFormat, - Object... args) { - errors.add(String.format(errorFormat, args)); - } - }), - new AdtManifestMergeCallback()); - - File[] libManifests = new File[libProjects.size()]; - int libIndex = 0; - for (IProject lib : libProjects) { - libManifests[libIndex++] = lib.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML) - .getLocation().toFile(); - } - - if (merger.process( - outFile.getLocation().toFile(), - manifest.getLocation().toFile(), - libManifests, - null /*injectAttributes*/, null /*packageOverride*/) == false) { - if (errors.size() > 1) { - StringBuilder sb = new StringBuilder(); - for (String s : errors) { - sb.append(s).append('\n'); - } - - markProject(AdtConstants.MARKER_MANIFMERGER, sb.toString(), - IMarker.SEVERITY_ERROR); - - } else if (errors.size() == 1) { - markProject(AdtConstants.MARKER_MANIFMERGER, errors.get(0), - IMarker.SEVERITY_ERROR); - } else { - markProject(AdtConstants.MARKER_MANIFMERGER, "Unknown error merging manifest", - IMarker.SEVERITY_ERROR); - } - return false; - } - - outFile.refreshLocal(IResource.DEPTH_INFINITE, mDerivedProgressMonitor); - saveProjectBooleanProperty(PROPERTY_MERGE_MANIFEST, mMustMergeManifest = false); - } - - return true; - } - - /** - * Handles resource changes and regenerate whatever files need regenerating. - * @param project the main project - * @param javaPackage the app package for the main project - * @param projectTarget the target of the main project - * @param manifest the {@link IFile} representing the project manifest - * @param libProjects the library dependencies - * @param isLibrary if the project is a library project - * @throws CoreException - * @throws AbortBuildException - */ - private void handleResources(IProject project, String javaPackage, IAndroidTarget projectTarget, - IFile manifest, IFolder resOutFolder, List<IProject> libProjects, boolean isLibrary, - IFile proguardFile) throws CoreException, AbortBuildException { - // get the resource folder - IFolder resFolder = project.getFolder(AdtConstants.WS_RESOURCES); - - // get the file system path - IPath outputLocation = mGenFolder.getLocation(); - IPath resLocation = resFolder.getLocation(); - IPath manifestLocation = manifest == null ? null : manifest.getLocation(); - - // those locations have to exist for us to do something! - if (outputLocation != null && resLocation != null - && manifestLocation != null) { - String osOutputPath = outputLocation.toOSString(); - String osResPath = resLocation.toOSString(); - String osManifestPath = manifestLocation.toOSString(); - - // remove the aapt markers - removeMarkersFromResource(manifest, AdtConstants.MARKER_AAPT_COMPILE); - removeMarkersFromContainer(resFolder, AdtConstants.MARKER_AAPT_COMPILE); - - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.Preparing_Generated_Files); - - // we need to figure out where to store the R class. - // get the parent folder for R.java and update mManifestPackageSourceFolder - IFolder mainPackageFolder = getGenManifestPackageFolder(); - - // handle libraries - ArrayList<IFolder> libResFolders = Lists.newArrayList(); - ArrayList<Pair<File, String>> libRFiles = Lists.newArrayList(); - if (libProjects != null) { - for (IProject lib : libProjects) { - IFolder libResFolder = lib.getFolder(SdkConstants.FD_RES); - if (libResFolder.exists()) { - libResFolders.add(libResFolder); - } - - try { - // get the package of the library, and if it's different form the - // main project, generate the R class for it too. - String libJavaPackage = AndroidManifest.getPackage(new IFolderWrapper(lib)); - if (libJavaPackage.equals(javaPackage) == false) { - - IFolder libOutput = BaseProjectHelper.getAndroidOutputFolder(lib); - File libOutputFolder = libOutput.getLocation().toFile(); - - libRFiles.add(Pair.of( - new File(libOutputFolder, "R.txt"), - libJavaPackage)); - - } - } catch (Exception e) { - } - } - } - - String proguardFilePath = proguardFile != null ? - proguardFile.getLocation().toOSString(): null; - - File resOutFile = resOutFolder.getLocation().toFile(); - String resOutPath = resOutFile.isDirectory() ? resOutFile.getAbsolutePath() : null; - - execAapt(project, projectTarget, osOutputPath, resOutPath, osResPath, osManifestPath, - mainPackageFolder, libResFolders, libRFiles, isLibrary, proguardFilePath); - } - } - - /** - * Executes AAPT to generate R.java/Manifest.java - * @param project the main project - * @param projectTarget the main project target - * @param osOutputPath the OS output path for the generated file. This is the source folder, not - * the package folder. - * @param osResPath the OS path to the res folder for the main project - * @param osManifestPath the OS path to the manifest of the main project - * @param packageFolder the IFolder that will contain the generated file. Unlike - * <var>osOutputPath</var> this is the direct parent of the generated files. - * If <var>customJavaPackage</var> is not null, this must match the new destination triggered - * by its value. - * @param libResFolders the list of res folders for the library. - * @param libRFiles a list of R files for the libraries. - * @param isLibrary if the project is a library project - * @param proguardFile an optional path to store proguard information - * @throws AbortBuildException - */ - @SuppressWarnings("deprecation") - private void execAapt(IProject project, IAndroidTarget projectTarget, String osOutputPath, - String osBcOutPath, String osResPath, String osManifestPath, IFolder packageFolder, - ArrayList<IFolder> libResFolders, List<Pair<File, String>> libRFiles, - boolean isLibrary, String proguardFile) - throws AbortBuildException { - - // We actually need to delete the manifest.java as it may become empty and - // in this case aapt doesn't generate an empty one, but instead doesn't - // touch it. - IFile manifestJavaFile = packageFolder.getFile(SdkConstants.FN_MANIFEST_CLASS); - manifestJavaFile.getLocation().toFile().delete(); - - // launch aapt: create the command line - ArrayList<String> array = new ArrayList<String>(); - - String aaptPath = mBuildToolInfo.getPath(BuildToolInfo.PathId.AAPT); - - array.add(aaptPath); - array.add("package"); //$NON-NLS-1$ - array.add("-m"); //$NON-NLS-1$ - if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) { - array.add("-v"); //$NON-NLS-1$ - } - - if (isLibrary) { - array.add("--non-constant-id"); //$NON-NLS-1$ - } - - if (libResFolders.size() > 0) { - array.add("--auto-add-overlay"); //$NON-NLS-1$ - } - - // If a library or has libraries, generate a text version of the R symbols. - File outputFolder = BaseProjectHelper.getAndroidOutputFolder(project).getLocation() - .toFile(); - - if (isLibrary || !libRFiles.isEmpty()) { - array.add("--output-text-symbols"); //$NON-NLS-1$ - array.add(outputFolder.getAbsolutePath()); - } - - array.add("-J"); //$NON-NLS-1$ - array.add(osOutputPath); - array.add("-M"); //$NON-NLS-1$ - array.add(osManifestPath); - if (osBcOutPath != null) { - array.add("-S"); //$NON-NLS-1$ - array.add(osBcOutPath); - } - array.add("-S"); //$NON-NLS-1$ - array.add(osResPath); - for (IFolder libResFolder : libResFolders) { - array.add("-S"); //$NON-NLS-1$ - array.add(libResFolder.getLocation().toOSString()); - } - - array.add("-I"); //$NON-NLS-1$ - array.add(projectTarget.getPath(IAndroidTarget.ANDROID_JAR)); - - // use the proguard file - if (proguardFile != null && proguardFile.length() > 0) { - array.add("-G"); - array.add(proguardFile); - } - - if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) { - StringBuilder sb = new StringBuilder(); - for (String c : array) { - sb.append(c); - sb.append(' '); - } - String cmd_line = sb.toString(); - AdtPlugin.printToConsole(project, cmd_line); - } - - // launch - try { - // launch the command line process - Process process = Runtime.getRuntime().exec( - array.toArray(new String[array.size()])); - - // list to store each line of stderr - ArrayList<String> stdErr = new ArrayList<String>(); - - // get the output and return code from the process - int returnCode = grabProcessOutput(process, stdErr); - - // attempt to parse the error output - boolean parsingError = AaptParser.parseOutput(stdErr, project); - - // if we couldn't parse the output we display it in the console. - if (parsingError) { - if (returnCode != 0) { - AdtPlugin.printErrorToConsole(project, stdErr.toArray()); - } else { - AdtPlugin.printBuildToConsole(BuildVerbosity.NORMAL, - project, stdErr.toArray()); - } - } - - if (returnCode != 0) { - // if the exec failed, and we couldn't parse the error output - // (and therefore not all files that should have been marked, - // were marked), we put a generic marker on the project and abort. - if (parsingError) { - markProject(AdtConstants.MARKER_ADT, - Messages.Unparsed_AAPT_Errors, IMarker.SEVERITY_ERROR); - } else if (stdErr.size() == 0) { - // no parsing error because sdterr was empty. We still need to put - // a marker otherwise there's no user visible feedback. - markProject(AdtConstants.MARKER_ADT, - String.format(Messages.AAPT_Exec_Error_d, returnCode), - IMarker.SEVERITY_ERROR); - } - - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - Messages.AAPT_Error); - - // abort if exec failed. - throw new AbortBuildException(); - } - - // now if the project has libraries, R needs to be created for each libraries - // unless this is a library. - if (isLibrary == false && !libRFiles.isEmpty()) { - File rFile = new File(outputFolder, SdkConstants.FN_RESOURCE_TEXT); - // if the project has no resources, the file could not exist. - if (rFile.isFile()) { - // Load the full symbols from the full R.txt file. - SymbolLoader fullSymbolValues = new SymbolLoader(rFile); - fullSymbolValues.load(); - - Multimap<String, SymbolLoader> libMap = ArrayListMultimap.create(); - - // First pass processing the libraries, collecting them by packageName, - // and ignoring the ones that have the same package name as the application - // (since that R class was already created). - - for (Pair<File, String> lib : libRFiles) { - String libPackage = lib.getSecond(); - File rText = lib.getFirst(); - - if (rText.isFile()) { - // load the lib symbols - SymbolLoader libSymbols = new SymbolLoader(rText); - libSymbols.load(); - - // store these symbols by associating them with the package name. - libMap.put(libPackage, libSymbols); - } - } - - // now loop on all the package names, merge all the symbols to write, - // and write them - for (String packageName : libMap.keySet()) { - Collection<SymbolLoader> symbols = libMap.get(packageName); - - SymbolWriter writer = new SymbolWriter(osOutputPath, packageName, - fullSymbolValues); - for (SymbolLoader symbolLoader : symbols) { - writer.addSymbolsToWrite(symbolLoader); - } - writer.write(); - } - } - } - - } catch (IOException e1) { - // something happen while executing the process, - // mark the project and exit - String msg; - String path = array.get(0); - if (!new File(path).exists()) { - msg = String.format(Messages.AAPT_Exec_Error_s, path); - } else { - String description = e1.getLocalizedMessage(); - if (e1.getCause() != null && e1.getCause() != e1) { - description = description + ": " + e1.getCause().getLocalizedMessage(); - } - msg = String.format(Messages.AAPT_Exec_Error_Other_s, description); - } - - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - // Add workaround for the Linux problem described here: - // http://developer.android.com/sdk/installing.html#troubleshooting - // There are various posts on StackOverflow elsewhere where people are asking - // about aapt failing to run, so even though this is documented in the - // Troubleshooting section add an error message to help with this - // scenario. - if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_LINUX - && System.getProperty("os.arch").endsWith("64") //$NON-NLS-1$ //$NON-NLS-2$ - && new File(aaptPath).exists() - && new File("/usr/bin/apt-get").exists()) { //$NON-NLS-1$ - markProject(AdtConstants.MARKER_ADT, - "Hint: On 64-bit systems, make sure the 32-bit libraries are installed: \"sudo apt-get install ia32-libs\" or on some systems, \"sudo apt-get install lib32z1\"", - IMarker.SEVERITY_ERROR); - // Note - this uses SEVERITY_ERROR even though it's really SEVERITY_INFO because - // we want this error message to show up adjacent to the aapt error message - // (and Eclipse sorts by priority) - } - - // This interrupts the build. - throw new AbortBuildException(); - } catch (InterruptedException e) { - // we got interrupted waiting for the process to end... - // mark the project and exit - String msg = String.format(Messages.AAPT_Exec_Error_s, array.get(0)); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - // This interrupts the build. - throw new AbortBuildException(); - } finally { - // we've at least attempted to run aapt, save the fact that we don't have to - // run it again, unless there's a new resource change. - saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, - mMustCompileResources = false); - ResourceManager.clearAaptRequest(project); - } - } - - /** - * Creates a relative {@link IPath} from a java package. - * @param javaPackageName the java package. - */ - private IPath getJavaPackagePath(String javaPackageName) { - // convert the java package into path - String[] segments = javaPackageName.split(AdtConstants.RE_DOT); - - StringBuilder path = new StringBuilder(); - for (String s : segments) { - path.append(AdtConstants.WS_SEP_CHAR); - path.append(s); - } - - return new Path(path.toString()); - } - - /** - * Returns an {@link IFolder} (located inside the 'gen' source folder), that matches the - * package defined in the manifest. This {@link IFolder} may not actually exist - * (aapt will create it anyway). - * @return the {@link IFolder} that will contain the R class or null if - * the folder was not found. - * @throws CoreException - */ - private IFolder getGenManifestPackageFolder() throws CoreException { - // get the path for the package - IPath packagePath = getJavaPackagePath(mManifestPackage); - - // get a folder for this path under the 'gen' source folder, and return it. - // This IFolder may not reference an actual existing folder. - return mGenFolder.getFolder(packagePath); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java deleted file mode 100644 index 57316f568..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerDeltaVisitor.java +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright (C) 2007 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.builders; - -import com.android.SdkConstants; -import com.android.ide.common.xml.ManifestData; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.build.Messages; -import com.android.ide.eclipse.adt.internal.build.SourceChangeHandler; -import com.android.ide.eclipse.adt.internal.build.builders.BaseBuilder.BaseDeltaVisitor; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; -import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.io.IFileWrapper; -import com.google.common.collect.Lists; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.resources.IResourceDeltaVisitor; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; - -import java.util.Arrays; -import java.util.List; - -/** - * Resource Delta visitor for the pre-compiler. - * <p/>This delta visitor only cares about files that are the source or the result of actions of the - * {@link PreCompilerBuilder}: - * <ul><li>R.java/Manifest.java generated by compiling the resources</li> - * <li>Any Java files generated by <code>aidl</code></li></ul>. - * - * Therefore it looks for the following: - * <ul><li>Any modification in the resource folder</li> - * <li>Removed files from the source folder receiving generated Java files</li> - * <li>Any modification to aidl files.</li> - * - */ -class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDeltaVisitor { - - // Result fields. - private boolean mChangedManifest = false; - - /** - * Compile flag. This is set to true if one of the changed/added/removed - * files is Manifest.java, or R.java. All other file changes - * will be taken care of by ResourceManager. - */ - private boolean mCompileResources = false; - - /** Manifest check/parsing flag. */ - private boolean mCheckedManifestXml = false; - - /** Application Package, gathered from the parsing of the manifest */ - private String mJavaPackage = null; - /** minSDKVersion attribute value, gathered from the parsing of the manifest */ - private String mMinSdkVersion = null; - - // Internal usage fields. - /** - * In Resource folder flag. This allows us to know if we're in the - * resource folder. - */ - private boolean mInRes = false; - - /** - * Current Source folder. This allows us to know if we're in a source - * folder, and which folder. - */ - private IFolder mSourceFolder = null; - - /** List of source folders. */ - private final List<IPath> mSourceFolders; - private boolean mIsGenSourceFolder = false; - - private final List<SourceChangeHandler> mSourceChangeHandlers = Lists.newArrayList(); - private final IWorkspaceRoot mRoot; - - private IFolder mAndroidOutputFolder; - - public PreCompilerDeltaVisitor(BaseBuilder builder, List<IPath> sourceFolders, - SourceChangeHandler... handlers) { - super(builder); - mSourceFolders = sourceFolders; - mRoot = ResourcesPlugin.getWorkspace().getRoot(); - - mSourceChangeHandlers.addAll(Arrays.asList(handlers)); - - mAndroidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(builder.getProject()); - } - - /** - * Get whether Manifest.java, Manifest.xml, or R.java have changed - * @return true if any of Manifest.xml, Manifest.java, or R.java have been modified - */ - public boolean getCompileResources() { - return mCompileResources || mChangedManifest; - } - - public boolean hasManifestChanged() { - return mChangedManifest; - } - - /** - * Returns whether the manifest file was parsed/checked for error during the resource delta - * visiting. - */ - public boolean getCheckedManifestXml() { - return mCheckedManifestXml; - } - - /** - * Returns the manifest package if the manifest was checked/parsed. - * <p/> - * This can return null in two cases: - * <ul> - * <li>The manifest was not part of the resource change delta, and the manifest was - * not checked/parsed ({@link #getCheckedManifestXml()} returns <code>false</code>)</li> - * <li>The manifest was parsed ({@link #getCheckedManifestXml()} returns <code>true</code>), - * but the package declaration is missing</li> - * </ul> - * @return the manifest package or null. - */ - public String getManifestPackage() { - return mJavaPackage; - } - - /** - * Returns the minSDkVersion attribute from the manifest if it was checked/parsed. - * <p/> - * This can return null in two cases: - * <ul> - * <li>The manifest was not part of the resource change delta, and the manifest was - * not checked/parsed ({@link #getCheckedManifestXml()} returns <code>false</code>)</li> - * <li>The manifest was parsed ({@link #getCheckedManifestXml()} returns <code>true</code>), - * but the package declaration is missing</li> - * </ul> - * @return the minSdkVersion or null. - */ - public String getMinSdkVersion() { - return mMinSdkVersion; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.core.resources.IResourceDeltaVisitor - * #visit(org.eclipse.core.resources.IResourceDelta) - */ - @Override - public boolean visit(IResourceDelta delta) throws CoreException { - // we are only going to look for changes in res/, source folders and in - // AndroidManifest.xml since the delta visitor goes through the main - // folder before its children we can check when the path segment - // count is 2 (format will be /$Project/folder) and make sure we are - // processing res/, source folders or AndroidManifest.xml - - IResource resource = delta.getResource(); - IPath path = resource.getFullPath(); - String[] segments = path.segments(); - - // since the delta visitor also visits the root we return true if - // segments.length = 1 - if (segments.length == 1) { - // this is always the Android project since we call - // Builder#getDelta(IProject) on the project itself. - return true; - } else if (segments.length == 2) { - // if we are at an item directly under the root directory, - // then we are not yet in a source or resource folder - mInRes = false; - mSourceFolder = null; - - if (SdkConstants.FD_RESOURCES.equalsIgnoreCase(segments[1])) { - // this is the resource folder that was modified. we want to - // see its content. - - // since we're going to visit its children next, we set the - // flag - mInRes = true; - mSourceFolder = null; - return true; - } else if (SdkConstants.FN_ANDROID_MANIFEST_XML.equalsIgnoreCase(segments[1])) { - // any change in the manifest could trigger a new R.java - // class, so we don't need to check the delta kind - if (delta.getKind() != IResourceDelta.REMOVED) { - // clean the error markers on the file. - IFile manifestFile = (IFile)resource; - - if (manifestFile.exists()) { - manifestFile.deleteMarkers(AdtConstants.MARKER_XML, true, - IResource.DEPTH_ZERO); - manifestFile.deleteMarkers(AdtConstants.MARKER_ANDROID, true, - IResource.DEPTH_ZERO); - } - - // parse the manifest for data and error - ManifestData manifestData = AndroidManifestHelper.parse( - new IFileWrapper(manifestFile), true /*gatherData*/, this); - - if (manifestData != null) { - mJavaPackage = manifestData.getPackage(); - mMinSdkVersion = manifestData.getMinSdkVersionString(); - } - - mCheckedManifestXml = true; - } - mChangedManifest = true; - - // we don't want to go to the children, not like they are - // any for this resource anyway. - return false; - } - } - - // at this point we can either be in the source folder or in the - // resource folder or in a different folder that contains a source - // folder. - // This is due to not all source folder being src/. Some could be - // something/somethingelse/src/ - - // so first we test if we already know we are in a source or - // resource folder. - - if (mSourceFolder != null) { - // if we are in the res folder, we are looking for the following changes: - // - added/removed/modified aidl files. - // - missing R.java file - - // if the resource is a folder, we just go straight to the children - if (resource.getType() == IResource.FOLDER) { - return true; - } - - if (resource.getType() != IResource.FILE) { - return false; - } - IFile file = (IFile)resource; - - // get the modification kind - int kind = delta.getKind(); - - // we process normal source folder and the 'gen' source folder differently. - if (mIsGenSourceFolder) { - // this is the generated java file source folder. - // - if R.java/Manifest.java are removed/modified, we recompile the resources - // - if aidl files are removed/modified, we recompile them. - - boolean outputWarning = false; - - String fileName = resource.getName(); - - // Special case of R.java/Manifest.java. - if (SdkConstants.FN_RESOURCE_CLASS.equals(fileName) || - SdkConstants.FN_MANIFEST_CLASS.equals(fileName)) { - // if it was removed, there's a possibility that it was removed due to a - // package change, or an aidl that was removed, but the only thing - // that will happen is that we'll have an extra build. Not much of a problem. - mCompileResources = true; - - // we want a warning - outputWarning = true; - } else { - // look to see if this file was generated by a processor. - for (SourceChangeHandler handler : mSourceChangeHandlers) { - if (handler.handleGeneratedFile(file, kind)) { - outputWarning = true; - break; // there shouldn't be 2 processors that handle the same file. - } - } - } - - if (outputWarning) { - if (kind == IResourceDelta.REMOVED) { - // We print an error just so that it's red, but it's just a warning really. - String msg = String.format(Messages.s_Removed_Recreating_s, fileName); - AdtPlugin.printErrorToConsole(mBuilder.getProject(), msg); - } else if (kind == IResourceDelta.CHANGED) { - // the file was modified manually! we can't allow it. - String msg = String.format(Messages.s_Modified_Manually_Recreating_s, - fileName); - AdtPlugin.printErrorToConsole(mBuilder.getProject(), msg); - } - } - } else { - // this is another source folder. - for (SourceChangeHandler handler : mSourceChangeHandlers) { - handler.handleSourceFile(file, kind); - } - } - - // no children. - return false; - } else if (mInRes) { - // if we are in the res folder, we are looking for the following - // changes: - // - added/removed/modified xml files. - // - added/removed files of any other type - - // if the resource is a folder, we just go straight to the - // children - if (resource.getType() == IResource.FOLDER) { - return true; - } - - // get the extension of the resource - String ext = resource.getFileExtension(); - int kind = delta.getKind(); - - String p = resource.getProjectRelativePath().toString(); - String message = null; - switch (kind) { - case IResourceDelta.CHANGED: - // display verbose message - message = String.format(Messages.s_Modified_Recreating_s, p); - break; - case IResourceDelta.ADDED: - // display verbose message - message = String.format(Messages.Added_s_s_Needs_Updating, p, - SdkConstants.FN_RESOURCE_CLASS); - break; - case IResourceDelta.REMOVED: - // display verbose message - message = String.format(Messages.s_Removed_s_Needs_Updating, p, - SdkConstants.FN_RESOURCE_CLASS); - break; - } - if (message != null) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, - mBuilder.getProject(), message); - } - - // If it's an XML resource, check the syntax - if (SdkConstants.EXT_XML.equalsIgnoreCase(ext) && kind != IResourceDelta.REMOVED) { - // check xml Validity - mBuilder.checkXML(resource, this); - } - // Whether or not to generate R.java for a changed resource is taken care of by the - // Resource Manager. - } else if (resource instanceof IFolder) { - // first check if we are in the android output folder. - if (resource.equals(mAndroidOutputFolder)) { - // we want to visit the merged manifest. - return true; - } - - // in this case we may be inside a folder that contains a source - // folder, go through the list of known source folders - - for (IPath sourceFolderPath : mSourceFolders) { - // first check if they match exactly. - if (sourceFolderPath.equals(path)) { - // this is a source folder! - mInRes = false; - mSourceFolder = getFolder(sourceFolderPath); // all non null due to test above - mIsGenSourceFolder = path.segmentCount() == 2 && - path.segment(1).equals(SdkConstants.FD_GEN_SOURCES); - return true; - } - - // check if we are on the way to a source folder. - int count = sourceFolderPath.matchingFirstSegments(path); - if (count == path.segmentCount()) { - mInRes = false; - return true; - } - } - - // if we're here, we are visiting another folder - // like /$Project/bin/ for instance (we get notified for changes - // in .class!) - // This could also be another source folder and we have found - // R.java in a previous source folder - // We don't want to visit its children - return false; - } - - return false; - } - - /** - * Returns a handle to the folder identified by the given path in this container. - * <p/>The different with {@link IContainer#getFolder(IPath)} is that this returns a non - * null object only if the resource actually exists and is a folder (and not a file) - * @param path the path of the folder to return. - * @return a handle to the folder if it exists, or null otherwise. - */ - private IFolder getFolder(IPath path) { - IResource resource = mRoot.findMember(path); - if (resource != null && resource.exists() && resource.getType() == IResource.FOLDER) { - return (IFolder)resource; - } - - return null; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ResourceManagerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ResourceManagerBuilder.java deleted file mode 100644 index 8e01cca29..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/ResourceManagerBuilder.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright (C) 2007 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.builders; - -import com.android.SdkConstants; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.build.Messages; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.sdklib.BuildToolInfo; -import com.android.sdklib.IAndroidTarget; -import com.android.utils.Pair; - -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.resources.IWorkspaceRoot; -import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; - -import java.util.List; -import java.util.Map; - -/** - * Resource manager builder whose only purpose is to refresh the resource folder - * so that the other builder use an up to date version. - */ -public class ResourceManagerBuilder extends BaseBuilder { - - public static final String ID = "com.android.ide.eclipse.adt.ResourceManagerBuilder"; //$NON-NLS-1$ - - public ResourceManagerBuilder() { - super(); - } - - @Override - protected void clean(IProgressMonitor monitor) throws CoreException { - super.clean(monitor); - - // Get the project. - IProject project = getProject(); - - // Clear the project of the generic markers - removeMarkersFromContainer(project, AdtConstants.MARKER_ADT); - } - - // build() returns a list of project from which this project depends for future compilation. - @SuppressWarnings("unchecked") - @Override - protected IProject[] build(int kind, Map args, IProgressMonitor monitor) - throws CoreException { - // Get the project. - final IProject project = getProject(); - IJavaProject javaProject = JavaCore.create(project); - - // Clear the project of the generic markers - removeMarkersFromContainer(project, AdtConstants.MARKER_ADT); - - // check for existing target marker, in which case we abort. - // (this means: no SDK, no target, or unresolvable target.) - try { - abortOnBadSetup(javaProject, null); - } catch (AbortBuildException e) { - return null; - } - - // Check the compiler compliance level, displaying the error message - // since this is the first builder. - Pair<Integer, String> result = ProjectHelper.checkCompilerCompliance(project); - String errorMessage = null; - switch (result.getFirst().intValue()) { - case ProjectHelper.COMPILER_COMPLIANCE_LEVEL: - errorMessage = Messages.Requires_Compiler_Compliance_s; - break; - case ProjectHelper.COMPILER_COMPLIANCE_SOURCE: - errorMessage = Messages.Requires_Source_Compatibility_s; - break; - case ProjectHelper.COMPILER_COMPLIANCE_CODEGEN_TARGET: - errorMessage = Messages.Requires_Class_Compatibility_s; - break; - } - - if (errorMessage != null) { - errorMessage = String.format(errorMessage, - result.getSecond() == null ? "(no value)" : result.getSecond()); - - if (JavaCore.VERSION_1_7.equals(result.getSecond())) { - // If the user is trying to target 1.7 but compiling with something older, - // the error message can be a bit misleading; instead point them in the - // direction of updating the project's build target. - Sdk currentSdk = Sdk.getCurrent(); - if (currentSdk != null) { - IAndroidTarget target = currentSdk.getTarget(project.getProject()); - if (target != null && target.getVersion().getApiLevel() < 19) { - errorMessage = "Using 1.7 requires compiling with Android 4.4 " + - "(KitKat); currently using " + target.getVersion(); - } - - ProjectState projectState = Sdk.getProjectState(project); - if (projectState != null) { - BuildToolInfo buildToolInfo = projectState.getBuildToolInfo(); - if (buildToolInfo == null) { - buildToolInfo = currentSdk.getLatestBuildTool(); - } - if (buildToolInfo != null && buildToolInfo.getRevision().getMajor() < 19) { - errorMessage = "Using 1.7 requires using Android Build Tools " + - "version 19 or later; currently using " + - buildToolInfo.getRevision(); - } - } - } - } - - markProject(AdtConstants.MARKER_ADT, errorMessage, IMarker.SEVERITY_ERROR); - AdtPlugin.printErrorToConsole(project, errorMessage); - - return null; - } - - // Check that the SDK directory has been setup. - String osSdkFolder = AdtPlugin.getOsSdkFolder(); - - if (osSdkFolder == null || osSdkFolder.length() == 0) { - AdtPlugin.printErrorToConsole(project, Messages.No_SDK_Setup_Error); - markProject(AdtConstants.MARKER_ADT, Messages.No_SDK_Setup_Error, - IMarker.SEVERITY_ERROR); - - return null; - } - - // check the 'gen' source folder is present - boolean hasGenSrcFolder = false; // whether the project has a 'gen' source folder setup - - IClasspathEntry[] classpaths = javaProject.readRawClasspath(); - if (classpaths != null) { - for (IClasspathEntry e : classpaths) { - if (e.getEntryKind() == IClasspathEntry.CPE_SOURCE) { - IPath path = e.getPath(); - if (path.segmentCount() == 2 && - path.segment(1).equals(SdkConstants.FD_GEN_SOURCES)) { - hasGenSrcFolder = true; - break; - } - } - } - } - - boolean genFolderPresent = false; // whether the gen folder actually exists - IResource resource = project.findMember(SdkConstants.FD_GEN_SOURCES); - genFolderPresent = resource != null && resource.exists(); - - if (hasGenSrcFolder == false && genFolderPresent) { - // No source folder setup for 'gen' in the project, but there's already a - // 'gen' resource (file or folder). - String message; - if (resource.getType() == IResource.FOLDER) { - // folder exists already! This is an error. If the folder had been created - // by the NewProjectWizard, it'd be a source folder. - message = String.format("%1$s already exists but is not a source folder. Convert to a source folder or rename it.", - resource.getFullPath().toString()); - } else { - // resource exists but is not a folder. - message = String.format( - "Resource %1$s is in the way. ADT needs a source folder called 'gen' to work. Rename or delete resource.", - resource.getFullPath().toString()); - } - - AdtPlugin.printErrorToConsole(project, message); - markProject(AdtConstants.MARKER_ADT, message, IMarker.SEVERITY_ERROR); - - return null; - } else if (hasGenSrcFolder == false || genFolderPresent == false) { - // either there is no 'gen' source folder in the project (older SDK), - // or the folder does not exist (was deleted, or was a fresh svn checkout maybe.) - - // In case we are migrating from an older SDK, we go through the current source - // folders and delete the generated Java files. - List<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(javaProject); - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - for (IPath path : sourceFolders) { - IResource member = root.findMember(path); - if (member != null) { - removeDerivedResources(member, monitor); - } - } - - // create the new source folder, if needed - IFolder genFolder = project.getFolder(SdkConstants.FD_GEN_SOURCES); - if (genFolderPresent == false) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, - "Creating 'gen' source folder for generated Java files"); - genFolder.create(true /* force */, true /* local */, - new SubProgressMonitor(monitor, 10)); - } - - // add it to the source folder list, if needed only (or it will throw) - if (hasGenSrcFolder == false) { - IClasspathEntry[] entries = javaProject.getRawClasspath(); - entries = ProjectHelper.addEntryToClasspath(entries, - JavaCore.newSourceEntry(genFolder.getFullPath())); - javaProject.setRawClasspath(entries, new SubProgressMonitor(monitor, 10)); - } - - // refresh specifically the gen folder first, as it may break the build - // if it doesn't arrive in time then refresh the whole project as usual. - genFolder.refreshLocal(IResource.DEPTH_ZERO, new SubProgressMonitor(monitor, 10)); - project.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 10)); - - // it seems like doing this fails to properly rebuild the project. the Java builder - // running right after this builder will not see the gen folder, and will not be - // restarted after this build. Therefore in this particular case, we start another - // build asynchronously so that it's rebuilt after this build. - launchJob(new Job("rebuild") { - @Override - protected IStatus run(IProgressMonitor m) { - try { - project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, m); - return Status.OK_STATUS; - } catch (CoreException e) { - return e.getStatus(); - } - } - }); - - } - - // convert older projects which use bin as the eclipse output folder into projects - // using bin/classes - IFolder androidOutput = BaseProjectHelper.getAndroidOutputFolder(project); - IFolder javaOutput = BaseProjectHelper.getJavaOutputFolder(project); - if (androidOutput.exists() == false || javaOutput == null || - javaOutput.getParent().equals(androidOutput) == false) { - // get what we want as the new java output. - IFolder newJavaOutput = androidOutput.getFolder(SdkConstants.FD_CLASSES_OUTPUT); - - if (androidOutput.exists() == false) { - androidOutput.create(true /*force*/, true /*local*/, monitor); - } - - if (newJavaOutput.exists() == false) { - newJavaOutput.create(true /*force*/, true /*local*/, monitor); - } - - // set the java output to this project. - javaProject.setOutputLocation(newJavaOutput.getFullPath(), monitor); - - // need to do a full build. Can't build while we're already building, so launch a - // job to build it right after this build - launchJob(new Job("rebuild") { - @Override - protected IStatus run(IProgressMonitor jobMonitor) { - try { - project.build(IncrementalProjectBuilder.CLEAN_BUILD, jobMonitor); - return Status.OK_STATUS; - } catch (CoreException e) { - return e.getStatus(); - } - } - }); - } - - // check that we have bin/res/ - IFolder binResFolder = androidOutput.getFolder(SdkConstants.FD_RESOURCES); - if (binResFolder.exists() == false) { - binResFolder.create(true /* force */, true /* local */, - new SubProgressMonitor(monitor, 10)); - project.refreshLocal(IResource.DEPTH_ONE, new SubProgressMonitor(monitor, 10)); - } - - // Check the preference to be sure we are supposed to refresh - // the folders. - if (AdtPrefs.getPrefs().getBuildForceResResfresh()) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, Messages.Refreshing_Res); - - // refresh the res folder. - IFolder resFolder = project.getFolder(AdtConstants.WS_RESOURCES); - resFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); - - // Also refresh the assets folder to make sure the ApkBuilder - // will now it's changed and will force a new resource packaging. - IFolder assetsFolder = project.getFolder(AdtConstants.WS_ASSETS); - assetsFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); - } - - return null; - } -} |