diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders')
9 files changed, 0 insertions, 4019 deletions
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; - } -} |