diff options
author | Xavier Ducrohet <xav@android.com> | 2012-03-07 10:36:30 -0800 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2012-03-07 15:11:19 -0800 |
commit | bcf44e9429811b3e1f97d21ea92816957bce2601 (patch) | |
tree | 9b6a7502b6901b193b4fedd99ca6e541bd6cd4f3 /eclipse | |
parent | ec60a783e8adca69f43e4a313f207fa919a7c06f (diff) | |
download | sdk-bcf44e9429811b3e1f97d21ea92816957bce2601.zip sdk-bcf44e9429811b3e1f97d21ea92816957bce2601.tar.gz sdk-bcf44e9429811b3e1f97d21ea92816957bce2601.tar.bz2 |
Figure out DX input path based on actual classpath.
This synchronizes the previous work on figuring out the actual
classpath for the library container and reuse this to figure out
what goes into dex.
Also use the classpath to figure out the java resources that should
be packaged in the apk. Additionally, only add java resources by
reading the output folder instead of the source folders as this
ensure that exclusion patterns are respected.
Change-Id: Iac742f4bdefab370ec3cf7d955736e84d58ead9c
Diffstat (limited to 'eclipse')
5 files changed, 166 insertions, 298 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java index e915544..ad4b787 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java @@ -21,8 +21,6 @@ import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AndroidPrintStream; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.IAndroidTarget; @@ -33,11 +31,9 @@ import com.android.sdklib.build.ApkBuilder.JarStatus; import com.android.sdklib.build.ApkBuilder.SigningInfo; import com.android.sdklib.build.ApkCreationException; import com.android.sdklib.build.DuplicateFileException; -import com.android.sdklib.build.IArchiveBuilder; import com.android.sdklib.build.SealedApkException; import com.android.sdklib.internal.build.DebugKeyProvider; import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException; -import com.android.sdklib.internal.build.SignedJarBuilder; import com.android.sdklib.util.GrabProcessOutput; import com.android.sdklib.util.GrabProcessOutput.IProcessOutput; import com.android.sdklib.util.GrabProcessOutput.Wait; @@ -46,9 +42,6 @@ import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceProxy; -import org.eclipse.core.resources.IResourceProxyVisitor; -import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; @@ -69,8 +62,11 @@ import java.io.PrintStream; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TreeMap; /** @@ -108,6 +104,8 @@ public class BuildHelper { private final boolean mVerbose; private final boolean mDebugMode; + private final Set<String> mCompiledCodePaths = new HashSet<String>(); + public static final boolean BENCHMARK_FLAG = false; public static long sStartOverallTime = 0; public static long sStartJavaCTime = 0; @@ -128,14 +126,18 @@ public class BuildHelper { * @param errStream * @param debugMode whether this is a debug build * @param verbose + * @throws CoreException */ public BuildHelper(IProject project, AndroidPrintStream outStream, - AndroidPrintStream errStream, boolean debugMode, boolean verbose) { + AndroidPrintStream errStream, boolean debugMode, boolean verbose, + ResourceMarker resMarker) throws CoreException { mProject = project; mOutStream = outStream; mErrStream = errStream; mDebugMode = debugMode; mVerbose = verbose; + + gatherPaths(resMarker); } public void updateCrunchCache() throws AaptExecException, AaptResultException { @@ -169,11 +171,6 @@ public class BuildHelper { } } - public static void writeResources(IArchiveBuilder builder, IJavaProject javaProject) - throws DuplicateFileException, ApkCreationException, SealedApkException, CoreException { - writeStandardResources(builder, javaProject, null); - } - /** * Packages the resources of the projet into a .ap_ file. * @param manifestFile the manifest of the project. @@ -365,19 +362,16 @@ public class BuildHelper { mVerbose ? mOutStream: null); apkBuilder.setDebugMode(mDebugMode); - // Now we write the standard resources from the project and the referenced projects. - writeStandardResources(apkBuilder, javaProject, referencedJavaProjects); - - // Now we write the standard resources from the external jars - for (String libraryOsPath : getExternalDependencies(resMarker)) { - File libFile = new File(libraryOsPath); - if (libFile.isFile()) { - JarStatus jarStatus = apkBuilder.addResourcesFromJar(new File(libraryOsPath)); + // Now we write the standard resources from all the output paths. + for (String path : mCompiledCodePaths) { + File file = new File(path); + if (file.isFile()) { + JarStatus jarStatus = apkBuilder.addResourcesFromJar(file); // check if we found native libraries in the external library. This // constitutes an error or warning depending on if they are in lib/ if (jarStatus.getNativeLibs().size() > 0) { - String libName = new File(libraryOsPath).getName(); + String libName = file.getName(); String msg = String.format( "Native libraries detected in '%1$s'. See console for more information.", @@ -418,11 +412,11 @@ public class BuildHelper { } } } - } else if (libFile.isDirectory()) { + } else if (file.isDirectory()) { // this is technically not a source folder (class folder instead) but since we // only care about Java resources (ie non class/java files) this will do the // same - apkBuilder.addSourceFolder(libFile); + apkBuilder.addSourceFolder(file); } } @@ -453,66 +447,11 @@ public class BuildHelper { } } - /** - * Return a list of the project output for compiled Java code. - * @return - * @throws CoreException - */ - public String[] getProjectJavaOutputs() throws CoreException { - IFolder outputFolder = BaseProjectHelper.getJavaOutputFolder(mProject); - - // get the list of referenced projects output to add - List<IProject> javaProjects = ProjectHelper.getReferencedProjects(mProject); - List<IJavaProject> referencedJavaProjects = BuildHelper.getJavaProjects(javaProjects); - - // get the project output, and since it's a new list object, just add the outputFolder - // of the project directly to it. - List<String> projectOutputs = getProjectJavaOutputs(referencedJavaProjects); - - projectOutputs.add(0, outputFolder.getLocation().toOSString()); - - return projectOutputs.toArray(new String[projectOutputs.size()]); - } - - /** - * Returns an array for all the compiled code for the project. This can include the - * code compiled by Eclipse for the main project and dependencies (Java only projects), as well - * as external jars used by the project or its library. - * - * This array of paths is compatible with the input for dx and can be passed as is to - * {@link #executeDx(IJavaProject, String[], String)}. - * - * @param resMarker - * @return a array (never empty) containing paths to compiled code. - * @throws CoreException - */ - public String[] getCompiledCodePaths(boolean includeProjectOutputs, ResourceMarker resMarker) - throws CoreException { - - // get the list of libraries to include with the source code - String[] libraries = getExternalDependencies(resMarker); - - int startIndex = 0; - - String[] compiledPaths; - - if (includeProjectOutputs) { - String[] projectOutputs = getProjectJavaOutputs(); - - compiledPaths = new String[libraries.length + projectOutputs.length]; - - System.arraycopy(projectOutputs, 0, compiledPaths, 0, projectOutputs.length); - startIndex = projectOutputs.length; - } else { - compiledPaths = new String[libraries.length]; - } - - System.arraycopy(libraries, 0, compiledPaths, startIndex, libraries.length); - - return compiledPaths; + public Collection<String> getCompiledCodePaths() { + return mCompiledCodePaths; } - public void runProguard(List<File> proguardConfigs, File inputJar, String[] jarFiles, + public void runProguard(List<File> proguardConfigs, File inputJar, Collection<String> jarFiles, File obfuscatedJar, File logOutput) throws ProguardResultException, ProguardExecException, IOException { IAndroidTarget target = Sdk.getCurrent().getTarget(mProject); @@ -723,13 +662,14 @@ public class BuildHelper { /** * Execute the Dx tool for dalvik code conversion. * @param javaProject The java project - * @param inputPath the path to the main input of dex + * @param inputPaths the input paths for DX * @param osOutFilePath the path of the dex file to create. * * @throws CoreException * @throws DexException */ - public void executeDx(IJavaProject javaProject, String[] inputPaths, String osOutFilePath) + public void executeDx(IJavaProject javaProject, Collection<String> inputPaths, + String osOutFilePath) throws CoreException, DexException { // get the dex wrapper @@ -917,153 +857,94 @@ public class BuildHelper { } /** - * Writes the standard resources of a project and its referenced projects - * into a {@link SignedJarBuilder}. - * Standard resources are non java/aidl files placed in the java package folders. - * @param builder the archive builder. - * @param javaProject the javaProject object. - * @param referencedJavaProjects the java projects that this project references. - * @throws ApkCreationException if an error occurred - * @throws SealedApkException if the APK is already sealed. - * @throws DuplicateFileException if a file conflicts with another already added to the APK - * at the same location inside the APK archive. - * @throws CoreException - */ - private static void writeStandardResources(IArchiveBuilder builder, IJavaProject javaProject, - List<IJavaProject> referencedJavaProjects) - throws DuplicateFileException, ApkCreationException, SealedApkException, - CoreException { - IWorkspace ws = ResourcesPlugin.getWorkspace(); - IWorkspaceRoot wsRoot = ws.getRoot(); - - writeStandardProjectResources(builder, javaProject, wsRoot); - - if (referencedJavaProjects != null) { - for (IJavaProject referencedJavaProject : referencedJavaProjects) { - // only include output from non android referenced project - // (This is to handle the case of reference Android projects in the context of - // instrumentation projects that need to reference the projects to be tested). - if (referencedJavaProject.getProject().hasNature( - AdtConstants.NATURE_DEFAULT) == false) { - writeStandardProjectResources(builder, referencedJavaProject, wsRoot); - } - } - } - } - - /** - * Writes the standard resources of a {@link IJavaProject} into a {@link SignedJarBuilder}. - * Standard resources are non java/aidl files placed in the java package folders. - * @param jarBuilder the {@link ApkBuilder}. - * @param javaProject the javaProject object. - * @param wsRoot the {@link IWorkspaceRoot}. - * @throws ApkCreationException if an error occurred - * @throws SealedApkException if the APK is already sealed. - * @throws DuplicateFileException if a file conflicts with another already added to the APK - * at the same location inside the APK archive. + * Computes all the project output and dependencies that must go into building the apk. + * + * @param resMarker * @throws CoreException */ - private static void writeStandardProjectResources(IArchiveBuilder builder, - IJavaProject javaProject, IWorkspaceRoot wsRoot) - throws DuplicateFileException, ApkCreationException, SealedApkException, CoreException { - // get the source pathes - List<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(javaProject); - - // loop on them and then recursively go through the content looking for matching files. - for (IPath sourcePath : sourceFolders) { - IResource sourceResource = wsRoot.findMember(sourcePath); - if (sourceResource != null && sourceResource.getType() == IResource.FOLDER) { - writeFolderResources(builder, javaProject, (IFolder) sourceResource); - } - } - } - - private static void writeFolderResources(IArchiveBuilder builder, - final IJavaProject javaProject, IFolder root) throws CoreException, - ApkCreationException, SealedApkException, DuplicateFileException { - final List<IPath> pathsToPackage = new ArrayList<IPath>(); - root.accept(new IResourceProxyVisitor() { - @Override - public boolean visit(IResourceProxy proxy) throws CoreException { - if (proxy.getType() == IResource.FOLDER) { - // If this folder isn't wanted, don't traverse into it. - return ApkBuilder.checkFolderForPackaging(proxy.getName()); - } - // If it's not a folder, it must be a file. We won't see any other resource type. - if (!ApkBuilder.checkFileForPackaging(proxy.getName())) { - return true; - } - IResource res = proxy.requestResource(); - if (!javaProject.isOnClasspath(res)) { - return true; - } - // Just record that we need to package this. Packaging here throws - // inappropriate checked exceptions. - IPath location = res.getLocation(); - pathsToPackage.add(location); - return true; - } - }, 0); - IPath rootLocation = root.getLocation(); - for (IPath path : pathsToPackage) { - IPath archivePath = path.makeRelativeTo(rootLocation); - builder.addFile(path.toFile(), archivePath.toString()); - } - } + private void gatherPaths(ResourceMarker resMarker) + throws CoreException { + IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - /** - * Returns an array of external dependencies used the project. This can be paths to jar files - * or to source folders. - * - * @param resMarker if non null, used to put Resource marker on problem files. - * @return an array of OS-specific absolute file paths - */ - private final String[] getExternalDependencies(ResourceMarker resMarker) { - // get a java project from it + // get a java project for the project. IJavaProject javaProject = JavaCore.create(mProject); - IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - ArrayList<String> oslibraryList = new ArrayList<String>(); + // get the output of the main project + IPath path = javaProject.getOutputLocation(); + IResource outputResource = wsRoot.findMember(path); + if (outputResource != null && outputResource.getType() == IResource.FOLDER) { + mCompiledCodePaths.add(outputResource.getLocation().toOSString()); + } // we could use IJavaProject.getResolvedClasspath directly, but we actually // want to see the containers themselves. IClasspathEntry[] classpaths = javaProject.readRawClasspath(); if (classpaths != null) { for (IClasspathEntry e : classpaths) { - // if this is a classpath variable reference, we resolve it. - if (e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - e = JavaCore.getResolvedClasspathEntry(e); + // ignore non exported entries, unless it's the LIBRARIES container, + // in which case we always want it (there may be some older projects that + // have it as non exported). + if (e.isExported() || + (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER && + e.getPath().toString().equals(AdtConstants.CONTAINER_LIBRARIES))) { + handleCPE(e, javaProject, wsRoot, resMarker); } + } + } + } - if (e.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { - handleClasspathEntry(e, wsRoot, oslibraryList, resMarker); - } else if (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { - // get the container - try { - IClasspathContainer container = JavaCore.getClasspathContainer( - e.getPath(), javaProject); - // ignore the system and default_system types as they represent - // libraries that are part of the runtime. - if (container.getKind() == IClasspathContainer.K_APPLICATION) { - IClasspathEntry[] entries = container.getClasspathEntries(); - for (IClasspathEntry entry : entries) { - handleClasspathEntry(entry, wsRoot, oslibraryList, resMarker); - } - } - } catch (JavaModelException jme) { - // can't resolve the container? ignore it. - AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", e.getPath()); + private void handleCPE(IClasspathEntry entry, IJavaProject javaProject, + IWorkspaceRoot wsRoot, ResourceMarker resMarker) { + + // if this is a classpath variable reference, we resolve it. + if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { + entry = JavaCore.getResolvedClasspathEntry(entry); + } + + if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { + IProject refProject = wsRoot.getProject(entry.getPath().lastSegment()); + try { + // ignore if it's an Android project, or if it's not a Java Project + if (refProject.hasNature(JavaCore.NATURE_ID) && + refProject.hasNature(AdtConstants.NATURE_DEFAULT) == false) { + IJavaProject refJavaProject = JavaCore.create(refProject); + + // get the output folder + IPath path = refJavaProject.getOutputLocation(); + IResource outputResource = wsRoot.findMember(path); + if (outputResource != null && outputResource.getType() == IResource.FOLDER) { + mCompiledCodePaths.add(outputResource.getLocation().toOSString()); } } + } catch (CoreException exception) { + // can't query the project nature? ignore } - } - return oslibraryList.toArray(new String[oslibraryList.size()]); + } else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { + handleClasspathLibrary(entry, wsRoot, resMarker); + } else if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { + // get the container + try { + IClasspathContainer container = JavaCore.getClasspathContainer( + entry.getPath(), javaProject); + // ignore the system and default_system types as they represent + // libraries that are part of the runtime. + if (container.getKind() == IClasspathContainer.K_APPLICATION) { + IClasspathEntry[] entries = container.getClasspathEntries(); + for (IClasspathEntry cpe : entries) { + handleCPE(cpe, javaProject, wsRoot, resMarker); + } + } + } catch (JavaModelException jme) { + // can't resolve the container? ignore it. + AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", entry.getPath()); + } + } } - private void handleClasspathEntry(IClasspathEntry e, IWorkspaceRoot wsRoot, - ArrayList<String> oslibraryList, ResourceMarker resMarker) { + private void handleClasspathLibrary(IClasspathEntry e, IWorkspaceRoot wsRoot, + ResourceMarker resMarker) { // get the IPath IPath path = e.getPath(); @@ -1077,7 +958,7 @@ public class BuildHelper { // case of a jar file (which could be relative to the workspace or a full path) if (resource != null && resource.exists() && resource.getType() == IResource.FILE) { - oslibraryList.add(resource.getLocation().toOSString()); + mCompiledCodePaths.add(resource.getLocation().toOSString()); } else { // if the jar path doesn't match a workspace resource, // then we get an OSString and check if this links to a valid file. @@ -1085,7 +966,7 @@ public class BuildHelper { File f = new File(osFullPath); if (f.isFile()) { - oslibraryList.add(osFullPath); + mCompiledCodePaths.add(osFullPath); } else { String message = String.format( Messages.Couldnt_Locate_s_Error, path); @@ -1102,7 +983,7 @@ public class BuildHelper { // this can be the case for a class folder. if (resource != null && resource.exists() && resource.getType() == IResource.FOLDER) { - oslibraryList.add(resource.getLocation().toOSString()); + mCompiledCodePaths.add(resource.getLocation().toOSString()); } else { // if the path doesn't match a workspace resource, // then we get an OSString and check if this links to a valid folder. @@ -1110,50 +991,10 @@ public class BuildHelper { File f = new File(osFullPath); if (f.isDirectory()) { - oslibraryList.add(osFullPath); - } - } - } - } - - /** - * Returns the list of the output folders for the specified {@link IJavaProject} objects, if - * they are Android projects. - * - * @param referencedJavaProjects the java projects. - * @return a new list object containing the output folder paths. - * @throws CoreException - */ - private List<String> getProjectJavaOutputs(List<IJavaProject> referencedJavaProjects) - throws CoreException { - ArrayList<String> list = new ArrayList<String>(); - - IWorkspace ws = ResourcesPlugin.getWorkspace(); - IWorkspaceRoot wsRoot = ws.getRoot(); - - for (IJavaProject javaProject : referencedJavaProjects) { - // only include output from non android referenced project - // (This is to handle the case of reference Android projects in the context of - // instrumentation projects that need to reference the projects to be tested). - if (javaProject.getProject().hasNature(AdtConstants.NATURE_DEFAULT) == false) { - // get the output folder - IPath path = null; - try { - path = javaProject.getOutputLocation(); - } catch (JavaModelException e) { - continue; - } - - IResource outputResource = wsRoot.findMember(path); - if (outputResource != null && outputResource.getType() == IResource.FOLDER) { - String outputOsPath = outputResource.getLocation().toOSString(); - - list.add(outputOsPath); + mCompiledCodePaths.add(osFullPath); } } } - - return list; } /** diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java index e03a150..015d230 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java @@ -30,6 +30,7 @@ import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.util.Collection; /** * Wrapper to access dx.jar through reflection. @@ -144,7 +145,7 @@ public final class DexWrapper { * @return the integer return code of com.android.dx.command.dexer.Main.run() * @throws CoreException */ - public synchronized int run(String osOutFilePath, String[] osFilenames, + public synchronized int run(String osOutFilePath, Collection<String> osFilenames, boolean verbose, PrintStream outStream, PrintStream errStream) throws CoreException { assert mRunMethod != null; @@ -171,7 +172,7 @@ public final class DexWrapper { // create the Arguments object. Object args = mArgConstructor.newInstance(); mArgOutName.set(args, osOutFilePath); - mArgFileNames.set(args, osFilenames); + mArgFileNames.set(args, osFilenames.toArray(new String[osFilenames.size()])); mArgJarOutput.set(args, false); mArgVerbose.set(args, verbose); 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 6c4eca4..1c4f3f3 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 @@ -38,6 +38,7 @@ 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.SdkConstants; +import com.android.sdklib.build.ApkBuilder; import com.android.sdklib.build.ApkCreationException; import com.android.sdklib.build.DuplicateFileException; import com.android.sdklib.build.IArchiveBuilder; @@ -68,6 +69,7 @@ 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; @@ -427,7 +429,8 @@ public class PostCompilerBuilder extends BaseBuilder { BuildHelper helper = new BuildHelper(project, mOutStream, mErrStream, true /*debugMode*/, - AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE); + AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE, + mResourceMarker); updateCrunchCache(project, helper); // refresh recursively bin/res folder @@ -542,7 +545,8 @@ public class PostCompilerBuilder extends BaseBuilder { BuildHelper helper = new BuildHelper(project, mOutStream, mErrStream, true /*debugMode*/, - AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE); + AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE, + mResourceMarker); // resource to the AndroidManifest.xml file IFile manifestFile = project.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML); @@ -637,8 +641,7 @@ public class PostCompilerBuilder extends BaseBuilder { System.out.println("\trunning dex!"); } try { - String[] dxInputPaths = helper.getCompiledCodePaths( - true /*includeProjectOutputs*/, mResourceMarker); + Collection<String> dxInputPaths = helper.getCompiledCodePaths(); helper.executeDx(javaProject, dxInputPaths, classesDexPath); } catch (DexException e) { @@ -920,8 +923,8 @@ public class PostCompilerBuilder extends BaseBuilder { // write the class files writeClassFilesIntoJar(jarBuilder, javaOutputFolder, javaOutputFolder); - // now write the standard Java resources - BuildHelper.writeResources(jarBuilder, JavaCore.create(project)); + // 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) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java index 93fe43d..c95569b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java @@ -62,6 +62,8 @@ import java.io.OutputStream; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; @@ -122,7 +124,8 @@ public final class ExportHelper { BuildHelper helper = new BuildHelper(project, fakeStream, fakeStream, - debugMode, false /*verbose*/); + debugMode, false /*verbose*/, + null /*resourceMarker*/); // get the list of library projects ProjectState projectState = Sdk.getProjectState(project); @@ -200,44 +203,46 @@ public final class ExportHelper { } } - String[] dxInput; + Collection<String> dxInput; if (runProguard) { - // the output of the main project (and any java-only project dependency) - String[] projectOutputs = helper.getProjectJavaOutputs(); + // get all the compiled code paths. This will contain both project output + // folder and jar files. + Collection<String> paths = helper.getCompiledCodePaths(); - // create a jar from the output of these projects + // create a jar file containing all the project output (as proguard cannot + // process folders of .class files). File inputJar = File.createTempFile(TEMP_PREFIX, AdtConstants.DOT_JAR); inputJar.deleteOnExit(); - JarOutputStream jos = new JarOutputStream(new FileOutputStream(inputJar)); - for (String po : projectOutputs) { - File root = new File(po); - if (root.exists()) { + + // a list of the other paths (jar files.) + List<String> jars = new ArrayList<String>(); + + for (String path : paths) { + File root = new File(path); + if (root.isDirectory()) { addFileToJar(jos, root, root); + } else if (root.isFile()) { + jars.add(path); } } jos.close(); - // get the other jar files - String[] jarFiles = helper.getCompiledCodePaths(false /*includeProjectOutputs*/, - null /*resourceMarker*/); - // destination file for proguard File obfuscatedJar = File.createTempFile(TEMP_PREFIX, AdtConstants.DOT_JAR); obfuscatedJar.deleteOnExit(); // run proguard - helper.runProguard(proguardConfigFiles, inputJar, jarFiles, obfuscatedJar, + helper.runProguard(proguardConfigFiles, inputJar, jars, obfuscatedJar, new File(project.getLocation().toFile(), SdkConstants.FD_PROGUARD)); // dx input is proguard's output - dxInput = new String[] { obfuscatedJar.getAbsolutePath() }; + dxInput = Collections.singletonList(obfuscatedJar.getAbsolutePath()); } else { // no proguard, simply get all the compiled code path: project output(s) + // jar file(s) - dxInput = helper.getCompiledCodePaths(true /*includeProjectOutputs*/, - null /*resourceMarker*/); + dxInput = helper.getCompiledCodePaths(); } IJavaProject javaProject = JavaCore.create(project); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java index f17f0c5..c2f2510 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java @@ -214,17 +214,16 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer entries.add(entry); - // now, gather the content of this library project's libs folder. + // process all of the library project's dependencies + getDependencyListFromClasspath(libProject, refProjects, jarFiles, true); + // and the content of its libs folder. getJarListFromLibsFolder(libProject, jarFiles); } - - // get project dependencies - getDependencyListFromClasspath(libProject, refProjects, jarFiles, false); } - // now process this projects' referenced projects - getDependencyListFromClasspath(iProject, refProjects, jarFiles, false); - // and its own jar files from libs + // now process this projects' referenced projects only. + processReferencedProjects(iProject, refProjects, jarFiles); + // and the content of its libs folder getJarListFromLibsFolder(iProject, jarFiles); // annotations support for older version of android @@ -311,6 +310,32 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer } /** + * Process reference projects from the main projects to add indirect dependencies coming + * from Java project. + * @param project the main project + * @param projects the project list to add to + * @param jarFiles the jar list to add to. + */ + private static void processReferencedProjects(IProject project, + Set<IProject> projects, Set<File> jarFiles) { + try { + IProject[] refs = project.getReferencedProjects(); + for (IProject p : refs) { + // ignore if it's an Android project, or if it's not a Java + // Project + if (p.hasNature(JavaCore.NATURE_ID) + && p.hasNature(AdtConstants.NATURE_DEFAULT) == false) { + + // process this project's dependencies + getDependencyListFromClasspath(p, projects, jarFiles, true /*includeJarFiles*/); + } + } + } catch (CoreException e) { + // can't get the referenced projects? ignore + } + } + + /** * Finds all the dependencies of a given project and add them to a project list and * a jar list. * Only classpath entries that are exported are added, and only Java project (not Android @@ -332,7 +357,10 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer IClasspathEntry[] classpaths = javaProject.readRawClasspath(); if (classpaths != null) { for (IClasspathEntry e : classpaths) { - processCPE(e, javaProject, wsRoot, projects, jarFiles, includeJarFiles); + // ignore entries that are not exported + if (e.isExported()) { + processCPE(e, javaProject, wsRoot, projects, jarFiles, includeJarFiles); + } } } } @@ -351,21 +379,11 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer IWorkspaceRoot wsRoot, Set<IProject> projects, Set<File> jarFiles, boolean includeJarFiles) { - // ignore entries that are not exported - if (entry.isExported() == false) { - return; - } - // if this is a classpath variable reference, we resolve it. if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { entry = JavaCore.getResolvedClasspathEntry(entry); } - // not sure if an exported var could resolve to an exported one? - if (entry.isExported() == false) { - return; - } - if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { IProject refProject = wsRoot.getProject(entry.getPath().lastSegment()); try { |