1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ant; 18 19 import org.apache.tools.ant.BuildException; 20 21 import java.io.File; 22 import java.io.FileNotFoundException; 23 import java.io.PrintStream; 24 import java.util.ArrayList; 25 import java.util.List; 26 import java.util.Set; 27 28 /** 29 * A base class for ant tasks that use a single dependency file to control (re)execution. 30 */ 31 public abstract class SingleDependencyTask extends BuildTypedTask { 32 33 private DependencyGraph mDependencies; 34 getExecTaskName()35 protected abstract String getExecTaskName(); 36 37 protected interface InputPathFactory { createPath(File file, Set<String> extensionsToCheck)38 InputPath createPath(File file, Set<String> extensionsToCheck); 39 } 40 41 private final static InputPathFactory sDefaultFactory = new InputPathFactory() { 42 @Override 43 public InputPath createPath(File file, Set<String> extensionsToCheck) { 44 return new InputPath(file, extensionsToCheck); 45 } 46 }; 47 48 /** 49 * Creates a list of {@link InputPath} from a list of {@link File} and an optional list of 50 * extensions. All the {@link InputPath} will share the same extension restrictions. 51 * @param paths the list of path 52 * @param extensionsToCheck A set of extensions. Only files with an extension in this set will 53 * be considered for a modification check. All deleted/created files will still be 54 * checked. If this is null, all files will be checked for modification date 55 * @return a list of {@link InputPath} 56 */ getInputPaths(List<File> paths, Set<String> extensionsToCheck, InputPathFactory factory)57 protected static List<InputPath> getInputPaths(List<File> paths, 58 Set<String> extensionsToCheck, InputPathFactory factory) { 59 List<InputPath> result = new ArrayList<InputPath>(paths.size()); 60 61 if (factory == null ) { 62 factory = sDefaultFactory; 63 } 64 65 for (File f : paths) { 66 result.add(factory.createPath(f, extensionsToCheck)); 67 } 68 69 return result; 70 } 71 72 /** 73 * Set up the dependency graph by passing it the location of the ".d" file, and the new input 74 * paths. 75 * @param dependencyFile path to the dependency file to use 76 * @param the new input paths for this new compilation. 77 * @return true if the dependency graph was successfully initialized 78 */ initDependencies(String dependencyFile, List<InputPath> inputPaths)79 protected boolean initDependencies(String dependencyFile, List<InputPath> inputPaths) { 80 if (hasBuildTypeChanged()) { 81 // we don't care about deps, we need to execute the task no matter what. 82 return true; 83 } 84 85 File depFile = new File(dependencyFile); 86 if (depFile.exists()) { 87 mDependencies = new DependencyGraph(dependencyFile, inputPaths); 88 return true; 89 } else { 90 return false; 91 } 92 } 93 94 /** 95 * Wrapper check to see if we need to execute this task at all 96 * @return true if the DependencyGraph reports that our prereqs or targets 97 * have changed since the last run 98 */ dependenciesHaveChanged()99 protected boolean dependenciesHaveChanged() { 100 if (hasBuildTypeChanged()) { 101 // if this is not a new build, display that build type change is forcing running 102 // the task. 103 if (isNewBuild() == false) { 104 String execName = getExecTaskName(); 105 if (execName == null) { 106 System.out.println( 107 "Current build type is different than previous build: forced task run."); 108 } else { 109 System.out.println( 110 "Current build type is different than previous build: forced " + 111 execName + " run."); 112 } 113 } 114 return true; 115 } 116 117 assert mDependencies != null : "Dependencies have not been initialized"; 118 return mDependencies.dependenciesHaveChanged(true /*printStatus*/); 119 } 120 generateDependencyFile(String depFilePath, List<InputPath> inputs, String outputFile)121 protected void generateDependencyFile(String depFilePath, 122 List<InputPath> inputs, String outputFile) { 123 File depFile = new File(depFilePath); 124 125 try { 126 PrintStream ps = new PrintStream(depFile); 127 128 // write the output file. 129 ps.print(outputFile); 130 ps.println(" : \\"); 131 132 //write the input files 133 int count = inputs.size(); 134 for (int i = 0 ; i < count ; i++) { 135 InputPath input = inputs.get(i); 136 File file = input.getFile(); 137 if (file.isDirectory()) { 138 writeContent(ps, file, input); 139 } else { 140 ps.print(file.getAbsolutePath()); 141 ps.println(" \\"); 142 } 143 } 144 145 ps.close(); 146 } catch (FileNotFoundException e) { 147 new BuildException(e); 148 } 149 } 150 writeContent(PrintStream ps, File file, InputPath input)151 private void writeContent(PrintStream ps, File file, InputPath input) { 152 if (input.ignores(file)) { 153 return; 154 } 155 156 File[] files = file.listFiles(); 157 if (files != null) { 158 for (File f : files) { 159 if (f.isDirectory()) { 160 writeContent(ps, f, input); 161 } else if (input.ignores(f) == false) { 162 ps.print(f.getAbsolutePath()); 163 ps.println(" \\"); 164 } 165 } 166 } 167 } 168 } 169