aboutsummaryrefslogtreecommitdiffstats
path: root/anttasks
diff options
context:
space:
mode:
authorXavier Ducrohet <xav@android.com>2011-08-25 18:36:48 -0700
committerXavier Ducrohet <xav@android.com>2011-09-01 14:11:31 -0700
commit891cbf7552f98af2f0baaed069b5eb64de50c556 (patch)
treea73ffbfbad6dffd5f98c864fde04fae221c34612 /anttasks
parent50b3e57fa887dc7182facfb178ef842103aeeaf3 (diff)
downloadsdk-891cbf7552f98af2f0baaed069b5eb64de50c556.zip
sdk-891cbf7552f98af2f0baaed069b5eb64de50c556.tar.gz
sdk-891cbf7552f98af2f0baaed069b5eb64de50c556.tar.bz2
Add proper dependency support in the dex step of the Ant-based build.
The dex step now generates a dependency file that is reused during following builds to check whether dex should occur. Also optimized the part that figures out if any dependencies have been modified/have gone missing. Change-Id: I7f6e915fc7b571ad973260daa506badced3a9c2a
Diffstat (limited to 'anttasks')
-rw-r--r--anttasks/src/com/android/ant/AaptExecTask.java28
-rw-r--r--anttasks/src/com/android/ant/AidlExecTask.java5
-rw-r--r--anttasks/src/com/android/ant/BaseTask.java68
-rw-r--r--anttasks/src/com/android/ant/DependencyGraph.java277
-rw-r--r--anttasks/src/com/android/ant/DexExecTask.java176
5 files changed, 440 insertions, 114 deletions
diff --git a/anttasks/src/com/android/ant/AaptExecTask.java b/anttasks/src/com/android/ant/AaptExecTask.java
index 3e2350f..2c242d3 100644
--- a/anttasks/src/com/android/ant/AaptExecTask.java
+++ b/anttasks/src/com/android/ant/AaptExecTask.java
@@ -323,32 +323,40 @@ public final class AaptExecTask extends BaseTask {
// Get whether we have libraries
Object libResRef = taskProject.getReference(mProjectLibrariesResName);
- // Set up our folders to check for changed files
- ArrayList<File> watchPaths = new ArrayList<File>();
- // We need to watch for changes in the main project res folder
+ // Set up our input paths that matter for dependency checks
+ ArrayList<File> inputPaths = new ArrayList<File>();
+
+ // the project res folder is an input path of course
for (Path pathList : mResources) {
for (String path : pathList.list()) {
- watchPaths.add(new File(path));
+ inputPaths.add(new File(path));
}
}
- // and if libraries exist, in their res folders
+
+ // as is its AndroidManifest.xml
+ if (mManifest != null) {
+ inputPaths.add(new File(mManifest));
+ }
+
+ // and if libraries exist, their res folders folders too.
if (libResRef instanceof Path) {
for (String path : ((Path)libResRef).list()) {
- watchPaths.add(new File(path));
+ inputPaths.add(new File(path));
}
}
- // If we're here to generate a .ap_ file we need to watch assets as well
+
+ // If we're here to generate a .ap_ file we need to use assets as an input path as well.
if (!generateRClass) {
File assetsDir = new File(mAssets);
if (mAssets != null && assetsDir.isDirectory()) {
- watchPaths.add(assetsDir);
+ inputPaths.add(assetsDir);
}
}
// Now we figure out what we need to do
if (generateRClass) {
// Check to see if our dependencies have changed. If not, then skip
- if (initDependencies(mRFolder + File.separator + "R.java.d", watchPaths)
+ if (initDependencies(mRFolder + File.separator + "R.java.d", inputPaths)
&& dependenciesHaveChanged() == false) {
System.out.println("No changed resources. R.java and Manifest.java untouched.");
return;
@@ -362,7 +370,7 @@ public final class AaptExecTask extends BaseTask {
dependencyFilePath += ".d";
// Check to see if our dependencies have changed
- if (initDependencies(dependencyFilePath , watchPaths)
+ if (initDependencies(dependencyFilePath, inputPaths)
&& dependenciesHaveChanged() == false) {
System.out.println("No changed resources or assets. " + mApkName
+ " remains untouched");
diff --git a/anttasks/src/com/android/ant/AidlExecTask.java b/anttasks/src/com/android/ant/AidlExecTask.java
index 98cac9b..1fd5a61 100644
--- a/anttasks/src/com/android/ant/AidlExecTask.java
+++ b/anttasks/src/com/android/ant/AidlExecTask.java
@@ -114,8 +114,7 @@ public class AidlExecTask extends Task {
DependencyGraph graph = new DependencyGraph(depFile, null /*watchPaths*/);
// get the source file. it's the first item in the pre-reqs
- List<File> preReqs = graph.getPrereqs();
- File sourceFile = preReqs.get(0);
+ File sourceFile = graph.getFirstPrereq();
String sourceFilePath = sourceFile.getAbsolutePath();
// The gen folder may contain other dependency files not generated by aidl.
@@ -126,7 +125,7 @@ public class AidlExecTask extends Task {
if (sourceFiles.remove(sourceFilePath) == false) {
// looks like the source file does not exist anymore!
// we'll have to remove the output!
- List<File> outputFiles = graph.getTargets();
+ Set<File> outputFiles = graph.getTargets();
toRemove.addAll(outputFiles);
// also need to remove the dep file.
diff --git a/anttasks/src/com/android/ant/BaseTask.java b/anttasks/src/com/android/ant/BaseTask.java
index 68dd6b5..4eb954b 100644
--- a/anttasks/src/com/android/ant/BaseTask.java
+++ b/anttasks/src/com/android/ant/BaseTask.java
@@ -20,8 +20,10 @@ import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import java.io.File;
-import java.util.ArrayList;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
/**
@@ -59,18 +61,14 @@ public abstract class BaseTask extends Task {
}
}
- @Override
- public void execute() throws BuildException {
-
- }
-
/**
- * Set up the dependency graph by passing it the location of the ".d" file
+ * Set up the dependency graph by passing it the location of the ".d" file, and the new input
+ * paths.
* @param dependencyFile path to the dependency file to use
- * @param watchPaths a list of folders to watch for new files
+ * @param the new input paths for this new compilation.
* @return true if the dependency graph was successfully initialized
*/
- protected boolean initDependencies(String dependencyFile, ArrayList<File> watchPaths) {
+ protected boolean initDependencies(String dependencyFile, List<File> inputPaths) {
if (mBuildType != null && mBuildType.equals(mPreviousBuildType) == false) {
// we don't care about deps, we need to execute the task no matter what.
return true;
@@ -78,7 +76,7 @@ public abstract class BaseTask extends Task {
File depFile = new File(dependencyFile);
if (depFile.exists()) {
- mDependencies = new DependencyGraph(dependencyFile, watchPaths);
+ mDependencies = new DependencyGraph(dependencyFile, inputPaths);
return true;
} else {
return false;
@@ -94,9 +92,12 @@ public abstract class BaseTask extends Task {
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.");
+ 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.");
+ System.out.println(
+ "Current build type is different than previous build: forced " +
+ execName + " run.");
}
return true;
}
@@ -105,4 +106,47 @@ public abstract class BaseTask extends Task {
return mDependencies.dependenciesHaveChanged(mRestrictTouchedExtensionsTo,
true /*printStatus*/);
}
+
+ protected void generateDependencyFile(String depFilePath,
+ List<File> inputs, String outputFile) {
+ File file = new File(depFilePath);
+
+ try {
+ PrintStream ps = new PrintStream(file);
+
+ // write the output file.
+ ps.print(outputFile);
+ ps.println(" : \\");
+
+ //write the input files
+ int count = inputs.size();
+ for (int i = 0 ; i < count ; i++) {
+ File input = inputs.get(i);
+ if (input.isDirectory()) {
+ writeContent(ps, input);
+ } else {
+ ps.print(input.getAbsolutePath());
+ ps.println(" \\");
+ }
+ }
+
+ ps.close();
+ } catch (FileNotFoundException e) {
+ new BuildException(e);
+ }
+ }
+
+ private void writeContent(PrintStream ps, File input) {
+ File[] files = input.listFiles();
+ if (files != null) {
+ for (File f : files) {
+ if (f.isDirectory()) {
+ writeContent(ps, f);
+ } else {
+ ps.print(f.getAbsolutePath());
+ ps.println(" \\");
+ }
+ }
+ }
+ }
}
diff --git a/anttasks/src/com/android/ant/DependencyGraph.java b/anttasks/src/com/android/ant/DependencyGraph.java
index 11c09e4..7f9c65a 100644
--- a/anttasks/src/com/android/ant/DependencyGraph.java
+++ b/anttasks/src/com/android/ant/DependencyGraph.java
@@ -16,13 +16,15 @@
package com.android.ant;
+import org.apache.tools.ant.BuildException;
+
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -33,15 +35,20 @@ import java.util.Set;
*/
public class DependencyGraph {
+ private static enum DependencyStatus {
+ NONE, NEW_FILE, UPDATED_FILE, MISSING_FILE, ERROR;
+ }
+
// Files that we know about from the dependency file
- private List<File> mTargets = Collections.emptyList();
- private List<File> mPrereqs = mTargets;
+ private Set<File> mTargets = Collections.emptySet();
+ private Set<File> mPrereqs = mTargets;
+ private File mFirstPrereq = null;
private boolean mMissingDepFile = false;
private long mDepFileLastModified;
- private final ArrayList<File> mWatchPaths;
+ private final List<File> mNewInputs;
- public DependencyGraph(String dependencyFilePath, ArrayList<File> watchPaths) {
- mWatchPaths = watchPaths;
+ public DependencyGraph(String dependencyFilePath, List<File> newInputPaths) {
+ mNewInputs = newInputPaths;
parseDependencyFile(dependencyFilePath);
}
@@ -55,40 +62,70 @@ public class DependencyGraph {
* prerequisite files have been modified since the last target generation.
*/
public boolean dependenciesHaveChanged(Set<String> extensionsToCheck, boolean printStatus) {
- boolean missingPrereq = missingPrereqFile();
- boolean newPrereq = newPrereqFile();
- boolean missingTarget = missingTargetFile();
- boolean modPrereq = modifiedPrereq(extensionsToCheck);
-
- if (printStatus) {
- if (mMissingDepFile) {
- System.out.println("No Dependency File Found");
- }
- if (missingPrereq) {
- System.out.println("Found Deleted Prereq File");
- }
- if (newPrereq) {
- System.out.println("Found New Prereq File");
- }
- if (missingTarget) {
+ // If no dependency file has been set up, then we'll just return true
+ // if we have a dependency file, we'll check to see what's been changed
+ if (mMissingDepFile) {
+ System.out.println("No Dependency File Found");
+ return true;
+ }
+
+ // check for missing output first
+ if (missingTargetFile()) {
+ if (printStatus) {
System.out.println("Found Deleted Target File");
}
- if (modPrereq) {
- System.out.println("Found Modified Prereq File");
- }
+ return true;
}
- // If no dependency file has been set up, then we'll just return true
- // if we have a dependency file, we'll check to see what's been changed
- return mMissingDepFile || missingPrereq || newPrereq || missingTarget || modPrereq;
+ // get the timestamp of the oldest target.
+ long oldestTarget = getOutputLastModified();
+
+ // first look through the input folders and look for new files or modified files.
+ DependencyStatus status = checkInputs(extensionsToCheck, oldestTarget);
+
+ // this can't find missing files. This is done later.
+ switch (status) {
+ case ERROR:
+ throw new BuildException();
+ case NEW_FILE:
+ if (printStatus) {
+ System.out.println("Found new input file");
+ }
+ return true;
+ case UPDATED_FILE:
+ if (printStatus) {
+ System.out.println("Found modified input file");
+ }
+ return true;
+ }
+
+ // now do a full check on the remaining files.
+ status = checkPrereqFiles(extensionsToCheck, oldestTarget);
+ // this can't find new input files. This is done above.
+ switch (status) {
+ case ERROR:
+ throw new BuildException();
+ case MISSING_FILE:
+ if (printStatus) {
+ System.out.println("Found deleted input file");
+ }
+ return true;
+ case UPDATED_FILE:
+ if (printStatus) {
+ System.out.println("Found modified input file");
+ }
+ return true;
+ }
+
+ return false;
}
- public List<File> getTargets() {
- return mTargets;
+ public Set<File> getTargets() {
+ return Collections.unmodifiableSet(mTargets);
}
- public List<File> getPrereqs() {
- return mPrereqs;
+ public File getFirstPrereq() {
+ return mFirstPrereq;
}
/**
@@ -144,79 +181,157 @@ public class DependencyGraph {
prereqs = files[1].trim().split(" ");
}
- mTargets = new ArrayList<File>(targets.length);
+ mTargets = new HashSet<File>(targets.length);
for (String path : targets) {
if (path.length() > 0) {
mTargets.add(new File(path));
}
}
- mTargets = Collections.unmodifiableList(mTargets);
- mPrereqs = new ArrayList<File>(prereqs.length);
+
+ mPrereqs = new HashSet<File>(prereqs.length);
for (String path : prereqs) {
if (path.length() > 0) {
- mPrereqs.add(new File(path));
+ File f = new File(path);
+ if (mFirstPrereq == null) {
+ mFirstPrereq = f;
+ }
+ mPrereqs.add(f);
}
}
- mPrereqs = Collections.unmodifiableList(mPrereqs);
}
/**
- * Check all the folders we know about to see if there have been new
- * files added to them.
- * @return true if a new file is encountered in the dependency folders
+ * Check all the input files and folders to see if there have been new
+ * files added to them or if any of the existing files have been modified.
+ *
+ * This looks at the input paths, not at the list of known prereq. Therefore this
+ * will not find missing files. It will however remove processed files from the
+ * prereq file list so that we can process those in a 2nd step.
+ *
+ * This should be followed by a call to {@link #checkPrereqFiles(long)} which
+ * will process the remaining files in the prereq list.
+ *
+ * If a change is found, this will return immediatly with either
+ * {@link DependencyStatus#NEW_FILE} or {@link DependencyStatus#UPDATED_FILE}.
+ *
+ * @param extensionsToCheck a set of extensions. Only files with an extension in this set will
+ * be considered for a modification check. All deleted/created files will still be
+ * checked. If this is null, all files will be checked for modification date
+ * @param oldestTarget the timestamp of the oldest output file to compare against.
+ *
+ * @return the status of the file in the watched folders.
+ *
*/
- private boolean newPrereqFile() {
- if (mWatchPaths != null) {
- for (File dir : mWatchPaths) {
- if (newFileInTree(dir)) {
- return true;
+ private DependencyStatus checkInputs(Set<String> extensionsToCheck, long oldestTarget) {
+ if (mNewInputs != null) {
+ for (File input : mNewInputs) {
+ if (input.isDirectory()) {
+ DependencyStatus status = checkInputFolder(input, extensionsToCheck,
+ oldestTarget);
+ if (status != DependencyStatus.NONE) {
+ return status;
+ }
+ } else if (input.isFile()) {
+ DependencyStatus status = checkInputFile(input, extensionsToCheck,
+ oldestTarget);
+ if (status != DependencyStatus.NONE) {
+ return status;
+ }
}
}
}
+
// If we make it all the way through our directories we're good.
- return false;
+ return DependencyStatus.NONE;
}
/**
* Check all the files in the tree under root and check to see if the files are
- * listed under the dependencies. Recurses into subdirs.
- * @param root the root of the file tree to search through
- * @return true if a file is encountered in the tree that is not in our list of prereqs
+ * listed under the dependencies, or if they have been modified. Recurses into subdirs.
+ *
+ * @param rootFolder the folder to search through.
+ * @param extensionsToCheck a set of extensions. Only files with an extension in this set will
+ * be considered for a modification check. All deleted/created files will still be
+ * checked. If this is null, all files will be checked for modification date
+ * @param oldestTarget the timestamp of the oldest output file to compare against.
+ *
+ * @return the status of the file in the folder.
*/
- private boolean newFileInTree(File root) {
- File[] files = root.listFiles();
+ private DependencyStatus checkInputFolder(File rootFolder, Set<String> extensionsToCheck,
+ long oldestTarget) {
+ File[] files = rootFolder.listFiles();
if (files == null) {
- System.err.println("ERROR " + root.toString() + " is not a dir or can't be read");
- return false;
+ System.err.println("ERROR " + rootFolder.toString() + " is not a dir or can't be read");
+ return DependencyStatus.ERROR;
}
// Loop through files in this folder
for (File file : files) {
// If this is a directory, recurse into it
if (file.isDirectory()) {
- if (newFileInTree(file)) {
- return true;
+ DependencyStatus status = checkInputFolder(file, extensionsToCheck, oldestTarget);
+ if (status != DependencyStatus.NONE) {
+ return status;
+ }
+ } else if (file.isFile()) {
+ DependencyStatus status = checkInputFile(file, extensionsToCheck, oldestTarget);
+ if (status != DependencyStatus.NONE) {
+ return status;
}
- } else if (file.isFile() && mPrereqs.contains(file) == false) {
- return true;
}
}
// If we got to here then we didn't find anything interesting
- return false;
+ return DependencyStatus.NONE;
+ }
+
+ private DependencyStatus checkInputFile(File file, Set<String> extensionsToCheck,
+ long oldestTarget) {
+ // if it's a file, remove it from the list of prereqs.
+ // This way if files in this folder don't trigger a build we'll have less
+ // files to go through manually
+ if (mPrereqs.remove(file) == false) {
+ // turns out this is a new file!
+ return DependencyStatus.NEW_FILE;
+ } else {
+ // check the time stamp on this file if it's a file we care about based on the
+ // list of extensions to check.
+ if (extensionsToCheck == null || extensionsToCheck.contains(getExtension(file))) {
+ if (file.lastModified() > oldestTarget) {
+ return DependencyStatus.UPDATED_FILE;
+ }
+ }
+ }
+
+ return DependencyStatus.NONE;
}
/**
- * Check all the prereq files we know about to make sure they're still there
- * @return true if any of the prereq files are missing.
+ * Check all the prereq files we know about to make sure they're still there, or that they
+ * haven't been modified since the last build.
+ *
+ * @param extensionsToCheck a set of extensions. Only files with an extension in this set will
+ * be considered for a modification check. All deleted/created files will still be
+ * checked. If this is null, all files will be checked for modification date
+ *
+ * @return the status of the files
*/
- private boolean missingPrereqFile() {
+ private DependencyStatus checkPrereqFiles(Set<String> extensionsToCheck, long oldestTarget) {
// Loop through our prereq files and make sure they still exist
for (File prereq : mPrereqs) {
if (prereq.exists() == false) {
- return true;
+ return DependencyStatus.MISSING_FILE;
+ }
+
+ // check the time stamp on this file if it's a file we care about based on the
+ // list of extensions to check.
+ if (extensionsToCheck == null || extensionsToCheck.contains(getExtension(prereq))) {
+ if (prereq.lastModified() > oldestTarget) {
+ return DependencyStatus.UPDATED_FILE;
+ }
}
}
- // If we get this far, then all our targets are okay
- return false;
+
+ // If we get this far, then all our prereq are okay
+ return DependencyStatus.NONE;
}
/**
@@ -235,12 +350,10 @@ public class DependencyGraph {
}
/**
- * Check to see if any of the prerequisite files have been modified since
- * the targets were last updated.
- * @return true if the latest prerequisite modification is after the oldest
- * target modification.
+ * Returns the earliest modification time stamp from all the output targets. If there
+ * are no known target, the dependency file time stamp is returned.
*/
- private boolean modifiedPrereq(Set<String> extensionsToCheck) {
+ private long getOutputLastModified() {
// Find the oldest target
long oldestTarget = Long.MAX_VALUE;
// if there's no output, then compare to the time of the dependency file.
@@ -254,20 +367,7 @@ public class DependencyGraph {
}
}
- // Find the newest prerequisite
- long newestPrereq = 0;
- for (File prereq : mPrereqs) {
- // If we have a list of extensions that we need to restrict ourselves to, only
- // consider this file if it has that extension.
- if (extensionsToCheck == null || extensionsToCheck.contains(getExtension(prereq))) {
- if (prereq.lastModified() > newestPrereq) {
- newestPrereq = prereq.lastModified();
- }
- }
- }
-
- // And return the comparison
- return newestPrereq > oldestTarget;
+ return oldestTarget;
}
/**
@@ -296,11 +396,11 @@ public class DependencyGraph {
}
/**
- * Gets the extension (if present) on a file by looking at the filename
- * @param file the file to get the extension of
- * @return the extension if present, or the empty string if the filename doesn't have
- * and extension.
- */
+ * Gets the extension (if present) on a file by looking at the filename
+ * @param file the file to get the extension of
+ * @return the extension if present, or the empty string if the filename doesn't have
+ * and extension.
+ */
private static String getExtension(File file) {
String filename = file.getName();
if (filename.lastIndexOf('.') == -1) {
@@ -309,5 +409,4 @@ public class DependencyGraph {
// Don't include the leading '.' in the extension
return filename.substring(filename.lastIndexOf('.') + 1);
}
-
}
diff --git a/anttasks/src/com/android/ant/DexExecTask.java b/anttasks/src/com/android/ant/DexExecTask.java
new file mode 100644
index 0000000..182ef84
--- /dev/null
+++ b/anttasks/src/com/android/ant/DexExecTask.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2011 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 org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.ExecTask;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.resources.FileResource;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Custom task to execute dx while handling dependencies.
+ */
+public class DexExecTask extends BaseTask {
+
+ private String mExecutable;
+ private String mOutput;
+ private boolean mVerbose = false;
+ private boolean mNoLocals = false;
+ private List<Path> mPathInputs;
+ private List<FileSet> mFileSetInputs;
+
+
+ /**
+ * Sets the value of the "executable" attribute.
+ * @param executable the value.
+ */
+ public void setExecutable(Path executable) {
+ mExecutable = TaskHelper.checkSinglePath("executable", executable);
+ }
+
+ /**
+ * Sets the value of the "verbose" attribute.
+ * @param verbose the value.
+ */
+ public void setVerbose(boolean verbose) {
+ mVerbose = verbose;
+ }
+
+ /**
+ * Sets the value of the "output" attribute.
+ * @param output the value.
+ */
+ public void setOutput(Path output) {
+ mOutput = TaskHelper.checkSinglePath("output", output);
+ }
+
+ /**
+ * Sets the value of the "nolocals" attribute.
+ * @param verbose the value.
+ */
+ public void setNoLocals(boolean nolocals) {
+ mNoLocals = nolocals;
+ }
+
+ /**
+ * Returns an object representing a nested <var>path</var> element.
+ */
+ public Object createPath() {
+ if (mPathInputs == null) {
+ mPathInputs = new ArrayList<Path>();
+ }
+
+ Path path = new Path(getProject());
+ mPathInputs.add(path);
+
+ return path;
+ }
+
+ /**
+ * Returns an object representing a nested <var>path</var> element.
+ */
+ public Object createFileSet() {
+ if (mFileSetInputs == null) {
+ mFileSetInputs = new ArrayList<FileSet>();
+ }
+
+ FileSet fs = new FileSet();
+ fs.setProject(getProject());
+ mFileSetInputs.add(fs);
+
+ return fs;
+ }
+
+
+ @Override
+ public void execute() throws BuildException {
+
+ // get all input paths
+ List<File> inputPaths = new ArrayList<File>();
+ if (mPathInputs != null) {
+ for (Path pathList : mPathInputs) {
+ for (String path : pathList.list()) {
+ inputPaths.add(new File(path));
+ }
+ }
+ }
+
+ if (mFileSetInputs != null) {
+ for (FileSet fs : mFileSetInputs) {
+ Iterator<?> iter = fs.iterator();
+ while (iter.hasNext()) {
+ FileResource fr = (FileResource) iter.next();
+ inputPaths.add(fr.getFile());
+ }
+ }
+ }
+
+ // figure out the path to the dependency file.
+ String depFile = mOutput + ".d";
+
+ if (initDependencies(depFile, inputPaths) && dependenciesHaveChanged() == false) {
+ System.out.println(
+ "No new compiled code. No need to convert bytecode to dalvik format.");
+ return;
+ }
+
+ System.out.println(String.format(
+ "Converting compiled files and external libraries into %1$s...", mOutput));
+
+ ExecTask task = new ExecTask();
+ task.setProject(getProject());
+ task.setOwningTarget(getOwningTarget());
+ task.setExecutable(mExecutable);
+ task.setTaskName(getExecTaskName());
+ task.setFailonerror(true);
+
+ task.createArg().setValue("--dex");
+
+ if (mNoLocals) {
+ task.createArg().setValue("--no-locals");
+ }
+
+ if (mVerbose) {
+ task.createArg().setValue("--verbose");
+ }
+
+ task.createArg().setValue("--output");
+ task.createArg().setValue(mOutput);
+
+
+ for (File f :inputPaths) {
+ task.createArg().setValue(f.getAbsolutePath());
+ }
+
+ // execute it.
+ task.execute();
+
+ // generate the dependency file.
+ generateDependencyFile(depFile, inputPaths, mOutput);
+ }
+
+ @Override
+ protected String getExecTaskName() {
+ return "dx";
+ }
+}