1*cda5da8dSAndroid Build Coastguard Worker"""distutils.dep_util 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard WorkerUtility functions for simple, timestamp-based dependency of files 4*cda5da8dSAndroid Build Coastguard Workerand groups of files; also, function based entirely on such 5*cda5da8dSAndroid Build Coastguard Workertimestamp dependency analysis.""" 6*cda5da8dSAndroid Build Coastguard Worker 7*cda5da8dSAndroid Build Coastguard Workerimport os 8*cda5da8dSAndroid Build Coastguard Workerfrom distutils.errors import DistutilsFileError 9*cda5da8dSAndroid Build Coastguard Worker 10*cda5da8dSAndroid Build Coastguard Worker 11*cda5da8dSAndroid Build Coastguard Workerdef newer (source, target): 12*cda5da8dSAndroid Build Coastguard Worker """Return true if 'source' exists and is more recently modified than 13*cda5da8dSAndroid Build Coastguard Worker 'target', or if 'source' exists and 'target' doesn't. Return false if 14*cda5da8dSAndroid Build Coastguard Worker both exist and 'target' is the same age or younger than 'source'. 15*cda5da8dSAndroid Build Coastguard Worker Raise DistutilsFileError if 'source' does not exist. 16*cda5da8dSAndroid Build Coastguard Worker """ 17*cda5da8dSAndroid Build Coastguard Worker if not os.path.exists(source): 18*cda5da8dSAndroid Build Coastguard Worker raise DistutilsFileError("file '%s' does not exist" % 19*cda5da8dSAndroid Build Coastguard Worker os.path.abspath(source)) 20*cda5da8dSAndroid Build Coastguard Worker if not os.path.exists(target): 21*cda5da8dSAndroid Build Coastguard Worker return 1 22*cda5da8dSAndroid Build Coastguard Worker 23*cda5da8dSAndroid Build Coastguard Worker from stat import ST_MTIME 24*cda5da8dSAndroid Build Coastguard Worker mtime1 = os.stat(source)[ST_MTIME] 25*cda5da8dSAndroid Build Coastguard Worker mtime2 = os.stat(target)[ST_MTIME] 26*cda5da8dSAndroid Build Coastguard Worker 27*cda5da8dSAndroid Build Coastguard Worker return mtime1 > mtime2 28*cda5da8dSAndroid Build Coastguard Worker 29*cda5da8dSAndroid Build Coastguard Worker# newer () 30*cda5da8dSAndroid Build Coastguard Worker 31*cda5da8dSAndroid Build Coastguard Worker 32*cda5da8dSAndroid Build Coastguard Workerdef newer_pairwise (sources, targets): 33*cda5da8dSAndroid Build Coastguard Worker """Walk two filename lists in parallel, testing if each source is newer 34*cda5da8dSAndroid Build Coastguard Worker than its corresponding target. Return a pair of lists (sources, 35*cda5da8dSAndroid Build Coastguard Worker targets) where source is newer than target, according to the semantics 36*cda5da8dSAndroid Build Coastguard Worker of 'newer()'. 37*cda5da8dSAndroid Build Coastguard Worker """ 38*cda5da8dSAndroid Build Coastguard Worker if len(sources) != len(targets): 39*cda5da8dSAndroid Build Coastguard Worker raise ValueError("'sources' and 'targets' must be same length") 40*cda5da8dSAndroid Build Coastguard Worker 41*cda5da8dSAndroid Build Coastguard Worker # build a pair of lists (sources, targets) where source is newer 42*cda5da8dSAndroid Build Coastguard Worker n_sources = [] 43*cda5da8dSAndroid Build Coastguard Worker n_targets = [] 44*cda5da8dSAndroid Build Coastguard Worker for i in range(len(sources)): 45*cda5da8dSAndroid Build Coastguard Worker if newer(sources[i], targets[i]): 46*cda5da8dSAndroid Build Coastguard Worker n_sources.append(sources[i]) 47*cda5da8dSAndroid Build Coastguard Worker n_targets.append(targets[i]) 48*cda5da8dSAndroid Build Coastguard Worker 49*cda5da8dSAndroid Build Coastguard Worker return (n_sources, n_targets) 50*cda5da8dSAndroid Build Coastguard Worker 51*cda5da8dSAndroid Build Coastguard Worker# newer_pairwise () 52*cda5da8dSAndroid Build Coastguard Worker 53*cda5da8dSAndroid Build Coastguard Worker 54*cda5da8dSAndroid Build Coastguard Workerdef newer_group (sources, target, missing='error'): 55*cda5da8dSAndroid Build Coastguard Worker """Return true if 'target' is out-of-date with respect to any file 56*cda5da8dSAndroid Build Coastguard Worker listed in 'sources'. In other words, if 'target' exists and is newer 57*cda5da8dSAndroid Build Coastguard Worker than every file in 'sources', return false; otherwise return true. 58*cda5da8dSAndroid Build Coastguard Worker 'missing' controls what we do when a source file is missing; the 59*cda5da8dSAndroid Build Coastguard Worker default ("error") is to blow up with an OSError from inside 'stat()'; 60*cda5da8dSAndroid Build Coastguard Worker if it is "ignore", we silently drop any missing source files; if it is 61*cda5da8dSAndroid Build Coastguard Worker "newer", any missing source files make us assume that 'target' is 62*cda5da8dSAndroid Build Coastguard Worker out-of-date (this is handy in "dry-run" mode: it'll make you pretend to 63*cda5da8dSAndroid Build Coastguard Worker carry out commands that wouldn't work because inputs are missing, but 64*cda5da8dSAndroid Build Coastguard Worker that doesn't matter because you're not actually going to run the 65*cda5da8dSAndroid Build Coastguard Worker commands). 66*cda5da8dSAndroid Build Coastguard Worker """ 67*cda5da8dSAndroid Build Coastguard Worker # If the target doesn't even exist, then it's definitely out-of-date. 68*cda5da8dSAndroid Build Coastguard Worker if not os.path.exists(target): 69*cda5da8dSAndroid Build Coastguard Worker return 1 70*cda5da8dSAndroid Build Coastguard Worker 71*cda5da8dSAndroid Build Coastguard Worker # Otherwise we have to find out the hard way: if *any* source file 72*cda5da8dSAndroid Build Coastguard Worker # is more recent than 'target', then 'target' is out-of-date and 73*cda5da8dSAndroid Build Coastguard Worker # we can immediately return true. If we fall through to the end 74*cda5da8dSAndroid Build Coastguard Worker # of the loop, then 'target' is up-to-date and we return false. 75*cda5da8dSAndroid Build Coastguard Worker from stat import ST_MTIME 76*cda5da8dSAndroid Build Coastguard Worker target_mtime = os.stat(target)[ST_MTIME] 77*cda5da8dSAndroid Build Coastguard Worker for source in sources: 78*cda5da8dSAndroid Build Coastguard Worker if not os.path.exists(source): 79*cda5da8dSAndroid Build Coastguard Worker if missing == 'error': # blow up when we stat() the file 80*cda5da8dSAndroid Build Coastguard Worker pass 81*cda5da8dSAndroid Build Coastguard Worker elif missing == 'ignore': # missing source dropped from 82*cda5da8dSAndroid Build Coastguard Worker continue # target's dependency list 83*cda5da8dSAndroid Build Coastguard Worker elif missing == 'newer': # missing source means target is 84*cda5da8dSAndroid Build Coastguard Worker return 1 # out-of-date 85*cda5da8dSAndroid Build Coastguard Worker 86*cda5da8dSAndroid Build Coastguard Worker source_mtime = os.stat(source)[ST_MTIME] 87*cda5da8dSAndroid Build Coastguard Worker if source_mtime > target_mtime: 88*cda5da8dSAndroid Build Coastguard Worker return 1 89*cda5da8dSAndroid Build Coastguard Worker else: 90*cda5da8dSAndroid Build Coastguard Worker return 0 91*cda5da8dSAndroid Build Coastguard Worker 92*cda5da8dSAndroid Build Coastguard Worker# newer_group () 93