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 files to control (re)execution. 30 */ 31 public abstract class SingleDependencyTask extends BuildTypedTask { 32 33 private DependencyGraph mDependencies; 34 35 protected abstract String getExecTaskName(); 36 37 protected interface InputPathFactory { 38 InputPath createPath(File file, Set<String> extensionsToCheck); 39 } 40 41 private final static InputPathFactory sDefaultFactory = new InputPathFactory() { 42 public InputPath createPath(File file, Set<String> extensionsToCheck) { 43 return new InputPath(file, extensionsToCheck); 44 } 45 }; 46 47 /** 48 * Creates a list of {@link InputPath} from a list of {@link File} and an optional list of 49 * extensions. All the {@link InputPath} will share the same extension restrictions. 50 * @param paths the list of path 51 * @param extensionsToCheck A set of extensions. Only files with an extension in this set will 52 * be considered for a modification check. All deleted/created files will still be 53 * checked. If this is null, all files will be checked for modification date 54 * @return a list of {@link InputPath} 55 */ 56 protected static List<InputPath> getInputPaths(List<File> paths, 57 Set<String> extensionsToCheck, InputPathFactory factory) { 58 List<InputPath> result = new ArrayList<InputPath>(paths.size()); 59 60 if (factory == null ) { 61 factory = sDefaultFactory; 62 } 63 64 for (File f : paths) { 65 result.add(factory.createPath(f, extensionsToCheck)); 66 } 67 68 return result; 69 } 70 71 /** 72 * Set up the dependency graph by passing it the location of the ".d" file, and the new input 73 * paths. 74 * @param dependencyFile path to the dependency file to use 75 * @param the new input paths for this new compilation. 76 * @return true if the dependency graph was successfully initialized 77 */ 78 protected boolean initDependencies(String dependencyFile, List<InputPath> inputPaths) { 79 if (hasBuildTypeChanged()) { 80 // we don't care about deps, we need to execute the task no matter what. 81 return true; 82 } 83 84 File depFile = new File(dependencyFile); 85 if (depFile.exists()) { 86 mDependencies = new DependencyGraph(dependencyFile, inputPaths); 87 return true; 88 } else { 89 return false; 90 } 91 } 92 93 /** 94 * Wrapper check to see if we need to execute this task at all 95 * @return true if the DependencyGraph reports that our prereqs or targets 96 * have changed since the last run 97 */ 98 protected boolean dependenciesHaveChanged() { 99 if (hasBuildTypeChanged()) { 100 // if this is not a new build, display that build type change is forcing running 101 // the task. 102 if (isNewBuild() == false) { 103 String execName = getExecTaskName(); 104 if (execName == null) { 105 System.out.println( 106 "Current build type is different than previous build: forced task run."); 107 } else { 108 System.out.println( 109 "Current build type is different than previous build: forced " + 110 execName + " run."); 111 } 112 } 113 return true; 114 } 115 116 assert mDependencies != null : "Dependencies have not been initialized"; 117 return mDependencies.dependenciesHaveChanged(true /*printStatus*/); 118 } 119 120 protected void generateDependencyFile(String depFilePath, 121 List<InputPath> inputs, String outputFile) { 122 File depFile = new File(depFilePath); 123 124 try { 125 PrintStream ps = new PrintStream(depFile); 126 127 // write the output file. 128 ps.print(outputFile); 129 ps.println(" : \\"); 130 131 //write the input files 132 int count = inputs.size(); 133 for (int i = 0 ; i < count ; i++) { 134 InputPath input = inputs.get(i); 135 File file = input.getFile(); 136 if (file.isDirectory()) { 137 writeContent(ps, file, input); 138 } else { 139 ps.print(file.getAbsolutePath()); 140 ps.println(" \\"); 141 } 142 } 143 144 ps.close(); 145 } catch (FileNotFoundException e) { 146 new BuildException(e); 147 } 148 } 149 150 private void writeContent(PrintStream ps, File file, InputPath input) { 151 if (input.ignores(file)) { 152 return; 153 } 154 155 File[] files = file.listFiles(); 156 if (files != null) { 157 for (File f : files) { 158 if (f.isDirectory()) { 159 writeContent(ps, f, input); 160 } else if (input.ignores(f) == false) { 161 ps.print(f.getAbsolutePath()); 162 ps.println(" \\"); 163 } 164 } 165 } 166 } 167 } 168