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