/* * 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; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; 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.PatternSet.NameEntry; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Task to execute aidl. *

* It expects 3 attributes:
* 'executable' ({@link Path} with a single path) for the location of the aidl executable
* 'framework' ({@link Path} with a single path) for the "preprocessed" file containing all the * parcelables exported by the framework
* 'genFolder' ({@link Path} with a single path) for the location of the gen folder. * * It also expects one or more inner elements called "source" which are identical to {@link Path} * elements. */ public class AidlExecTask extends Task { private String mExecutable; private String mFramework; private String mGenFolder; private final ArrayList mPaths = new ArrayList(); /** * Sets the value of the "executable" attribute. * @param executable the value. */ public void setExecutable(Path executable) { mExecutable = TaskHelper.checkSinglePath("executable", executable); } public void setFramework(Path value) { mFramework = TaskHelper.checkSinglePath("framework", value); } public void setGenFolder(Path value) { mGenFolder = TaskHelper.checkSinglePath("genFolder", value); } public Path createSource() { Path p = new Path(getProject()); mPaths.add(p); return p; } @Override public void execute() throws BuildException { if (mExecutable == null) { throw new BuildException("AidlExecTask's 'executable' is required."); } if (mFramework == null) { throw new BuildException("AidlExecTask's 'framework' is required."); } if (mGenFolder == null) { throw new BuildException("AidlExecTask's 'genFolder' is required."); } Project taskProject = getProject(); // build a list of all the source folders ArrayList sourceFolders = new ArrayList(); for (Path p : mPaths) { String[] values = p.list(); if (values != null) { sourceFolders.addAll(Arrays.asList(values)); } } // gather all the aidl files from all the source folders. Set sourceFiles = getFileListByExtension(taskProject, sourceFolders, "**/*.aidl"); if (sourceFiles.size() > 0) { System.out.println(String.format("Found %d aidl files.", sourceFiles.size())); } // go look for all dependency files in the gen folder. Set depFiles = getFileListByExtension(taskProject, mGenFolder, "**/*.d"); // parse all the dep files and keep the ones that are aidl and check if they require // compilation again. ArrayList toCompile = new ArrayList(); ArrayList toRemove = new ArrayList(); ArrayList depsToRemove = new ArrayList(); for (String depFile : depFiles) { DependencyGraph graph = new DependencyGraph(depFile, null /*watchPaths*/); // get the source file. it's the first item in the pre-reqs File sourceFile = graph.getFirstPrereq(); String sourceFilePath = sourceFile.getAbsolutePath(); // The gen folder may contain other dependency files not generated by aidl. // We only care if the first pre-rep is an aidl file. if (sourceFilePath.toLowerCase().endsWith(".aidl")) { // remove from the list of sourceFiles to mark as "processed" (but not compiled // yet, that'll be done by adding it to toCompile) if (sourceFiles.remove(sourceFilePath) == false) { // looks like the source file does not exist anymore! // we'll have to remove the output! Set outputFiles = graph.getTargets(); toRemove.addAll(outputFiles); // also need to remove the dep file. depsToRemove.add(depFile); } else if (graph.dependenciesHaveChanged(false /*printStatus*/)) { // need to recompile! toCompile.add(sourceFilePath); } } } // add to the list of files to compile, whatever is left in sourceFiles. Those are // new files that have never been compiled. toCompile.addAll(sourceFiles); if (toCompile.size() > 0) { System.out.println(String.format("Compiling %d aidl files.", toCompile.size())); for (String toCompilePath : toCompile) { ExecTask task = new ExecTask(); task.setProject(taskProject); task.setOwningTarget(getOwningTarget()); task.setExecutable(mExecutable); task.setTaskName("aidl"); task.setFailonerror(true); task.createArg().setValue("-p" + mFramework); task.createArg().setValue("-o" + mGenFolder); // add all the source folders as import in case an aidl file in a source folder // imports a parcelable from another source folder. for (String importFolder : sourceFolders) { task.createArg().setValue("-I" + importFolder); } // set auto dependency file creation task.createArg().setValue("-a"); task.createArg().setValue(toCompilePath); // execute it. task.execute(); } } else { System.out.println(String.format("No aidl files to compile.")); } if (toRemove.size() > 0) { System.out.println(String.format("%d obsolete output files to remove.", toRemove.size())); for (File toRemoveFile : toRemove) { if (toRemoveFile.delete() == false) { System.err.println("Failed to remove " + toRemoveFile.getAbsolutePath()); } } } // remove the dependency files that are obsolete if (depsToRemove.size() > 0) { System.out.println(String.format("%d obsolete dependency files to remove.", depsToRemove.size())); for (String path : depsToRemove) { if (new File(path).delete() == false) { System.err.println("Failed to remove " + path); } } } } private Set getFileListByExtension(Project taskProject, List sourceFolders, String filter) { HashSet sourceFiles = new HashSet(); for (String sourceFolder : sourceFolders) { sourceFiles.addAll(getFileListByExtension(taskProject, sourceFolder, filter)); } return sourceFiles; } private Set getFileListByExtension(Project taskProject, String sourceFolder, String filter) { HashSet sourceFiles = new HashSet(); // create a fileset to find all the files in the folder FileSet fs = new FileSet(); fs.setProject(taskProject); fs.setDir(new File(sourceFolder)); NameEntry include = fs.createInclude(); include.setName(filter); // loop through the results of the file set Iterator iter = fs.iterator(); while (iter.hasNext()) { sourceFiles.add(iter.next().toString()); } return sourceFiles; } }