1065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin/* 2065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * Copyright (C) 2011 The Android Open Source Project 3065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * 4065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * Licensed under the Apache License, Version 2.0 (the "License"); 5065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * you may not use this file except in compliance with the License. 6065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * You may obtain a copy of the License at 7065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * 8065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * http://www.apache.org/licenses/LICENSE-2.0 9065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * 10065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * Unless required by applicable law or agreed to in writing, software 11065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * distributed under the License is distributed on an "AS IS" BASIS, 12065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * See the License for the specific language governing permissions and 14065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * limitations under the License. 15065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin */ 16065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 17065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskinpackage com.android.ant; 18065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 19f92c116240bc645a89b12975dd438a46645abe88Xavier Ducrohetimport com.google.common.base.Charsets; 20f92c116240bc645a89b12975dd438a46645abe88Xavier Ducrohetimport com.google.common.io.Files; 21f92c116240bc645a89b12975dd438a46645abe88Xavier Ducrohet 22891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohetimport org.apache.tools.ant.BuildException; 23891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 24065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskinimport java.io.File; 25065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskinimport java.io.IOException; 26065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskinimport java.util.Collections; 27891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohetimport java.util.HashSet; 2850b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohetimport java.util.List; 29065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskinimport java.util.Set; 30065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 31065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin/** 32065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * This class takes care of dependency tracking for all targets and prerequisites listed in 33065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * a single dependency file. A dependency graph always has a dependency file associated with it 34065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * for the duration of its lifetime 35065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin */ 36065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskinpublic class DependencyGraph { 37065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 38e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet private final static boolean DEBUG = false; 39e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet 40891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet private static enum DependencyStatus { 41891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet NONE, NEW_FILE, UPDATED_FILE, MISSING_FILE, ERROR; 42891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 43891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 44065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // Files that we know about from the dependency file 45891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet private Set<File> mTargets = Collections.emptySet(); 46891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet private Set<File> mPrereqs = mTargets; 47891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet private File mFirstPrereq = null; 4850b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet private boolean mMissingDepFile = false; 4950b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet private long mDepFileLastModified; 500fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet private final List<InputPath> mNewInputs; 510fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet 520fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet public DependencyGraph(String dependencyFilePath, List<InputPath> newInputPaths) { 53891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet mNewInputs = newInputPaths; 54065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin parseDependencyFile(dependencyFilePath); 55065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 56065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 57065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin /** 58065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * Check all the dependencies to see if anything has changed. 590fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet * 6050b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet * @param printStatus will print to {@link System#out} the dependencies status. 61065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * @return true if new prerequisites have appeared, target files are missing or if 62065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * prerequisite files have been modified since the last target generation. 63065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin */ 640fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet public boolean dependenciesHaveChanged(boolean printStatus) { 65891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // If no dependency file has been set up, then we'll just return true 66891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // if we have a dependency file, we'll check to see what's been changed 67891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (mMissingDepFile) { 68891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet System.out.println("No Dependency File Found"); 69891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return true; 70891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 71891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 72891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // check for missing output first 73891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (missingTargetFile()) { 74891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (printStatus) { 7550b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet System.out.println("Found Deleted Target File"); 7650b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet } 77891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return true; 78065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 7950b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet 800fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet // get the time stamp of the oldest target. 81891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet long oldestTarget = getOutputLastModified(); 82891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 83891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // first look through the input folders and look for new files or modified files. 840fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet DependencyStatus status = checkInputs(oldestTarget); 85891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 86891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // this can't find missing files. This is done later. 87891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet switch (status) { 88891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet case ERROR: 89891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet throw new BuildException(); 90891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet case NEW_FILE: 91891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (printStatus) { 92891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet System.out.println("Found new input file"); 93891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 94891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return true; 95891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet case UPDATED_FILE: 96891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (printStatus) { 97891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet System.out.println("Found modified input file"); 98891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 99891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return true; 100891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 101891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 102891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // now do a full check on the remaining files. 1030fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet status = checkPrereqFiles(oldestTarget); 104891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // this can't find new input files. This is done above. 105891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet switch (status) { 106891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet case ERROR: 107891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet throw new BuildException(); 108891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet case MISSING_FILE: 109891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (printStatus) { 110891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet System.out.println("Found deleted input file"); 111891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 112891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return true; 113891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet case UPDATED_FILE: 114891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (printStatus) { 115891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet System.out.println("Found modified input file"); 116891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 117891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return true; 118891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 119891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 120891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return false; 12150b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet } 12250b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet 123891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet public Set<File> getTargets() { 124891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return Collections.unmodifiableSet(mTargets); 12550b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet } 12650b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet 127891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet public File getFirstPrereq() { 128891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return mFirstPrereq; 129065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 130065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 131065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin /** 132065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * Parses the given dependency file and stores the file paths 133065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * 134065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * @param dependencyFilePath the dependency file 135065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin */ 136065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin private void parseDependencyFile(String dependencyFilePath) { 13750b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet // first check if the dependency file is here. 13850b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet File depFile = new File(dependencyFilePath); 13950b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet if (depFile.isFile() == false) { 14050b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet mMissingDepFile = true; 14150b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet return; 14250b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet } 14350b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet 14450b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet // get the modification time of the dep file as we may need it later 14550b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet mDepFileLastModified = depFile.lastModified(); 14650b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet 147065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // Read in our dependency file 148f92c116240bc645a89b12975dd438a46645abe88Xavier Ducrohet List<String> content = readFile(depFile); 149065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin if (content == null) { 150065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin System.err.println("ERROR: Couldn't read " + dependencyFilePath); 151065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin return; 152065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 153065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 154065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // The format is something like: 155065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // output1 output2 [...]: dep1 dep2 [...] 156065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // expect it's likely split on several lines. So let's move it back on a single line 157065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // first 158f92c116240bc645a89b12975dd438a46645abe88Xavier Ducrohet StringBuilder sb = new StringBuilder(); 159f92c116240bc645a89b12975dd438a46645abe88Xavier Ducrohet for (String line : content) { 160065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin line = line.trim(); 161065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin if (line.endsWith("\\")) { 162065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin line = line.substring(0, line.length() - 1); 163065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 164065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin sb.append(line); 165065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 166065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 167065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // split the left and right part 168065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin String[] files = sb.toString().split(":"); 169065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 170065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // get the target files: 171065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin String[] targets = files[0].trim().split(" "); 172065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 173065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin String[] prereqs = {}; 174065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // Check to make sure our dependency file is okay 175065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin if (files.length < 1) { 176065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin System.err.println( 177065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin "Warning! Dependency file does not list any prerequisites after ':' "); 178065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } else { 179065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // and the prerequisite files: 180065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin prereqs = files[1].trim().split(" "); 181065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 182065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 183891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet mTargets = new HashSet<File>(targets.length); 184065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin for (String path : targets) { 18550b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet if (path.length() > 0) { 18650b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet mTargets.add(new File(path)); 18750b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet } 188065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 189891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 190891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet mPrereqs = new HashSet<File>(prereqs.length); 191065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin for (String path : prereqs) { 19250b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet if (path.length() > 0) { 193e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet if (DEBUG) { 194e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet System.out.println("PREREQ: " + path); 195e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet } 196891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet File f = new File(path); 197891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (mFirstPrereq == null) { 198891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet mFirstPrereq = f; 199891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 200891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet mPrereqs.add(f); 20150b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet } 202065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 203065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 204065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 205065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin /** 206891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * Check all the input files and folders to see if there have been new 207891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * files added to them or if any of the existing files have been modified. 208891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * 209891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * This looks at the input paths, not at the list of known prereq. Therefore this 210891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * will not find missing files. It will however remove processed files from the 211891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * prereq file list so that we can process those in a 2nd step. 212891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * 213891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * This should be followed by a call to {@link #checkPrereqFiles(long)} which 214891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * will process the remaining files in the prereq list. 215891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * 216a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet * If a change is found, this will return immediately with either 217891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * {@link DependencyStatus#NEW_FILE} or {@link DependencyStatus#UPDATED_FILE}. 218891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * 219891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * @param oldestTarget the timestamp of the oldest output file to compare against. 220891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * 221891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * @return the status of the file in the watched folders. 222891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * 223065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin */ 2240fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet private DependencyStatus checkInputs(long oldestTarget) { 225891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (mNewInputs != null) { 2260fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet for (InputPath input : mNewInputs) { 227a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet File file = input.getFile(); 228a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet if (file.isDirectory()) { 229a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet DependencyStatus status = checkInputFolder(file, input, oldestTarget); 230891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (status != DependencyStatus.NONE) { 231891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return status; 232891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 233a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet } else if (file.isFile()) { 234a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet DependencyStatus status = checkInputFile(file, input, oldestTarget); 235891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (status != DependencyStatus.NONE) { 236891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return status; 237891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 23850b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet } 239065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 240065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 241891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 242065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // If we make it all the way through our directories we're good. 243891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return DependencyStatus.NONE; 244065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 245065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 246065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin /** 247065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * Check all the files in the tree under root and check to see if the files are 248891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * listed under the dependencies, or if they have been modified. Recurses into subdirs. 249891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * 250a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet * @param folder the folder to search through. 251a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet * @param inputFolder the root level inputFolder 2520fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet * @param oldestTarget the time stamp of the oldest output file to compare against. 253891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * 254891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * @return the status of the file in the folder. 255065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin */ 256a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet private DependencyStatus checkInputFolder(File folder, InputPath inputFolder, 257891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet long oldestTarget) { 258a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet if (inputFolder.ignores(folder)) { 259a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet return DependencyStatus.NONE; 260a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet } 261a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet 262a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet File[] files = folder.listFiles(); 263065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin if (files == null) { 264a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet System.err.println("ERROR " + folder.toString() + " is not a dir or can't be read"); 265891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return DependencyStatus.ERROR; 266065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 267065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // Loop through files in this folder 268065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin for (File file : files) { 269065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // If this is a directory, recurse into it 270065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin if (file.isDirectory()) { 271a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet DependencyStatus status = checkInputFolder(file, inputFolder, oldestTarget); 272891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (status != DependencyStatus.NONE) { 273891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return status; 274891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 275891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } else if (file.isFile()) { 276a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet DependencyStatus status = checkInputFile(file, inputFolder, oldestTarget); 277891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (status != DependencyStatus.NONE) { 278891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return status; 279065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 280065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 281065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 282065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // If we got to here then we didn't find anything interesting 283891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return DependencyStatus.NONE; 284891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 285891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 286a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet private DependencyStatus checkInputFile(File file, InputPath inputFolder, 287891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet long oldestTarget) { 288a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet if (inputFolder.ignores(file)) { 289a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet return DependencyStatus.NONE; 290a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet } 291a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet 292891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // if it's a file, remove it from the list of prereqs. 293891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // This way if files in this folder don't trigger a build we'll have less 294891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // files to go through manually 295891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (mPrereqs.remove(file) == false) { 296891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // turns out this is a new file! 297e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet 298e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet if (DEBUG) { 299e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet System.out.println("NEW FILE: " + file.getAbsolutePath()); 300e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet } 301891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return DependencyStatus.NEW_FILE; 302891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } else { 303a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet // check the time stamp on this file if it's a file we care about based what the 304a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet // input folder decides. 305a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet if (inputFolder.checksForModification(file)) { 306891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet if (file.lastModified() > oldestTarget) { 307e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet if (DEBUG) { 308e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet System.out.println("UPDATED FILE: " + file.getAbsolutePath()); 309e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet } 310891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return DependencyStatus.UPDATED_FILE; 311891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 312891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 313891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 314891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 315891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return DependencyStatus.NONE; 316065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 317065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 318065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin /** 319891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * Check all the prereq files we know about to make sure they're still there, or that they 320891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * haven't been modified since the last build. 321891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * 3220fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet * @param oldestTarget the time stamp of the oldest output file to compare against. 323891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * 324891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * @return the status of the files 325065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin */ 3260fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet private DependencyStatus checkPrereqFiles(long oldestTarget) { 327a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet // TODO: Optimize for the case of a specific file as inputPath. 328a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet // We should have a map of filepath to inputpath to quickly search through them? 329a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet 330065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // Loop through our prereq files and make sure they still exist 331065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin for (File prereq : mPrereqs) { 332065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin if (prereq.exists() == false) { 333e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet if (DEBUG) { 334e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet System.out.println("MISSING FILE: " + prereq.getAbsolutePath()); 335e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet } 336891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return DependencyStatus.MISSING_FILE; 337891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet } 338891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 339a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet // check the time stamp on this file if it's a file we care about. 340a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet // To know if we care about the file we have to find the matching input. 3410fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet if (mNewInputs != null) { 3420fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet String filePath = prereq.getAbsolutePath(); 3430fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet for (InputPath input : mNewInputs) { 344a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet File inputFile = input.getFile(); 345a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet // if the input path is a directory, check if the prereq file is in it, 346a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet // otherwise check if the prereq file match exactly the input path. 347a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet if (inputFile.isDirectory()) { 348a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet if (filePath.startsWith(inputFile.getAbsolutePath())) { 349a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet // ok file is inside a directory type input folder. 350a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet // check if we need to check this type of file, and if yes, check it. 351a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet if (input.checksForModification(prereq)) { 352a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet if (prereq.lastModified() > oldestTarget) { 353e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet if (DEBUG) { 354e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet System.out.println( 355e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet "UPDATED FILE: " + prereq.getAbsolutePath()); 356e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet } 357a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet return DependencyStatus.UPDATED_FILE; 358a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet } 359a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet } 360a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet } 361a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet } else { 362a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet // this is a file input path, we must check if the match is exact. 363a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet if (prereq.equals(inputFile)) { 364a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet if (input.checksForModification(prereq)) { 365a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet if (prereq.lastModified() > oldestTarget) { 366e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet if (DEBUG) { 367e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet System.out.println( 368e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet "UPDATED FILE: " + prereq.getAbsolutePath()); 369e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet } 370a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet return DependencyStatus.UPDATED_FILE; 371a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet } 372a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet } 373a9a28238f7b20d7c0a05c95afad02fcdb34e0d0eXavier Ducrohet } 3740fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet } 3750fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet } 3762c8cced2d84e8e93214a976be7afd6f5913fc74fXavier Ducrohet } else { 3772c8cced2d84e8e93214a976be7afd6f5913fc74fXavier Ducrohet // no input? we consider all files. 3782c8cced2d84e8e93214a976be7afd6f5913fc74fXavier Ducrohet if (prereq.lastModified() > oldestTarget) { 379e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet if (DEBUG) { 380e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet System.out.println("UPDATED FILE: " + prereq.getAbsolutePath()); 381e162064a7b5db1eecec34271bc7e2a4296181ea6Xavier Ducrohet } 3822c8cced2d84e8e93214a976be7afd6f5913fc74fXavier Ducrohet return DependencyStatus.UPDATED_FILE; 3832c8cced2d84e8e93214a976be7afd6f5913fc74fXavier Ducrohet } 3840fd7983848915b9424501afee8d8f0ea6f08f858Xavier Ducrohet } 385065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 386891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet 387891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet // If we get this far, then all our prereq are okay 388891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return DependencyStatus.NONE; 389065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 390065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 391065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin /** 392065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * Check all the target files we know about to make sure they're still there 393065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * @return true if any of the target files are missing. 394065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin */ 395065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin private boolean missingTargetFile() { 396065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // Loop through our target files and make sure they still exist 397065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin for (File target : mTargets) { 398065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin if (target.exists() == false) { 399065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin return true; 400065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 401065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 402065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // If we get this far, then all our targets are okay 403065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin return false; 404065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 405065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 406065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin /** 407891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * Returns the earliest modification time stamp from all the output targets. If there 408891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet * are no known target, the dependency file time stamp is returned. 409065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin */ 410891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet private long getOutputLastModified() { 411065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin // Find the oldest target 412065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin long oldestTarget = Long.MAX_VALUE; 41350b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet // if there's no output, then compare to the time of the dependency file. 41450b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet if (mTargets.size() == 0) { 41550b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet oldestTarget = mDepFileLastModified; 41650b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet } else { 41750b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet for (File target : mTargets) { 41850b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet if (target.lastModified() < oldestTarget) { 41950b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet oldestTarget = target.lastModified(); 42050b3e57fa887dc7182facfb178ef842103aeeaf3Xavier Ducrohet } 421065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 422065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 423065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 424891cbf7552f98af2f0baaed069b5eb64de50c556Xavier Ducrohet return oldestTarget; 425065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 426065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin 427065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin /** 428065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * Reads and returns the content of a text file. 429aea408b68a6f833327b6e0954a28f414f58133acXavier Ducrohet * @param file the file to read 430065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin * @return null if the file could not be read 431065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin */ 432f92c116240bc645a89b12975dd438a46645abe88Xavier Ducrohet private static List<String> readFile(File file) { 433065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin try { 434f92c116240bc645a89b12975dd438a46645abe88Xavier Ducrohet return Files.readLines(file, Charsets.UTF_8); 4355f2b9cd07a6f3c409971218ee34d3f7b36bd4725Siva Velusamy } catch (IOException e) { 436f92c116240bc645a89b12975dd438a46645abe88Xavier Ducrohet // return null below 437065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 438f92c116240bc645a89b12975dd438a46645abe88Xavier Ducrohet 439065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin return null; 440065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin } 441065dfacbf0c6e46c80f53d9207fac17afcb1fca7Josiah Gaskin} 442