blob: b91a62eb5660514b8936981b89683c5b9f5656f5 [file] [log] [blame]
Greg Wardaebf7062000-04-04 02:05:59 +00001"""distutils.dep_util
2
3Utility functions for simple, timestamp-based dependency of files
4and groups of files; also, function based entirely on such
5timestamp dependency analysis."""
6
Greg Wardaebf7062000-04-04 02:05:59 +00007__revision__ = "$Id$"
8
9import os
10from distutils.errors import DistutilsFileError
11
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000012def newer(source, target):
13 """Tells if the target is newer than the source.
Greg Wardaebf7062000-04-04 02:05:59 +000014
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000015 Return true if 'source' exists and is more recently modified than
16 'target', or if 'source' exists and 'target' doesn't.
17
18 Return false if both exist and 'target' is the same age or younger
19 than 'source'. Raise DistutilsFileError if 'source' does not exist.
20
21 Note that this test is not very accurate: files created in the same second
22 will have the same "age".
Greg Wardca4289f2000-09-26 02:13:49 +000023 """
24 if not os.path.exists(source):
Thomas Wouters89d996e2007-09-08 17:39:28 +000025 raise DistutilsFileError("file '%s' does not exist" %
26 os.path.abspath(source))
Greg Wardca4289f2000-09-26 02:13:49 +000027 if not os.path.exists(target):
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000028 return True
Greg Wardaebf7062000-04-04 02:05:59 +000029
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000030 return os.stat(source).st_mtime > os.stat(target).st_mtime
Greg Wardaebf7062000-04-04 02:05:59 +000031
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000032def newer_pairwise(sources, targets):
Greg Wardaebf7062000-04-04 02:05:59 +000033 """Walk two filename lists in parallel, testing if each source is newer
Greg Wardca4289f2000-09-26 02:13:49 +000034 than its corresponding target. Return a pair of lists (sources,
35 targets) where source is newer than target, according to the semantics
36 of 'newer()'.
37 """
38 if len(sources) != len(targets):
Collin Winter5b7e9d72007-08-30 03:52:21 +000039 raise ValueError("'sources' and 'targets' must be same length")
Greg Wardaebf7062000-04-04 02:05:59 +000040
41 # build a pair of lists (sources, targets) where source is newer
42 n_sources = []
43 n_targets = []
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000044 for source, target in zip(sources, targets):
45 if newer(source, target):
46 n_sources.append(source)
47 n_targets.append(target)
Greg Wardaebf7062000-04-04 02:05:59 +000048
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000049 return n_sources, n_targets
Greg Wardaebf7062000-04-04 02:05:59 +000050
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000051def newer_group(sources, target, missing='error'):
Greg Wardca4289f2000-09-26 02:13:49 +000052 """Return true if 'target' is out-of-date with respect to any file
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000053 listed in 'sources'.
54
55 In other words, if 'target' exists and is newer
Greg Wardca4289f2000-09-26 02:13:49 +000056 than every file in 'sources', return false; otherwise return true.
57 'missing' controls what we do when a source file is missing; the
58 default ("error") is to blow up with an OSError from inside 'stat()';
59 if it is "ignore", we silently drop any missing source files; if it is
60 "newer", any missing source files make us assume that 'target' is
61 out-of-date (this is handy in "dry-run" mode: it'll make you pretend to
62 carry out commands that wouldn't work because inputs are missing, but
63 that doesn't matter because you're not actually going to run the
64 commands).
65 """
Greg Wardaebf7062000-04-04 02:05:59 +000066 # If the target doesn't even exist, then it's definitely out-of-date.
Greg Wardca4289f2000-09-26 02:13:49 +000067 if not os.path.exists(target):
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000068 return True
Fred Drakeb94b8492001-12-06 20:51:35 +000069
Greg Wardaebf7062000-04-04 02:05:59 +000070 # Otherwise we have to find out the hard way: if *any* source file
71 # is more recent than 'target', then 'target' is out-of-date and
72 # we can immediately return true. If we fall through to the end
73 # of the loop, then 'target' is up-to-date and we return false.
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000074 target_mtime = os.stat(target).st_mtime
75
Greg Wardaebf7062000-04-04 02:05:59 +000076 for source in sources:
Greg Wardca4289f2000-09-26 02:13:49 +000077 if not os.path.exists(source):
Greg Wardaebf7062000-04-04 02:05:59 +000078 if missing == 'error': # blow up when we stat() the file
Fred Drakeb94b8492001-12-06 20:51:35 +000079 pass
80 elif missing == 'ignore': # missing source dropped from
Greg Wardaebf7062000-04-04 02:05:59 +000081 continue # target's dependency list
82 elif missing == 'newer': # missing source means target is
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000083 return True # out-of-date
Fred Drakeb94b8492001-12-06 20:51:35 +000084
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000085 if os.stat(source).st_mtime > target_mtime:
86 return True
Greg Wardaebf7062000-04-04 02:05:59 +000087
Tarek Ziadé7ecb9c62009-12-10 15:35:35 +000088 return False