diff options
Diffstat (limited to 'anttasks')
-rw-r--r-- | anttasks/src/com/android/ant/AaptExecLoopTask.java | 30 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/AidlExecTask.java | 5 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/AntConstants.java | 63 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/BaseTask.java | 39 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/MultiApkExportTask.java | 18 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/NewSetupTask.java | 638 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/SetupTask.java | 587 |
7 files changed, 720 insertions, 660 deletions
diff --git a/anttasks/src/com/android/ant/AaptExecLoopTask.java b/anttasks/src/com/android/ant/AaptExecLoopTask.java index ebefde5..6b438bb 100644 --- a/anttasks/src/com/android/ant/AaptExecLoopTask.java +++ b/anttasks/src/com/android/ant/AaptExecLoopTask.java @@ -88,6 +88,8 @@ public final class AaptExecLoopTask extends BaseTask { private String mResourceFilter; private String mRFolder; private final ArrayList<NoCompress> mNoCompressList = new ArrayList<NoCompress>(); + private String mProjectLibrariesResName; + private String mProjectLibrariesPackageName; /** * Sets the value of the "executable" attribute. @@ -235,6 +237,15 @@ public final class AaptExecLoopTask extends BaseTask { } } + public void setProjectLibrariesResName(String projectLibrariesResName) { + mProjectLibrariesResName = projectLibrariesResName; + } + + public void setProjectLibrariesPackageName(String projectLibrariesPackageName) { + mProjectLibrariesPackageName = projectLibrariesPackageName; + } + + /** * Returns an object representing a nested <var>nocompress</var> element. */ @@ -268,6 +279,13 @@ public final class AaptExecLoopTask extends BaseTask { */ @Override public void execute() throws BuildException { + if (mProjectLibrariesResName == null) { + throw new BuildException("Missing attribute projectLibrariesResName"); + } + if (mProjectLibrariesPackageName == null) { + throw new BuildException("Missing attribute projectLibrariesPackageName"); + } + Project taskProject = getProject(); String libPkgProp = null; @@ -275,7 +293,7 @@ public final class AaptExecLoopTask extends BaseTask { // if the parameters indicate generation of the R class, check if // more R classes need to be created for libraries. if (mRFolder != null && new File(mRFolder).isDirectory()) { - libPkgProp = taskProject.getProperty(AntConstants.PROP_PROJECT_LIBS_PKG); + libPkgProp = taskProject.getProperty(mProjectLibrariesPackageName); if (libPkgProp != null) { // Replace ";" with ":" since that's what aapt expects libPkgProp = libPkgProp.replace(';', ':'); @@ -285,6 +303,11 @@ public final class AaptExecLoopTask extends BaseTask { callAapt(libPkgProp); } + @Override + protected String getExecTaskName() { + return "aapt"; + } + /** * Calls aapt with the given parameters. * @param resourceFilter the resource configuration filter to pass to aapt (if configName is @@ -298,7 +321,7 @@ public final class AaptExecLoopTask extends BaseTask { final boolean generateRClass = mRFolder != null && new File(mRFolder).isDirectory(); // Get whether we have libraries - Object libResRef = taskProject.getReference(AntConstants.PROP_PROJECT_LIBS_RES_REF); + Object libResRef = taskProject.getReference(mProjectLibrariesResName); // Set up our folders to check for changed files ArrayList<File> watchPaths = new ArrayList<File>(); @@ -358,8 +381,7 @@ public final class AaptExecLoopTask extends BaseTask { task.setExecutable(mExecutable); task.setFailonerror(true); - File exe = new File(mExecutable); - task.setTaskName(exe.getName()); + task.setTaskName(getExecTaskName()); // aapt command. Only "package" is supported at this time really. task.createArg().setValue(mCommand); diff --git a/anttasks/src/com/android/ant/AidlExecTask.java b/anttasks/src/com/android/ant/AidlExecTask.java index f2fa094..5fa1f30 100644 --- a/anttasks/src/com/android/ant/AidlExecTask.java +++ b/anttasks/src/com/android/ant/AidlExecTask.java @@ -93,9 +93,6 @@ public class AidlExecTask extends Task { } } - File exe = new File(mExecutable); - String execTaskName = exe.getName(); - // now loop on all the source folders to find all the aidl to compile // and compile them for (String sourceFolder : sourceFolders) { @@ -115,7 +112,7 @@ public class AidlExecTask extends Task { task.setProject(taskProject); task.setOwningTarget(getOwningTarget()); task.setExecutable(mExecutable); - task.setTaskName(execTaskName); + task.setTaskName("aidl"); task.setFailonerror(true); task.createArg().setValue("-p" + mFramework); diff --git a/anttasks/src/com/android/ant/AntConstants.java b/anttasks/src/com/android/ant/AntConstants.java deleted file mode 100644 index a87d0d5..0000000 --- a/anttasks/src/com/android/ant/AntConstants.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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.ant; - -/** - * Constants used by custom tasks and the rules files. - */ -public interface AntConstants { - - /** ant property with the path to the android.jar file */ - public final static String PROP_ANDROID_JAR = "android.jar"; - - /** ant property with the path to the framework.aidl file */ - public final static String PROP_ANDROID_AIDL = "android.aidl"; - - /** ant property with the path to the renderscript framework include folder. */ - public final static String PROP_ANDROID_RENDERSCRIPT = "android.rs"; - - /** ant property with the path to the aapt tool */ - public final static String PROP_AAPT = "aapt"; - /** ant property with the path to the aidl tool */ - public final static String PROP_AIDL = "aidl"; - /** ant property with the path to the dx tool */ - public final static String PROP_DX = "dx"; - /** ant property with the path to the renderscript tool */ - public final static String PROP_RENDERSCRIPT = "renderscript"; - /** ref id to the <path> object containing all the boot classpaths. */ - public final static String PROP_CLASSPATH_REF = "android.target.classpath"; - - /** ant property ref to the list of source folder for the project libraries */ - public static final String PROP_PROJECT_LIBS_SRC_REF = "project.libraries.src"; - /** ant property ref to the list of jars for the project libraries */ - public static final String PROP_PROJECT_LIBS_JARS_REF = "project.libraries.jars"; - /** ant property ref to the list of libs folder for the project libraries */ - public static final String PROP_PROJECT_LIBS_LIBS_REF = "project.libraries.libs"; - /** ant property ref to the list of res folder for the project libraries */ - public static final String PROP_PROJECT_LIBS_RES_REF = "project.libraries.res"; - /** ant property for semi-colon separated packages for the project libraries */ - public static final String PROP_PROJECT_LIBS_PKG = "project.libraries.package"; - /** ant property for the test project directory */ - public static final String PROP_TESTED_PROJECT_DIR = "tested.project.dir"; - - public static final String PROP_MANIFEST_PACKAGE = "manifest.package"; - - public static final String PROP_OUT_ABS_DIR = "out.absolute.dir"; - - public static final String PROP_KEY_STORE_PASSWORD = "key.store.password"; - public static final String PROP_KEY_ALIAS_PASSWORD = "key.alias.password"; -} diff --git a/anttasks/src/com/android/ant/BaseTask.java b/anttasks/src/com/android/ant/BaseTask.java index 2126d3f..00b7fcb 100644 --- a/anttasks/src/com/android/ant/BaseTask.java +++ b/anttasks/src/com/android/ant/BaseTask.java @@ -25,18 +25,22 @@ import java.util.ArrayList; /** * A base class for the ant task that contains logic for handling dependency files */ -public class BaseTask extends Task { +public abstract class BaseTask extends Task { private DependencyGraph mDependencies; + private String mPreviousBuildType; + private String mBuildType; + + public void setPreviousBuildType(String previousBuildType) { + mPreviousBuildType = previousBuildType; + } + + public void setBuildType(String buildType) { + mBuildType = buildType; + } + + protected abstract String getExecTaskName(); - /* - * (non-Javadoc) - * - * Executes the loop. Based on the values inside default.properties, this will - * create alternate temporary ap_ files. - * - * @see org.apache.tools.ant.Task#execute() - */ @Override public void execute() throws BuildException { @@ -46,9 +50,14 @@ public class BaseTask extends Task { * Set up the dependency graph by passing it the location of the ".d" file * @param dependencyFile path to the dependency file to use * @param watchPaths a list of folders to watch for new files - * @return true if the dependency graph was sucessfully initialized + * @return true if the dependency graph was successfully initialized */ protected boolean initDependencies(String dependencyFile, ArrayList<File> watchPaths) { + if (mBuildType != null && mBuildType.equals(mPreviousBuildType) == false) { + // we don't care about deps, we need to execute the task no matter what. + return true; + } + File depFile = new File(dependencyFile); if (depFile.exists()) { mDependencies = new DependencyGraph(dependencyFile, watchPaths); @@ -64,6 +73,16 @@ public class BaseTask extends Task { * have changed since the last run */ protected boolean dependenciesHaveChanged() { + if (mBuildType != null && mBuildType.equals(mPreviousBuildType) == false) { + String execName = getExecTaskName(); + if (execName == null) { + System.out.println("Current build type is different than previous build: forced task run."); + } else { + System.out.println("Current build type is different than previous build: forced " + execName + " run."); + } + return true; + } + assert mDependencies != null : "Dependencies have not been initialized"; return mDependencies.dependenciesHaveChanged(); } diff --git a/anttasks/src/com/android/ant/MultiApkExportTask.java b/anttasks/src/com/android/ant/MultiApkExportTask.java index a21478e..6b23162 100644 --- a/anttasks/src/com/android/ant/MultiApkExportTask.java +++ b/anttasks/src/com/android/ant/MultiApkExportTask.java @@ -52,6 +52,12 @@ import javax.xml.xpath.XPathFactory; */ public class MultiApkExportTask extends Task { + private static final String PROP_OUT_ABS_DIR = "out.absolute.dir"; + + private static final String PROP_KEY_STORE_PASSWORD = "key.store.password"; + private static final String PROP_KEY_ALIAS_PASSWORD = "key.alias.password"; + + private Target mTarget; private XPathFactory mXPathFactory; @@ -117,7 +123,7 @@ public class MultiApkExportTask extends Task { mXPathFactory = XPathFactory.newInstance(); File exportProjectOutput = new File( - getValidatedProperty(antProject, AntConstants.PROP_OUT_ABS_DIR)); + getValidatedProperty(antProject, PROP_OUT_ABS_DIR)); // if there's no error, and we can sign, prompt for the passwords. String keyStorePassword = null; @@ -127,23 +133,21 @@ public class MultiApkExportTask extends Task { Input input = new Input(); input.setProject(antProject); - input.setAddproperty(AntConstants.PROP_KEY_STORE_PASSWORD); + input.setAddproperty(PROP_KEY_STORE_PASSWORD); input.setMessage(String.format("Please enter keystore password (store: %1$s):", keyStore)); input.execute(); input = new Input(); input.setProject(antProject); - input.setAddproperty(AntConstants.PROP_KEY_ALIAS_PASSWORD); + input.setAddproperty(PROP_KEY_ALIAS_PASSWORD); input.setMessage(String.format("Please enter password for alias '%1$s':", keyAlias)); input.execute(); // and now read the property so that they can be set into the sub ant task. - keyStorePassword = getValidatedProperty(antProject, - AntConstants.PROP_KEY_STORE_PASSWORD); - keyAliasPassword = getValidatedProperty(antProject, - AntConstants.PROP_KEY_ALIAS_PASSWORD); + keyStorePassword = getValidatedProperty(antProject, PROP_KEY_STORE_PASSWORD); + keyAliasPassword = getValidatedProperty(antProject, PROP_KEY_ALIAS_PASSWORD); } for (ApkData apk : apks) { diff --git a/anttasks/src/com/android/ant/NewSetupTask.java b/anttasks/src/com/android/ant/NewSetupTask.java new file mode 100644 index 0000000..50dcdab --- /dev/null +++ b/anttasks/src/com/android/ant/NewSetupTask.java @@ -0,0 +1,638 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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.ant; + +import com.android.io.FileWrapper; +import com.android.io.FolderWrapper; +import com.android.sdklib.AndroidVersion; +import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.ISdkLog; +import com.android.sdklib.SdkConstants; +import com.android.sdklib.SdkManager; +import com.android.sdklib.IAndroidTarget.IOptionalLibrary; +import com.android.sdklib.internal.project.ProjectProperties; +import com.android.sdklib.internal.project.ProjectProperties.PropertyType; +import com.android.sdklib.xml.AndroidManifest; +import com.android.sdklib.xml.AndroidXPathFactory; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Path.PathElement; +import org.apache.tools.ant.util.DeweyDecimal; +import org.xml.sax.InputSource; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpressionException; + +/** + * Setup Ant task. This task accomplishes: + * <ul> + * <li>Gets the project target hash string from {@link ProjectProperties#PROPERTY_TARGET}, + * and resolves it to get the project's {@link IAndroidTarget}.</li> + * + * <li>Sets up properties so that aapt can find the android.jar and other files/folders in + * the resolved target.</li> + * + * <li>Sets up the boot classpath ref so that the <code>javac</code> task knows where to find + * the libraries. This includes the default android.jar from the resolved target but also optional + * libraries provided by the target (if any, when the target is an add-on).</li> + * + * <li>Resolve library dependencies and setup various Path references for them</li> + * </ul> + * + * This is used in the main rules file only. + * + */ +public class NewSetupTask extends Task { + private final static String ANT_MIN_VERSION = "1.8.0"; + + private String mProjectTypeOut; + private String mAndroidJarFileOut; + private String mAndroidAidlFileOut; + private String mRenderScriptExeOut; + private String mRenderScriptIncludeDirOut; + private String mBootclasspathrefOut; + private String mProjectLibrariesRootOut; + private String mProjectLibrariesResOut; + private String mProjectLibrariesPackageOut; + private String mProjectLibrariesJarsOut; + private String mProjectLibrariesLibsOut; + + public void setProjectTypeOut(String projectTypeOut) { + mProjectTypeOut = projectTypeOut; + } + + public void setAndroidJarFileOut(String androidJarFileOut) { + mAndroidJarFileOut = androidJarFileOut; + } + + public void setAndroidAidlFileOut(String androidAidlFileOut) { + mAndroidAidlFileOut = androidAidlFileOut; + } + + public void setRenderScriptExeOut(String renderScriptExeOut) { + mRenderScriptExeOut = renderScriptExeOut; + } + + public void setRenderScriptIncludeDirOut(String renderScriptIncludeDirOut) { + mRenderScriptIncludeDirOut = renderScriptIncludeDirOut; + } + + public void setBootclasspathrefOut(String bootclasspathrefOut) { + mBootclasspathrefOut = bootclasspathrefOut; + } + + public void setProjectLibrariesRootOut(String projectLibrariesRootOut) { + mProjectLibrariesRootOut = projectLibrariesRootOut; + } + + public void setProjectLibrariesResOut(String projectLibrariesResOut) { + mProjectLibrariesResOut = projectLibrariesResOut; + } + + public void setProjectLibrariesPackageOut(String projectLibrariesPackageOut) { + mProjectLibrariesPackageOut = projectLibrariesPackageOut; + } + + public void setProjectLibrariesJarsOut(String projectLibrariesJarsOut) { + mProjectLibrariesJarsOut = projectLibrariesJarsOut; + } + + public void setProjectLibrariesLibsOut(String projectLibrariesLibsOut) { + mProjectLibrariesLibsOut = projectLibrariesLibsOut; + } + + @Override + public void execute() throws BuildException { + if (mProjectTypeOut == null) { + throw new BuildException("Missing attribute projectTypeOut"); + } + if (mAndroidJarFileOut == null) { + throw new BuildException("Missing attribute androidJarFileOut"); + } + if (mAndroidAidlFileOut == null) { + throw new BuildException("Missing attribute androidAidlFileOut"); + } + if (mRenderScriptExeOut == null) { + throw new BuildException("Missing attribute renderScriptExeOut"); + } + if (mRenderScriptIncludeDirOut == null) { + throw new BuildException("Missing attribute renderScriptIncludeDirOut"); + } + if (mBootclasspathrefOut == null) { + throw new BuildException("Missing attribute bootclasspathrefOut"); + } + if (mProjectLibrariesRootOut == null) { + throw new BuildException("Missing attribute projectLibrariesRootOut"); + } + if (mProjectLibrariesResOut == null) { + throw new BuildException("Missing attribute projectLibrariesResOut"); + } + if (mProjectLibrariesPackageOut == null) { + throw new BuildException("Missing attribute projectLibrariesPackageOut"); + } + if (mProjectLibrariesJarsOut == null) { + throw new BuildException("Missing attribute projectLibrariesJarsOut"); + } + if (mProjectLibrariesLibsOut == null) { + throw new BuildException("Missing attribute projectLibrariesLibsOut"); + } + + + Project antProject = getProject(); + + // check the Ant version + DeweyDecimal version = getVersion(antProject); + DeweyDecimal atLeast = new DeweyDecimal(ANT_MIN_VERSION); + if (atLeast.isGreaterThan(version)) { + throw new BuildException( + "The Android Ant-based build system requires Ant " + + ANT_MIN_VERSION + + " or later. Current version is " + + version); + } + + // get the SDK location + File sdkDir = TaskHelper.getSdkLocation(antProject); + String sdkOsPath = sdkDir.getPath(); + + // Make sure the OS sdk path ends with a directory separator + if (sdkOsPath.length() > 0 && !sdkOsPath.endsWith(File.separator)) { + sdkOsPath += File.separator; + } + + // display SDK Tools revision + int toolsRevison = TaskHelper.getToolsRevision(sdkDir); + if (toolsRevison != -1) { + System.out.println("Android SDK Tools Revision " + toolsRevison); + } + + // detect that the platform tools is there. + File platformTools = new File(sdkDir, SdkConstants.FD_PLATFORM_TOOLS); + if (platformTools.isDirectory() == false) { + throw new BuildException(String.format( + "SDK Platform Tools component is missing. " + + "Please install it with the SDK Manager (%1$s%2$c%3$s)", + SdkConstants.FD_TOOLS, + File.separatorChar, + SdkConstants.androidCmdName())); + } + + // get the target property value + String targetHashString = antProject.getProperty(ProjectProperties.PROPERTY_TARGET); + + boolean isTestProject = false; + + if (antProject.getProperty(ProjectProperties.PROPERTY_TESTED_PROJECT) != null) { + isTestProject = true; + } + + if (targetHashString == null) { + throw new BuildException("Android Target is not set."); + } + + // load up the sdk targets. + final ArrayList<String> messages = new ArrayList<String>(); + SdkManager manager = SdkManager.createManager(sdkOsPath, new ISdkLog() { + public void error(Throwable t, String errorFormat, Object... args) { + if (errorFormat != null) { + messages.add(String.format("Error: " + errorFormat, args)); + } + if (t != null) { + messages.add("Error: " + t.getMessage()); + } + } + + public void printf(String msgFormat, Object... args) { + messages.add(String.format(msgFormat, args)); + } + + public void warning(String warningFormat, Object... args) { + messages.add(String.format("Warning: " + warningFormat, args)); + } + }); + + if (manager == null) { + // since we failed to parse the SDK, lets display the parsing output. + for (String msg : messages) { + System.out.println(msg); + } + throw new BuildException("Failed to parse SDK content."); + } + + // resolve it + IAndroidTarget androidTarget = manager.getTargetFromHashString(targetHashString); + + if (androidTarget == null) { + throw new BuildException(String.format( + "Unable to resolve target '%s'", targetHashString)); + } + + // display the project info + System.out.println("Project Target: " + androidTarget.getName()); + if (androidTarget.isPlatform() == false) { + System.out.println("Vendor: " + androidTarget.getVendor()); + System.out.println("Platform Version: " + androidTarget.getVersionName()); + } + System.out.println("API level: " + androidTarget.getVersion().getApiString()); + + // check if the project is a library + boolean isLibrary = false; + + String libraryProp = antProject.getProperty(ProjectProperties.PROPERTY_LIBRARY); + if (libraryProp != null) { + isLibrary = Boolean.valueOf(libraryProp).booleanValue(); + } + + if (isLibrary) { + System.out.println("Project Type: Android Library"); + } + + // look for referenced libraries. + processReferencedLibraries(antProject, androidTarget); + + // always check the manifest minSdkVersion. + checkManifest(antProject, androidTarget.getVersion()); + + // sets up the properties to find android.jar/framework.aidl/target tools + String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR); + antProject.setProperty(mAndroidJarFileOut, androidJar); + + String androidAidl = androidTarget.getPath(IAndroidTarget.ANDROID_AIDL); + antProject.setProperty(mAndroidAidlFileOut, androidAidl); + + Path includePath = new Path(antProject); + PathElement element = includePath.createPathElement(); + element.setPath(androidTarget.getPath(IAndroidTarget.ANDROID_RS)); + element = includePath.createPathElement(); + element.setPath(androidTarget.getPath(IAndroidTarget.ANDROID_RS_CLANG)); + antProject.setProperty(mRenderScriptIncludeDirOut, includePath.toString()); + + // TODO: figure out the actual compiler to use based on the minSdkVersion + antProject.setProperty(mRenderScriptExeOut, + sdkOsPath + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + + SdkConstants.FN_RENDERSCRIPT); + + // sets up the boot classpath + + // create the Path object + Path bootclasspath = new Path(antProject); + + // create a PathElement for the framework jar + element = bootclasspath.createPathElement(); + element.setPath(androidJar); + + // create PathElement for each optional library. + IOptionalLibrary[] libraries = androidTarget.getOptionalLibraries(); + if (libraries != null) { + HashSet<String> visitedJars = new HashSet<String>(); + for (IOptionalLibrary library : libraries) { + String jarPath = library.getJarPath(); + if (visitedJars.contains(jarPath) == false) { + visitedJars.add(jarPath); + + element = bootclasspath.createPathElement(); + element.setPath(library.getJarPath()); + } + } + } + + // sets the path in the project with a reference + antProject.addReference(mBootclasspathrefOut, bootclasspath); + + // finally set the project type. + if (isLibrary) { + antProject.setProperty(mProjectTypeOut, "library"); + } else if (isTestProject) { + antProject.setProperty(mProjectTypeOut, "test"); + } else { + antProject.setProperty(mProjectTypeOut, "project"); + } + } + + /** + * Checks the manifest <code>minSdkVersion</code> attribute. + * @param antProject the ant project + * @param androidVersion the version of the platform the project is compiling against. + */ + private void checkManifest(Project antProject, AndroidVersion androidVersion) { + try { + File manifest = new File(antProject.getBaseDir(), SdkConstants.FN_ANDROID_MANIFEST_XML); + + XPath xPath = AndroidXPathFactory.newXPath(); + + // check the package name. + String value = xPath.evaluate( + "/" + AndroidManifest.NODE_MANIFEST + + "/@" + AndroidManifest.ATTRIBUTE_PACKAGE, + new InputSource(new FileInputStream(manifest))); + if (value != null) { // aapt will complain if it's missing. + // only need to check that the package has 2 segments + if (value.indexOf('.') == -1) { + throw new BuildException(String.format( + "Application package '%1$s' must have a minimum of 2 segments.", + value)); + } + } + + // check the minSdkVersion value + value = xPath.evaluate( + "/" + AndroidManifest.NODE_MANIFEST + + "/" + AndroidManifest.NODE_USES_SDK + + "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + ":" + + AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, + new InputSource(new FileInputStream(manifest))); + + if (androidVersion.isPreview()) { + // in preview mode, the content of the minSdkVersion must match exactly the + // platform codename. + String codeName = androidVersion.getCodename(); + if (codeName.equals(value) == false) { + throw new BuildException(String.format( + "For '%1$s' SDK Preview, attribute minSdkVersion in AndroidManifest.xml must be '%1$s'", + codeName)); + } + } else if (value.length() > 0) { + // for normal platform, we'll only display warnings if the value is lower or higher + // than the target api level. + // First convert to an int. + int minSdkValue = -1; + try { + minSdkValue = Integer.parseInt(value); + } catch (NumberFormatException e) { + // looks like it's not a number: error! + throw new BuildException(String.format( + "Attribute %1$s in AndroidManifest.xml must be an Integer!", + AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION)); + } + + int projectApiLevel = androidVersion.getApiLevel(); + if (minSdkValue < projectApiLevel) { + System.out.println(String.format( + "WARNING: Attribute %1$s in AndroidManifest.xml (%2$d) is lower than the project target API level (%3$d)", + AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, + minSdkValue, projectApiLevel)); + } else if (minSdkValue > androidVersion.getApiLevel()) { + System.out.println(String.format( + "WARNING: Attribute %1$s in AndroidManifest.xml (%2$d) is higher than the project target API level (%3$d)", + AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, + minSdkValue, projectApiLevel)); + } + } else { + // no minSdkVersion? display a warning + System.out.println( + "WARNING: No minSdkVersion value set. Application will install on all Android versions."); + } + + } catch (XPathExpressionException e) { + throw new BuildException(e); + } catch (FileNotFoundException e) { + throw new BuildException(e); + } + } + + private void processReferencedLibraries(Project antProject, IAndroidTarget androidTarget) { + // prepare several paths for future tasks + Path rootPath = new Path(antProject); + Path resPath = new Path(antProject); + Path libsPath = new Path(antProject); + Path jarsPath = new Path(antProject); + StringBuilder packageStrBuilder = new StringBuilder(); + + FilenameFilter filter = new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.toLowerCase().endsWith(".jar"); + } + }; + + System.out.println("\n------------------\nResolving library dependencies:"); + + ArrayList<File> libraries = getProjectLibraries(antProject); + + if (libraries.size() > 0) { + System.out.println("------------------\nOrdered libraries:"); + + for (File library : libraries) { + String libRootPath = library.getAbsolutePath(); + System.out.println(libRootPath); + + // get the root path. + PathElement element = rootPath.createPathElement(); + element.setPath(libRootPath); + + // get the res path. Always $PROJECT/res + element = resPath.createPathElement(); + element.setPath(libRootPath + "/" + SdkConstants.FD_RESOURCES); + + // get the libs path. Always $PROJECT/libs + element = libsPath.createPathElement(); + element.setPath(libRootPath + "/" + SdkConstants.FD_NATIVE_LIBS); + + // get the jars from it too. + // 1. the library code jar + element = jarsPath.createPathElement(); + element.setPath(libRootPath + "/" + SdkConstants.FD_OUTPUT + + "/" + SdkConstants.FN_CLASSES_JAR); + + // 2. the 3rd party jar files + File libsFolder = new File(library, SdkConstants.FD_NATIVE_LIBS); + File[] jarFiles = libsFolder.listFiles(filter); + if (jarFiles != null) { + for (File jarFile : jarFiles) { + element = jarsPath.createPathElement(); + element.setPath(jarFile.getAbsolutePath()); + } + } + + // get the package from the manifest. + FileWrapper manifest = new FileWrapper(library, + SdkConstants.FN_ANDROID_MANIFEST_XML); + + try { + String value = AndroidManifest.getPackage(manifest); + if (value != null) { // aapt will complain if it's missing. + packageStrBuilder.append(';'); + packageStrBuilder.append(value); + } + } catch (Exception e) { + throw new BuildException(e); + } + } + } else { + System.out.println("No library dependencies.\n"); + } + + System.out.println("------------------\n"); + + // even with no libraries, always setup these so that various tasks in Ant don't complain + // (the task themselves can handle a ref to an empty Path) + antProject.addReference(mProjectLibrariesJarsOut, jarsPath); + antProject.addReference(mProjectLibrariesLibsOut, libsPath); + + // the rest is done only if there's a library. + if (jarsPath.list().length > 0) { + System.out.println("DEBUG: " + rootPath.toString()); + antProject.addReference(mProjectLibrariesRootOut, rootPath); + antProject.addReference(mProjectLibrariesResOut, resPath); + antProject.setProperty(mProjectLibrariesPackageOut, packageStrBuilder.toString()); + } + } + + /** + * Returns all the library dependencies of a given Ant project. + * @param antProject the Ant project + * @return a list of properties, sorted from highest priority to lowest. + */ + private ArrayList<File> getProjectLibraries(final Project antProject) { + ArrayList<File> libraries = new ArrayList<File>(); + File baseDir = antProject.getBaseDir(); + + // get the top level list of library dependencies. + List<File> topLevelLibraries = getDirectDependencies(baseDir, new IPropertySource() { + public String getProperty(String name) { + return antProject.getProperty(name); + } + }); + + // process the libraries in case they depend on other libraries. + resolveFullLibraryDependencies(topLevelLibraries, libraries); + + return libraries; + } + + /** + * Resolves a given list of libraries, finds out if they depend on other libraries, and + * returns a full list of all the direct and indirect dependencies in the proper order (first + * is higher priority when calling aapt). + * @param inLibraries the libraries to resolve + * @param outLibraries where to store all the libraries. + */ + private void resolveFullLibraryDependencies(List<File> inLibraries, List<File> outLibraries) { + // loop in the inverse order to resolve dependencies on the libraries, so that if a library + // is required by two higher level libraries it can be inserted in the correct place + for (int i = inLibraries.size() - 1 ; i >= 0 ; i--) { + File library = inLibraries.get(i); + + // get the default.property file for it + final ProjectProperties defaultProp = ProjectProperties.load( + new FolderWrapper(library), PropertyType.DEFAULT); + + // get its libraries + List<File> dependencies = getDirectDependencies(library, new IPropertySource() { + public String getProperty(String name) { + return defaultProp.getProperty(name); + } + }); + + // resolve the dependencies for those libraries + resolveFullLibraryDependencies(dependencies, outLibraries); + + // and add the current one (if needed) in front (higher priority) + if (outLibraries.contains(library) == false) { + outLibraries.add(0, library); + } + } + } + + public interface IPropertySource { + String getProperty(String name); + } + + /** + * Returns the top level library dependencies of a given <var>source</var> representing a + * project properties. + * @param baseFolder the base folder of the project (to resolve relative paths) + * @param source a source of project properties. + */ + private List<File> getDirectDependencies(File baseFolder, IPropertySource source) { + ArrayList<File> libraries = new ArrayList<File>(); + + // first build the list. they are ordered highest priority first. + int index = 1; + while (true) { + String propName = ProjectProperties.PROPERTY_LIB_REF + Integer.toString(index++); + String rootPath = source.getProperty(propName); + + if (rootPath == null) { + break; + } + + try { + File library = new File(baseFolder, rootPath).getCanonicalFile(); + + // check for validity + File defaultProp = new File(library, PropertyType.DEFAULT.getFilename()); + if (defaultProp.isFile() == false) { + // error! + throw new BuildException(String.format( + "%1$s resolve to a path with no %2$s file for project %3$s", rootPath, + PropertyType.DEFAULT.getFilename(), baseFolder.getAbsolutePath())); + } + + if (libraries.contains(library) == false) { + System.out.println(String.format("%1$s: %2$s => %3$s", + baseFolder.getAbsolutePath(), rootPath, library.getAbsolutePath())); + + libraries.add(library); + } + } catch (IOException e) { + throw new BuildException("Failed to resolve library path: " + rootPath, e); + } + } + + return libraries; + } + + /** + * Returns the Ant version as a {@link DeweyDecimal} object. + * + * This is based on the implementation of + * org.apache.tools.ant.taskdefs.condition.AntVersion.getVersion() + * + * @param antProject the current ant project. + * @return the ant version. + */ + private DeweyDecimal getVersion(Project antProject) { + char[] versionString = antProject.getProperty("ant.version").toCharArray(); + StringBuilder sb = new StringBuilder(); + boolean foundFirstDigit = false; + for (int i = 0; i < versionString.length; i++) { + if (Character.isDigit(versionString[i])) { + sb.append(versionString[i]); + foundFirstDigit = true; + } + if (versionString[i] == '.' && foundFirstDigit) { + sb.append(versionString[i]); + } + if (Character.isLetter(versionString[i]) && foundFirstDigit) { + break; + } + } + return new DeweyDecimal(sb.toString()); + } +} diff --git a/anttasks/src/com/android/ant/SetupTask.java b/anttasks/src/com/android/ant/SetupTask.java index e15f77b..c0bc55d 100644 --- a/anttasks/src/com/android/ant/SetupTask.java +++ b/anttasks/src/com/android/ant/SetupTask.java @@ -16,588 +16,31 @@ package com.android.ant; -import com.android.io.FileWrapper; -import com.android.io.FolderWrapper; -import com.android.sdklib.AndroidVersion; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.ISdkLog; -import com.android.sdklib.SdkConstants; -import com.android.sdklib.SdkManager; -import com.android.sdklib.IAndroidTarget.IOptionalLibrary; -import com.android.sdklib.internal.project.ProjectProperties; -import com.android.sdklib.internal.project.ProjectProperties.PropertyType; -import com.android.sdklib.xml.AndroidManifest; -import com.android.sdklib.xml.AndroidXPathFactory; - import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.ImportTask; -import org.apache.tools.ant.types.Path; -import org.apache.tools.ant.types.Path.PathElement; -import org.apache.tools.ant.util.DeweyDecimal; -import org.xml.sax.InputSource; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FilenameFilter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathExpressionException; /** - * Setup/Import Ant task. This task accomplishes: - * <ul> - * <li>Gets the project target hash string from {@link ProjectProperties#PROPERTY_TARGET}, - * and resolves it to get the project's {@link IAndroidTarget}.</li> - * <li>Sets up properties so that aapt can find the android.jar in the resolved target.</li> - * <li>Sets up the boot classpath ref so that the <code>javac</code> task knows where to find - * the libraries. This includes the default android.jar from the resolved target but also optional - * libraries provided by the target (if any, when the target is an add-on).</li> - * <li>Imports the build rules located in the resolved target so that the build actually does - * something. This can be disabled with the attribute <var>import</var> set to <code>false</code> - * </li></ul> - * - * This is used in build.xml/template. + * Legacy setupTask class used by older build system. * + * If this is used it actually only display an error about the need to update the build file. */ -public final class SetupTask extends ImportTask { - private final static String ANT_MIN_VERSION = "1.8.0"; - // main rules file - private final static String RULES_MAIN = "main_rules.xml"; - // test rules file - depends on android_rules.xml - private final static String RULES_TEST = "test_rules.xml"; - // library rules file. - private final static String RULES_LIBRARY = "lib_rules.xml"; - - private boolean mDoImport = true; - - @Override - public void execute() throws BuildException { - Project antProject = getProject(); - - // check the Ant version - DeweyDecimal version = getVersion(antProject); - DeweyDecimal atLeast = new DeweyDecimal(ANT_MIN_VERSION); - if (atLeast.isGreaterThan(version)) { - throw new BuildException( - "The Android Ant-based build system requires Ant " + - ANT_MIN_VERSION + - " or later. Current version is " + - version); - } - - // get the SDK location - File sdkDir = TaskHelper.getSdkLocation(antProject); - String sdkOsPath = sdkDir.getPath(); - - // Make sure the OS sdk path ends with a directory separator - if (sdkOsPath.length() > 0 && !sdkOsPath.endsWith(File.separator)) { - sdkOsPath += File.separator; - } - - // display SDK Tools revision - int toolsRevison = TaskHelper.getToolsRevision(sdkDir); - if (toolsRevison != -1) { - System.out.println("Android SDK Tools Revision " + toolsRevison); - } - - // detect that the platform tools is there. - File platformTools = new File(sdkDir, SdkConstants.FD_PLATFORM_TOOLS); - if (platformTools.isDirectory() == false) { - throw new BuildException(String.format( - "SDK Platform Tools component is missing. " + - "Please install it with the SDK Manager (%1$s%2$c%3$s)", - SdkConstants.FD_TOOLS, - File.separatorChar, - SdkConstants.androidCmdName())); - } - - // get the target property value - String targetHashString = antProject.getProperty(ProjectProperties.PROPERTY_TARGET); - - boolean isTestProject = false; - - if (antProject.getProperty(AntConstants.PROP_TESTED_PROJECT_DIR) != null) { - isTestProject = true; - } - - if (targetHashString == null) { - throw new BuildException("Android Target is not set."); - } - - // load up the sdk targets. - final ArrayList<String> messages = new ArrayList<String>(); - SdkManager manager = SdkManager.createManager(sdkOsPath, new ISdkLog() { - public void error(Throwable t, String errorFormat, Object... args) { - if (errorFormat != null) { - messages.add(String.format("Error: " + errorFormat, args)); - } - if (t != null) { - messages.add("Error: " + t.getMessage()); - } - } - - public void printf(String msgFormat, Object... args) { - messages.add(String.format(msgFormat, args)); - } - - public void warning(String warningFormat, Object... args) { - messages.add(String.format("Warning: " + warningFormat, args)); - } - }); - - if (manager == null) { - // since we failed to parse the SDK, lets display the parsing output. - for (String msg : messages) { - System.out.println(msg); - } - throw new BuildException("Failed to parse SDK content."); - } - - // resolve it - IAndroidTarget androidTarget = manager.getTargetFromHashString(targetHashString); - - if (androidTarget == null) { - throw new BuildException(String.format( - "Unable to resolve target '%s'", targetHashString)); - } - - // display the project info - System.out.println("Project Target: " + androidTarget.getName()); - if (androidTarget.isPlatform() == false) { - System.out.println("Vendor: " + androidTarget.getVendor()); - System.out.println("Platform Version: " + androidTarget.getVersionName()); - } - System.out.println("API level: " + androidTarget.getVersion().getApiString()); - - // check if the project is a library - boolean isLibrary = false; - - String libraryProp = antProject.getProperty(ProjectProperties.PROPERTY_LIBRARY); - if (libraryProp != null) { - isLibrary = Boolean.valueOf(libraryProp).booleanValue(); - } - - if (isLibrary) { - System.out.println("Project Type: Android Library"); - } - - // look for referenced libraries. - processReferencedLibraries(antProject, androidTarget); - - // always check the manifest minSdkVersion. - checkManifest(antProject, androidTarget.getVersion()); - - // sets up the properties to find android.jar/framework.aidl/target tools - String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR); - antProject.setProperty(AntConstants.PROP_ANDROID_JAR, androidJar); - - String androidAidl = androidTarget.getPath(IAndroidTarget.ANDROID_AIDL); - antProject.setProperty(AntConstants.PROP_ANDROID_AIDL, androidAidl); - - Path includePath = new Path(antProject); - PathElement element = includePath.createPathElement(); - element.setPath(androidTarget.getPath(IAndroidTarget.ANDROID_RS)); - element = includePath.createPathElement(); - element.setPath(androidTarget.getPath(IAndroidTarget.ANDROID_RS_CLANG)); - antProject.setProperty(AntConstants.PROP_ANDROID_RENDERSCRIPT, includePath.toString()); - - antProject.setProperty(AntConstants.PROP_AAPT, androidTarget.getPath(IAndroidTarget.AAPT)); - antProject.setProperty(AntConstants.PROP_AIDL, androidTarget.getPath(IAndroidTarget.AIDL)); - antProject.setProperty(AntConstants.PROP_DX, androidTarget.getPath(IAndroidTarget.DX)); - antProject.setProperty(AntConstants.PROP_RENDERSCRIPT, - sdkOsPath + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + - SdkConstants.FN_RENDERSCRIPT); - - // sets up the boot classpath - - // create the Path object - Path bootclasspath = new Path(antProject); - - // create a PathElement for the framework jar - element = bootclasspath.createPathElement(); - element.setPath(androidJar); - - // create PathElement for each optional library. - IOptionalLibrary[] libraries = androidTarget.getOptionalLibraries(); - if (libraries != null) { - HashSet<String> visitedJars = new HashSet<String>(); - for (IOptionalLibrary library : libraries) { - String jarPath = library.getJarPath(); - if (visitedJars.contains(jarPath) == false) { - visitedJars.add(jarPath); - - element = bootclasspath.createPathElement(); - element.setPath(library.getJarPath()); - } - } - } - - // finally sets the path in the project with a reference - antProject.addReference(AntConstants.PROP_CLASSPATH_REF, bootclasspath); - - // Now the import section. This is only executed if the task actually has to import a file. - if (mDoImport) { - // check the ant folder exists in the tools folder of the SDK. - File rulesFolder = new File( - new File(sdkOsPath, SdkConstants.FD_TOOLS), - SdkConstants.FD_ANT); - - // make sure the file exists. - if (rulesFolder.isDirectory() == false) { - throw new BuildException(String.format("Rules directory '%s' is missing.", - rulesFolder.getAbsolutePath())); - } - - // name of the rules files to import based on the type of project - String importedRulesFileName = - isLibrary ? RULES_LIBRARY : isTestProject ? RULES_TEST : RULES_MAIN; - - // now check the rules file exists. - File rules = new File(rulesFolder, importedRulesFileName); - - if (rules.isFile() == false) { - throw new BuildException(String.format("Build rules file '%s' is missing.", - rules)); - } - - // display the file being imported. - // figure out the path relative to the SDK - String rulesOsPath = rules.getAbsolutePath(); - if (rulesOsPath.startsWith(sdkOsPath)) { - rulesOsPath = rulesOsPath.substring(sdkOsPath.length()); - if (rulesOsPath.startsWith(File.separator)) { - rulesOsPath = rulesOsPath.substring(1); - } - } - System.out.println("\nImporting rules file: " + rulesOsPath); - - // set the file location to import - setFile(rules.getAbsolutePath()); - - // and import - super.execute(); - } - } - - /** - * Sets the value of the "import" attribute. - * @param value the value. - */ - public void setImport(boolean value) { - mDoImport = value; - } +public final class SetupTask extends Task { /** - * Checks the manifest <code>minSdkVersion</code> attribute. - * @param antProject the ant project - * @param androidVersion the version of the platform the project is compiling against. - */ - private void checkManifest(Project antProject, AndroidVersion androidVersion) { - try { - File manifest = new File(antProject.getBaseDir(), SdkConstants.FN_ANDROID_MANIFEST_XML); - - XPath xPath = AndroidXPathFactory.newXPath(); - - // check the package name. - String value = xPath.evaluate( - "/" + AndroidManifest.NODE_MANIFEST + - "/@" + AndroidManifest.ATTRIBUTE_PACKAGE, - new InputSource(new FileInputStream(manifest))); - if (value != null) { // aapt will complain if it's missing. - // only need to check that the package has 2 segments - if (value.indexOf('.') == -1) { - throw new BuildException(String.format( - "Application package '%1$s' must have a minimum of 2 segments.", - value)); - } - } - - // check the minSdkVersion value - value = xPath.evaluate( - "/" + AndroidManifest.NODE_MANIFEST + - "/" + AndroidManifest.NODE_USES_SDK + - "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + ":" + - AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, - new InputSource(new FileInputStream(manifest))); - - if (androidVersion.isPreview()) { - // in preview mode, the content of the minSdkVersion must match exactly the - // platform codename. - String codeName = androidVersion.getCodename(); - if (codeName.equals(value) == false) { - throw new BuildException(String.format( - "For '%1$s' SDK Preview, attribute minSdkVersion in AndroidManifest.xml must be '%1$s'", - codeName)); - } - } else if (value.length() > 0) { - // for normal platform, we'll only display warnings if the value is lower or higher - // than the target api level. - // First convert to an int. - int minSdkValue = -1; - try { - minSdkValue = Integer.parseInt(value); - } catch (NumberFormatException e) { - // looks like it's not a number: error! - throw new BuildException(String.format( - "Attribute %1$s in AndroidManifest.xml must be an Integer!", - AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION)); - } - - int projectApiLevel = androidVersion.getApiLevel(); - if (minSdkValue < projectApiLevel) { - System.out.println(String.format( - "WARNING: Attribute %1$s in AndroidManifest.xml (%2$d) is lower than the project target API level (%3$d)", - AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, - minSdkValue, projectApiLevel)); - } else if (minSdkValue > androidVersion.getApiLevel()) { - System.out.println(String.format( - "WARNING: Attribute %1$s in AndroidManifest.xml (%2$d) is higher than the project target API level (%3$d)", - AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, - minSdkValue, projectApiLevel)); - } - } else { - // no minSdkVersion? display a warning - System.out.println( - "WARNING: No minSdkVersion value set. Application will install on all Android versions."); - } - - } catch (XPathExpressionException e) { - throw new BuildException(e); - } catch (FileNotFoundException e) { - throw new BuildException(e); - } - } - - private void processReferencedLibraries(Project antProject, IAndroidTarget androidTarget) { - // prepare several paths for future tasks - Path sourcePath = new Path(antProject); - Path resPath = new Path(antProject); - Path libsPath = new Path(antProject); - Path jarsPath = new Path(antProject); - StringBuilder sb = new StringBuilder(); - - FilenameFilter filter = new FilenameFilter() { - public boolean accept(File dir, String name) { - return name.toLowerCase().endsWith(".jar"); - } - }; - - System.out.println("\n------------------\nResolving library dependencies:"); - - ArrayList<File> libraries = getProjectLibraries(antProject); - - if (libraries.size() > 0) { - System.out.println("------------------\nOrdered libraries:"); - - for (File library : libraries) { - System.out.println(library.getAbsolutePath()); - - // get the source path. default is src but can be overriden by the property - // "source.dir" in build.properties. - PathElement element = sourcePath.createPathElement(); - ProjectProperties prop = ProjectProperties.load(new FolderWrapper(library), - PropertyType.BUILD); - - String sourceDir = SdkConstants.FD_SOURCES; - if (prop != null) { - String value = prop.getProperty(ProjectProperties.PROPERTY_BUILD_SOURCE_DIR); - if (value != null) { - sourceDir = value; - } - } - - String path = library.getAbsolutePath(); - - element.setPath(path + "/" + sourceDir); - - // get the res path. Always $PROJECT/res - element = resPath.createPathElement(); - element.setPath(path + "/" + SdkConstants.FD_RESOURCES); - - // get the libs path. Always $PROJECT/libs - element = libsPath.createPathElement(); - element.setPath(path + "/" + SdkConstants.FD_NATIVE_LIBS); - - // get the jars from it too - File libsFolder = new File(library, SdkConstants.FD_NATIVE_LIBS); - File[] jarFiles = libsFolder.listFiles(filter); - if (jarFiles != null) { - for (File jarFile : jarFiles) { - element = jarsPath.createPathElement(); - element.setPath(jarFile.getAbsolutePath()); - } - } - - // get the package from the manifest. - FileWrapper manifest = new FileWrapper(library, - SdkConstants.FN_ANDROID_MANIFEST_XML); - - try { - String value = AndroidManifest.getPackage(manifest); - if (value != null) { // aapt will complain if it's missing. - sb.append(';'); - sb.append(value); - } - } catch (Exception e) { - throw new BuildException(e); - } - } - } else { - System.out.println("No library dependencies.\n"); - } - - System.out.println("------------------\n"); - - // even with no libraries, always setup these so that various tasks in Ant don't complain - // (the task themselves can handle a ref to an empty Path) - antProject.addReference(AntConstants.PROP_PROJECT_LIBS_SRC_REF, sourcePath); - antProject.addReference(AntConstants.PROP_PROJECT_LIBS_JARS_REF, jarsPath); - antProject.addReference(AntConstants.PROP_PROJECT_LIBS_LIBS_REF, libsPath); - - // the rest is done only if there's a library. - if (sourcePath.list().length > 0) { - antProject.addReference(AntConstants.PROP_PROJECT_LIBS_RES_REF, resPath); - antProject.setProperty(AntConstants.PROP_PROJECT_LIBS_PKG, sb.toString()); - } - } - - /** - * Returns all the library dependencies of a given Ant project. - * @param antProject the Ant project - * @return a list of properties, sorted from highest priority to lowest. - */ - private ArrayList<File> getProjectLibraries(final Project antProject) { - ArrayList<File> libraries = new ArrayList<File>(); - File baseDir = antProject.getBaseDir(); - - // get the top level list of library dependencies. - ArrayList<File> topLevelLibraries = getDirectDependencies(baseDir, new IPropertySource() { - public String getProperty(String name) { - return antProject.getProperty(name); - } - }); - - // process the libraries in case they depend on other libraries. - resolveFullLibraryDependencies(topLevelLibraries, libraries); - - return libraries; - } - - /** - * Resolves a given list of libraries, finds out if they depend on other libraries, and - * returns a full list of all the direct and indirect dependencies in the proper order (first - * is higher priority when calling aapt). - * @param inLibraries the libraries to resolve - * @param outLibraries where to store all the libraries. - */ - private void resolveFullLibraryDependencies(ArrayList<File> inLibraries, - ArrayList<File> outLibraries) { - // loop in the inverse order to resolve dependencies on the libraries, so that if a library - // is required by two higher level libraries it can be inserted in the correct place - for (int i = inLibraries.size() - 1 ; i >= 0 ; i--) { - File library = inLibraries.get(i); - - // get the default.property file for it - final ProjectProperties defaultProp = ProjectProperties.load( - new FolderWrapper(library), PropertyType.DEFAULT); - - // get its libraries - ArrayList<File> dependencies = getDirectDependencies(library, new IPropertySource() { - public String getProperty(String name) { - return defaultProp.getProperty(name); - } - }); - - // resolve the dependencies for those libraries - resolveFullLibraryDependencies(dependencies, outLibraries); - - // and add the current one (if needed) in front (higher priority) - if (outLibraries.contains(library) == false) { - outLibraries.add(0, library); - } - } - } - - public interface IPropertySource { - String getProperty(String name); - } - - /** - * Returns the top level library dependencies of a given <var>source</var> representing a - * project properties. - * @param baseFolder the base folder of the project (to resolve relative paths) - * @param source a source of project properties. - */ - private ArrayList<File> getDirectDependencies(File baseFolder, IPropertySource source) { - ArrayList<File> libraries = new ArrayList<File>(); - - // first build the list. they are ordered highest priority first. - int index = 1; - while (true) { - String propName = ProjectProperties.PROPERTY_LIB_REF + Integer.toString(index++); - String rootPath = source.getProperty(propName); - - if (rootPath == null) { - break; - } - - try { - File library = new File(baseFolder, rootPath).getCanonicalFile(); - - // check for validity - File defaultProp = new File(library, PropertyType.DEFAULT.getFilename()); - if (defaultProp.isFile() == false) { - // error! - throw new BuildException(String.format( - "%1$s resolve to a path with no %2$s file for project %3$s", rootPath, - PropertyType.DEFAULT.getFilename(), baseFolder.getAbsolutePath())); - } - - if (libraries.contains(library) == false) { - System.out.println(String.format("%1$s: %2$s => %3$s", - baseFolder.getAbsolutePath(), rootPath, library.getAbsolutePath())); - - libraries.add(library); - } - } catch (IOException e) { - throw new BuildException("Failed to resolve library path: " + rootPath, e); - } - } - - return libraries; - } - - /** - * Returns the Ant version as a {@link DeweyDecimal} object. - * - * This is based on the implementation of - * org.apache.tools.ant.taskdefs.condition.AntVersion.getVersion() + * @param b unused. * - * @param antProject the current ant project. - * @return the ant version. + * @deprecated only present because the original {@link SetupTask} extends {@link ImportTask}. */ - private DeweyDecimal getVersion(Project antProject) { - char[] versionString = antProject.getProperty("ant.version").toCharArray(); - StringBuffer sb = new StringBuffer(); - boolean foundFirstDigit = false; - for (int i = 0; i < versionString.length; i++) { - if (Character.isDigit(versionString[i])) { - sb.append(versionString[i]); - foundFirstDigit = true; - } - if (versionString[i] == '.' && foundFirstDigit) { - sb.append(versionString[i]); - } - if (Character.isLetter(versionString[i]) && foundFirstDigit) { - break; - } - } - return new DeweyDecimal(sb.toString()); + @Deprecated + public void setImport(boolean b) { + // do nothing } + @Override + public void execute() throws BuildException { + throw new BuildException("\n\nError. You are using an obsolete build.xml\n" + + "You need to delete it and regenerate it using\n" + + "\tandroid update project\n"); + } } |