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