/* * 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.Project; import org.apache.tools.ant.Task; 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.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; class MultiFilesTask extends Task { static enum DisplayType { FOUND, COMPILING, REMOVE_OUTPUT, REMOVE_DEP; } interface SourceProcessor { String getSourceFileExtension(); void process(String filePath, String sourceFolder, List sourceFolders, Project taskProject); void displayMessage(DisplayType type, int count); } protected void processFiles(SourceProcessor processor, List paths, String genFolder) { Project taskProject = getProject(); String extension = processor.getSourceFileExtension(); // build a list of all the source folders ArrayList sourceFolders = new ArrayList(); for (Path p : paths) { String[] values = p.list(); if (values != null) { sourceFolders.addAll(Arrays.asList(values)); } } // gather all the source files from all the source folders. Map sourceFiles = getFileListByExtension(taskProject, sourceFolders, "**/*." + extension); if (sourceFiles.size() > 0) { processor.displayMessage(DisplayType.FOUND, sourceFiles.size()); } // go look for all dependency files in the gen folder. This will have all dependency // files but we can filter them based on the first pre-req file. Map depFiles = getFileListByExtension(taskProject, genFolder, "**/*.d"); // parse all the dep files and keep the ones that are of the proper type and check if // they require compilation again. Map toCompile = new HashMap(); ArrayList toRemove = new ArrayList(); ArrayList depsToRemove = new ArrayList(); for (String depFile : depFiles.keySet()) { 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 this particular // processor. // We only care if the first pre-rep is of the right extension. if (sourceFilePath.toLowerCase().endsWith("." + extension)) { // remove from the list of sourceFiles to mark as "processed" (but not compiled // yet, that'll be done by adding it to toCompile) String sourceFolder = sourceFiles.get(sourceFilePath); if (sourceFolder == null) { // 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 { // Source file is present. remove it from the list as being processed. sourceFiles.remove(sourceFilePath); // check if it needs to be recompiled. if (graph.dependenciesHaveChanged(false /*printStatus*/)) { toCompile.put(sourceFilePath, sourceFolder); } } } } // add to the list of files to compile, whatever is left in sourceFiles. Those are // new files that have never been compiled. toCompile.putAll(sourceFiles); processor.displayMessage(DisplayType.COMPILING, toCompile.size()); if (toCompile.size() > 0) { for (Entry toCompilePath : toCompile.entrySet()) { processor.process(toCompilePath.getKey(), toCompilePath.getValue(), sourceFolders, taskProject); } } if (toRemove.size() > 0) { processor.displayMessage(DisplayType.REMOVE_OUTPUT, 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) { processor.displayMessage(DisplayType.REMOVE_DEP, toRemove.size()); for (String path : depsToRemove) { if (new File(path).delete() == false) { System.err.println("Failed to remove " + path); } } } } private Map getFileListByExtension(Project taskProject, List sourceFolders, String filter) { HashMap sourceFiles = new HashMap(); for (String sourceFolder : sourceFolders) { sourceFiles.putAll(getFileListByExtension(taskProject, sourceFolder, filter)); } return sourceFiles; } private Map getFileListByExtension(Project taskProject, String sourceFolder, String filter) { HashMap sourceFiles = new HashMap(); // 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.put(iter.next().toString(), sourceFolder); } return sourceFiles; } }