diff options
author | Xavier Ducrohet <xav@android.com> | 2012-05-08 18:23:25 -0700 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2012-05-21 15:55:04 -0700 |
commit | d542e65fe2c7fc968c646f43c2d99d52ca3f380a (patch) | |
tree | 9c774d03d2c609495d567a0fa0fc787bbd323a83 | |
parent | a84497267ef0f8280fcd33f9fb5c848a34f6a609 (diff) | |
download | sdk-d542e65fe2c7fc968c646f43c2d99d52ca3f380a.tar.gz |
Manifest merge for ADT.
Change-Id: I635098594605af497a8b7d244e502385b8f34d1e
12 files changed, 310 insertions, 94 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/.classpath b/eclipse/plugins/com.android.ide.eclipse.adt/.classpath index 3a203c471..4c132edb6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/.classpath +++ b/eclipse/plugins/com.android.ide.eclipse.adt/.classpath @@ -1,7 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry excluding="Makefile|resources/" kind="src" path="src"/> - <classpathentry exported="true" kind="lib" path="libs/ant-glob.jar"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="lib" path="libs/kxml2-2.3.0.jar"/> @@ -15,6 +14,8 @@ <classpathentry kind="lib" path="libs/assetstudio.jar" sourcepath="/assetstudio"/> <classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/> <classpathentry combineaccessrules="false" kind="src" path="/ddmuilib"/> + <classpathentry exported="true" kind="lib" path="libs/ant-glob.jar"/> + <classpathentry exported="true" kind="lib" path="libs/manifmerger.jar" sourcepath="/ManifestMerger"/> <classpathentry kind="var" path="ANDROID_SRC/sdk/eclipse/plugins/com.android.ide.eclipse.adt/libs/propertysheet.jar" sourcepath="/ANDROID_SRC/external/eclipse-windowbuilder/propertysheet/src"/> <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/asm-tools/asm-4.0.jar" sourcepath="/ANDROID_SRC/prebuilts/tools/common/asm-tools/src.zip"/> <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/asm-tools/asm-tree-4.0.jar" sourcepath="/ANDROID_SRC/prebuilts/tools/common/asm-tools/src.zip"/> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF index 427b1762a..38d2885d1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF +++ b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF @@ -18,7 +18,8 @@ Bundle-ClassPath: ., libs/asm-tree-4.0.jar, libs/propertysheet.jar, libs/ant-glob.jar, - libs/swtmenubar.jar + libs/swtmenubar.jar, + libs/manifmerger.jar Bundle-Activator: com.android.ide.eclipse.adt.AdtPlugin Bundle-Vendor: The Android Open Source Project Require-Bundle: com.android.ide.eclipse.base, diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml index 6d609367f..5c3e9a0ea 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml @@ -58,6 +58,14 @@ <persistent value="true" /> </extension> <extension + id="com.android.ide.eclipse.adt.manifMergerProblem" + name="Android Manifest Merger Problem" + point="org.eclipse.core.resources.markers"> + <super type="org.eclipse.core.resources.problemmarker" /> + <super type="org.eclipse.core.resources.textmarker" /> + <persistent value="true" /> + </extension> + <extension id="com.android.ide.eclipse.adt.adtProblem" name="Android ADT Problem" point="org.eclipse.core.resources.markers"> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java index 904c4e6da..e5e84d90b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java @@ -237,6 +237,7 @@ public class AdtConstants { * from the {@link PreCompilerBuilder} */ public final static String MARKER_ANDROID = LEGACY_PLUGIN_ID + ".androidProblem"; //$NON-NLS-1$ + /** aapt marker error when running the package command, only to be used in * {@link PostCompilerBuilder} */ public final static String MARKER_AAPT_PACKAGE = LEGACY_PLUGIN_ID + ".aapt2Problem"; //$NON-NLS-1$ @@ -244,6 +245,9 @@ public class AdtConstants { /** final packaging error marker, only to be used in {@link PostCompilerBuilder} */ public final static String MARKER_PACKAGING = AdtPlugin.PLUGIN_ID + ".packagingProblem"; //$NON-NLS-1$ + /** manifest merger error, only to be used in {@link PreCompilerBuilder} */ + public final static String MARKER_MANIFMERGER = AdtPlugin.PLUGIN_ID + ".manifMergerProblem"; //$NON-NLS-1$ + /** Marker for lint errors */ public final static String MARKER_LINT = AdtPlugin.PLUGIN_ID + ".lintProblem"; //$NON-NLS-1$ 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 index 8b9492d02..1444f76a4 100644 --- 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 @@ -57,7 +57,8 @@ import javax.xml.parsers.SAXParserFactory; */ public abstract class BaseBuilder extends IncrementalProjectBuilder { - protected final static boolean DEBUG = false; + 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; 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 index 36d739746..fd963c02f 100644 --- 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 @@ -94,6 +94,23 @@ class ChangedFileSetHelper { } /** + * 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 a project's javac output. * @param project the project * @return a ChangedFileSet @@ -102,7 +119,7 @@ class ChangedFileSetHelper { // input pattern is based on the project's Java compiler's output folder String path = getRelativeJavaCOut(project); - ChangedFileSet set = new ChangedFileSet("bytecode", //$NON-NLS-1$ + ChangedFileSet set = new ChangedFileSet("compiledCode", //$NON-NLS-1$ path + "/**/*" + AdtConstants.DOT_CLASS); //$NON-NLS-1$ return set; @@ -136,9 +153,9 @@ class ChangedFileSetHelper { // input pattern is based on the project's Java compiler's output folder String path = getRelativeJavaCOut(project); - ChangedFileSet set = new ChangedFileSet("libResources", //$NON-NLS-1$ + ChangedFileSet set = new ChangedFileSet("classAndJars", //$NON-NLS-1$ path + "/**/*" + AdtConstants.DOT_CLASS, //$NON-NLS-1$ - SdkConstants.FD_NATIVE_LIBS + "*" + AdtConstants.DOT_JAR); //$NON-NLS-1$ + SdkConstants.FD_NATIVE_LIBS + "/*" + AdtConstants.DOT_JAR); //$NON-NLS-1$ // output file is based on the project's android output folder path = getRelativeAndroidOut(project); 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 index 7109eb85c..81fceb164 100644 --- 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 @@ -29,7 +29,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import java.util.ArrayList; -import java.util.HashMap; +import java.util.IdentityHashMap; import java.util.List; import java.util.Map; @@ -45,18 +45,26 @@ import java.util.Map; */ class PatternBasedDeltaVisitor implements IResourceDeltaVisitor { - private final boolean DEBUG_LOG = "1".equals( //$NON-NLS-1$ - System.getenv("ANDROID_VISITOR_DEBUG")); //$NON-NLS-1$ + 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 IProject mProject; + private final Map<ChangedFileSet, Boolean> mResults = + new IdentityHashMap<ChangedFileSet, Boolean>(); - private final Map<ChangedFileSet, Boolean> mResults = new HashMap<ChangedFileSet, Boolean>(); private final String mLogName; - PatternBasedDeltaVisitor(IProject project, String logName) { - mProject = project; + 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) { @@ -81,7 +89,7 @@ class PatternBasedDeltaVisitor implements IResourceDeltaVisitor { return BuildHelper.checkFolderForPackaging((IFolder)resource); } else if (resource.getType() == IResource.FILE) { - IPath path = resource.getFullPath().makeRelativeTo(mProject.getFullPath()); + IPath path = resource.getFullPath().makeRelativeTo(mDeltaProject.getFullPath()); // 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) { @@ -95,12 +103,13 @@ class PatternBasedDeltaVisitor implements IResourceDeltaVisitor { String cfs_logName = set.getLogName(); if (cfs_logName != null) { - AdtPlugin.log(IStatus.INFO, "%s (%s): %s", //$NON-NLS-1$ - mLogName, cfs_logName, + 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", //$NON-NLS-1$ - mLogName, resource.getFullPath().toString()); + AdtPlugin.log(IStatus.INFO, "%s (%s): %s", //$NON-NLS-1$ + mMainProject.getName(), mLogName, + resource.getFullPath().toString()); } } @@ -112,12 +121,12 @@ class PatternBasedDeltaVisitor implements IResourceDeltaVisitor { String cfs_logName = set.getLogName(); if (cfs_logName != null) { - AdtPlugin.log(IStatus.INFO, "%s (%s): REMOVED: %s", //$NON-NLS-1$ - mLogName, cfs_logName, + 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: REMOVED: %s", //$NON-NLS-1$ - mLogName, + AdtPlugin.log(IStatus.INFO, "%s (%s): %s", //$NON-NLS-1$ + mMainProject.getName(), mLogName, resource.getFullPath().toString()); } } 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 index 99f37ad4e..ea3a32515 100644 --- 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 @@ -134,8 +134,8 @@ public class PostCompilerBuilder extends BaseBuilder { // Get the project. IProject project = getProject(); - if (DEBUG) { - System.out.println("CLEAN(POST) " + project.getName()); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s CLEAN(POST)", project.getName()); } // Clear the project of the generic markers @@ -167,8 +167,8 @@ public class PostCompilerBuilder extends BaseBuilder { // get a project object IProject project = getProject(); - if (DEBUG) { - System.out.println("BUILD(POST) " + project.getName()); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s BUILD(POST)", project.getName()); } // Benchmarking start @@ -228,8 +228,8 @@ public class PostCompilerBuilder extends BaseBuilder { AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, Messages.Start_Full_Apk_Build); - if (DEBUG) { - System.out.println("\tfull build!"); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s full build!", project.getName()); } // Full build: we do all the steps. @@ -248,28 +248,31 @@ public class PostCompilerBuilder extends BaseBuilder { mConvertToDex = true; mBuildFinalPackage = true; } else { - PatternBasedDeltaVisitor dv = new PatternBasedDeltaVisitor(project, - project.getName()); - dv.addSet(ChangedFileSetHelper.MANIFEST); - ChangedFileSet resCFS = ChangedFileSetHelper.getResCfs(project); - dv.addSet(resCFS); + PatternBasedDeltaVisitor dv = new PatternBasedDeltaVisitor( + project, project, + "POST:Main"); - ChangedFileSet androidCodeCFS = ChangedFileSetHelper.getCodeCfs(project); - dv.addSet(androidCodeCFS); + ChangedFileSet manifestCfs = ChangedFileSetHelper.getMergedManifestCfs(project); + dv.addSet(manifestCfs); - ChangedFileSet javaResCFS = ChangedFileSetHelper.getJavaResCfs(project); - dv.addSet(javaResCFS); + 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(ChangedFileSetHelper.MANIFEST) || - dv.checkSet(resCFS); + mPackageResources |= dv.checkSet(manifestCfs) || dv.checkSet(resCfs); - mConvertToDex |= dv.checkSet(androidCodeCFS); + mConvertToDex |= dv.checkSet(androidCodeCfs); - mBuildFinalPackage |= dv.checkSet(javaResCFS) || + mBuildFinalPackage |= dv.checkSet(javaResCfs) || dv.checkSet(ChangedFileSetHelper.NATIVE_LIBS); } @@ -279,17 +282,18 @@ public class PostCompilerBuilder extends BaseBuilder { delta = getDelta(libProject); if (delta != null) { PatternBasedDeltaVisitor visitor = new PatternBasedDeltaVisitor( - libProject, project.getName()); + project, libProject, + "POST:Lib"); - ChangedFileSet libResCFS = ChangedFileSetHelper.getFullResCfs( + ChangedFileSet libResCfs = ChangedFileSetHelper.getFullResCfs( libProject); - visitor.addSet(libResCFS); + visitor.addSet(libResCfs); visitor.addSet(ChangedFileSetHelper.NATIVE_LIBS); // FIXME: add check on the library.jar? delta.accept(visitor); - mPackageResources |= visitor.checkSet(libResCFS); + mPackageResources |= visitor.checkSet(libResCfs); mBuildFinalPackage |= visitor.checkSet( ChangedFileSetHelper.NATIVE_LIBS); } @@ -303,19 +307,20 @@ public class PostCompilerBuilder extends BaseBuilder { delta = getDelta(referencedJavaProject.getProject()); if (delta != null) { PatternBasedDeltaVisitor visitor = new PatternBasedDeltaVisitor( - referencedJavaProject.getProject(), project.getName()); + project, referencedJavaProject.getProject(), + "POST:RefedProject"); - ChangedFileSet javaResCFS = ChangedFileSetHelper.getJavaResCfs(project); - visitor.addSet(javaResCFS); + ChangedFileSet javaResCfs = ChangedFileSetHelper.getJavaResCfs(project); + visitor.addSet(javaResCfs); - ChangedFileSet bytecodeCFS = ChangedFileSetHelper.getByteCodeCfs(project); - visitor.addSet(bytecodeCFS); + ChangedFileSet bytecodeCfs = ChangedFileSetHelper.getByteCodeCfs(project); + visitor.addSet(bytecodeCfs); delta.accept(visitor); // save the state - mConvertToDex |= visitor.checkSet(bytecodeCFS); - mBuildFinalPackage |= visitor.checkSet(javaResCFS); + mConvertToDex |= visitor.checkSet(bytecodeCfs); + mBuildFinalPackage |= visitor.checkSet(javaResCfs); } } } @@ -350,8 +355,8 @@ public class PostCompilerBuilder extends BaseBuilder { // also update the crunch cache always since aapt does it smartly only // on the files that need it. - if (DEBUG) { - System.out.println("\trunning crunch!"); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s running crunch!", project.getName()); } BuildHelper helper = new BuildHelper(project, mOutStream, mErrStream, @@ -365,8 +370,8 @@ public class PostCompilerBuilder extends BaseBuilder { if (mConvertToDex) { // in this case this means some class files changed and // we need to update the jar file. - if (DEBUG) { - System.out.println("\tupdating jar!"); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s updating jar!", project.getName()); } // resource to the AndroidManifest.xml file @@ -473,8 +478,17 @@ public class PostCompilerBuilder extends BaseBuilder { 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 = project.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML); + IFile manifestFile = androidOutputFolder.getFile( + SdkConstants.FN_ANDROID_MANIFEST_XML); if (manifestFile == null || manifestFile.exists() == false) { // mark project and exit @@ -484,14 +498,6 @@ public class PostCompilerBuilder extends BaseBuilder { return allRefProjects; } - IPath androidBinLocation = androidOutputFolder.getLocation(); - if (androidBinLocation == null) { - markProject(AdtConstants.MARKER_PACKAGING, Messages.Output_Missing, - IMarker.SEVERITY_ERROR); - return allRefProjects; - } - String osAndroidBinPath = androidBinLocation.toOSString(); - // Remove the old .apk. // This make sure that if the apk is corrupted, then dx (which would attempt // to open it), will not fail. @@ -507,8 +513,8 @@ public class PostCompilerBuilder extends BaseBuilder { if (mPackageResources) { // also update the crunch cache always since aapt does it smartly only // on the files that need it. - if (DEBUG) { - System.out.println("\trunning crunch!"); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s running crunch!", project.getName()); } if (updateCrunchCache(project, helper) == false) { return allRefProjects; @@ -517,8 +523,8 @@ public class PostCompilerBuilder extends BaseBuilder { // refresh recursively bin/res folder resOutputFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); - if (DEBUG) { - System.out.println("\tpackaging resources!"); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s packaging resources!", project.getName()); } // remove some aapt_package only markers. removeMarkersFromContainer(project, AdtConstants.MARKER_AAPT_PACKAGE); @@ -562,8 +568,8 @@ public class PostCompilerBuilder extends BaseBuilder { // then we check if we need to package the .class into classes.dex if (mConvertToDex) { - if (DEBUG) { - System.out.println("\trunning dex!"); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s running dex!", project.getName()); } try { Collection<String> dxInputPaths = helper.getCompiledCodePaths(); @@ -600,8 +606,8 @@ public class PostCompilerBuilder extends BaseBuilder { // This is the default package with all the resources. try { - if (DEBUG) { - System.out.println("\tmaking final package!"); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s making final package!", project.getName()); } helper.finalDebugPackage( osAndroidBinPath + File.separator + AdtConstants.FN_RESOURCES_AP_, 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 index 232f40f52..0347af66e 100644 --- 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 @@ -40,10 +40,13 @@ 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.sdklib.AndroidVersion; import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.ISdkLog; import com.android.sdklib.SdkConstants; import com.android.sdklib.internal.build.BuildConfigGenerator; +import com.android.sdklib.io.FileOp; import com.android.sdklib.xml.AndroidManifest; import com.android.sdklib.xml.ManifestData; @@ -56,6 +59,7 @@ 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.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IJavaProject; @@ -90,19 +94,26 @@ public class PreCompilerBuilder extends BaseBuilder { */ 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$ - /** - * Resource Compile flag. This flag is reset to false after each successful compilation, and - * stored in the project persistent properties. This allows the builder to remember its state - * when the project is closed/opened. - */ + 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; private final List<SourceProcessor> mProcessors = new ArrayList<SourceProcessor>(2); @@ -219,8 +230,8 @@ public class PreCompilerBuilder extends BaseBuilder { // get a project object IProject project = getProject(); - if (DEBUG) { - System.out.println("BUILD(PRE) " + project.getName()); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s BUILD(PRE)", project.getName()); } // For the PreCompiler, only the library projects are considered Referenced projects, @@ -254,6 +265,8 @@ public class PreCompilerBuilder extends BaseBuilder { // now we need to get the classpath list List<IPath> sourceFolderPathList = BaseProjectHelper.getSourceClasspaths(javaProject); + IFolder androidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(project); + PreCompilerDeltaVisitor dv = null; String javaPackage = null; String minSdkVersion = null; @@ -262,13 +275,14 @@ public class PreCompilerBuilder extends BaseBuilder { AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, Messages.Start_Full_Pre_Compiler); - if (DEBUG) { - System.out.println("\tfull build!"); + 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; @@ -301,13 +315,15 @@ public class PreCompilerBuilder extends BaseBuilder { // 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(); ProjectResources projectResources = resManager.getProjectResources(project); if (ResourceManager.isAutoBuilding()) { - IdeScanningContext context = new IdeScanningContext(projectResources, project); + IdeScanningContext context = new IdeScanningContext(projectResources, + project); resManager.processDelta(delta, context); @@ -342,7 +358,31 @@ public class PreCompilerBuilder extends BaseBuilder { // 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 (mMustMergeManifest == false && 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); + + delta.accept(visitor); + + mMustMergeManifest |= visitor.checkSet(ChangedFileSetHelper.MANIFEST); + + // no need to test others. + if (mMustMergeManifest) { + break; + } + } + } + } + // store the build status in the persistent storage + saveProjectBooleanProperty(PROPERTY_MERGE_MANIFEST, mMustMergeManifest); saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, mMustCompileResources); saveProjectBooleanProperty(PROPERTY_COMPILE_BUILDCONFIG, mMustCreateBuildConfig); @@ -354,7 +394,6 @@ public class PreCompilerBuilder extends BaseBuilder { return result; } - // get the manifest file IFile manifestFile = ProjectHelper.getManifest(project); @@ -549,12 +588,14 @@ public class PreCompilerBuilder extends BaseBuilder { // force a clean doClean(project, monitor); + mMustMergeManifest = true; mMustCompileResources = true; mMustCreateBuildConfig = true; for (SourceProcessor processor : mProcessors) { processor.prepareFullBuild(project); } + saveProjectBooleanProperty(PROPERTY_MERGE_MANIFEST, mMustMergeManifest); saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, mMustCompileResources); saveProjectBooleanProperty(PROPERTY_COMPILE_BUILDCONFIG, mMustCreateBuildConfig); } @@ -566,6 +607,19 @@ public class PreCompilerBuilder extends BaseBuilder { 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; + } + } + // run the source processors int processorStatus = SourceProcessor.COMPILE_STATUS_NONE; for (SourceProcessor processor : mProcessors) { @@ -591,8 +645,8 @@ public class PreCompilerBuilder extends BaseBuilder { // generate resources. boolean compiledTheResources = mMustCompileResources; if (mMustCompileResources) { - if (DEBUG) { - System.out.println("\tcompiling resources!"); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s compiling resources!", project.getName()); } handleResources(project, javaPackage, projectTarget, manifestFile, libProjects, projectState.isLibrary()); @@ -618,8 +672,8 @@ public class PreCompilerBuilder extends BaseBuilder { protected void clean(IProgressMonitor monitor) throws CoreException { super.clean(monitor); - if (DEBUG) { - System.out.println("CLEAN(PRE) " + getProject().getName()); + if (DEBUG_LOG) { + AdtPlugin.log(IStatus.INFO, "%s CLEAN(PRE)", getProject().getName()); } doClean(getProject(), monitor); @@ -646,6 +700,7 @@ public class PreCompilerBuilder extends BaseBuilder { 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 @@ -667,6 +722,7 @@ public class PreCompilerBuilder extends BaseBuilder { 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); @@ -715,6 +771,10 @@ public class PreCompilerBuilder extends BaseBuilder { } 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(); @@ -725,6 +785,90 @@ public class PreCompilerBuilder extends BaseBuilder { } } + 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>(); + + ManifestMerger merger = new ManifestMerger(new ISdkLog() { + + @Override + public void warning(String warningFormat, Object... args) { + AdtPlugin.printToConsole(getProject(), String.format(warningFormat, args)); + } + + @Override + public void printf(String msgFormat, Object... args) { + AdtPlugin.printToConsole(getProject(), String.format(msgFormat, args)); + } + + @Override + public void error(Throwable t, String errorFormat, Object... args) { + errors.add(String.format(errorFormat, args)); + } + }); + + 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) == 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. 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 index 1c9692433..c8f448cc5 100644 --- 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 @@ -24,6 +24,7 @@ import com.android.ide.eclipse.adt.internal.build.SourceProcessor; 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.android.sdklib.SdkConstants; import com.android.sdklib.xml.ManifestData; @@ -58,9 +59,11 @@ import java.util.List; 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.xml, Manifest.java, or R.java. All other file changes + * files is Manifest.java, or R.java. All other file changes * will be taken care of by ResourceManager. */ private boolean mCompileResources = false; @@ -94,7 +97,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDelta new ArrayList<SourceChangeHandler>(); private final IWorkspaceRoot mRoot; - + private IFolder mAndroidOutputFolder; public PreCompilerDeltaVisitor(BaseBuilder builder, List<IPath> sourceFolders, List<SourceProcessor> processors) { @@ -106,6 +109,8 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDelta SourceChangeHandler handler = processor.getChangeHandler(); mSourceChangeHandlers.add(handler); } + + mAndroidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(builder.getProject()); } /** @@ -113,7 +118,11 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDelta * @return true if any of Manifest.xml, Manifest.java, or R.java have been modified */ public boolean getCompileResources() { - return mCompileResources; + return mCompileResources || mChangedManifest; + } + + public boolean hasManifestChanged() { + return mChangedManifest; } /** @@ -220,7 +229,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDelta mCheckedManifestXml = true; } - mCompileResources = true; + mChangedManifest = true; // we don't want to go to the children, not like they are // any for this resource anyway. @@ -356,6 +365,12 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements IResourceDelta // 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 diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/ProjectState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/ProjectState.java index 84ee34169..64053adcf 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/ProjectState.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/ProjectState.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.sdk; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.internal.project.ProjectProperties; @@ -206,6 +208,14 @@ public final class ProjectState { return mProperties; } + public @Nullable String getProperty(@NonNull String name) { + if (mProperties != null) { + return mProperties.getProperty(name); + } + + return null; + } + public void setTarget(IAndroidTarget target) { mTarget = target; } diff --git a/eclipse/scripts/create_all_symlinks.sh b/eclipse/scripts/create_all_symlinks.sh index 68481c1b4..2ec32ebab 100755 --- a/eclipse/scripts/create_all_symlinks.sh +++ b/eclipse/scripts/create_all_symlinks.sh @@ -124,7 +124,7 @@ CP_FILES="$CP_FILES @:$BASE_PLUGIN_DEST $BASE_PLUGIN_LIBS $BASE_PLUGIN_PREBUILTS ### ADT ### ADT_DEST="sdk/eclipse/plugins/com.android.ide.eclipse.adt/libs" -ADT_LIBS="ant-glob assetstudio ide_common layoutlib_api lint_api lint_checks ninepatch propertysheet rule_api sdkuilib swtmenubar" +ADT_LIBS="ant-glob assetstudio ide_common layoutlib_api lint_api lint_checks ninepatch propertysheet rule_api sdkuilib swtmenubar manifmerger" ADT_PREBUILTS="\ prebuilts/misc/common/kxml2/kxml2-2.3.0.jar \ prebuilts/tools/common/asm-tools/asm-4.0.jar \ |