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 distutils.errors import DistutilsFileError
     11 
     12 def newer(source, target):
     13     """Tells if the target is newer than the source.
     14 
     15     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".
     23     """
     24     if not os.path.exists(source):
     25         raise DistutilsFileError("file '%s' does not exist" %
     26                                  os.path.abspath(source))
     27     if not os.path.exists(target):
     28         return True
     29 
     30     return os.stat(source).st_mtime > os.stat(target).st_mtime
     31 
     32 def newer_pairwise(sources, targets):
     33     """Walk two filename lists in parallel, testing if each source is newer
     34     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):
     39         raise ValueError, "'sources' and 'targets' must be same length"
     40 
     41     # build a pair of lists (sources, targets) where  source is newer

     42     n_sources = []
     43     n_targets = []
     44     for source, target in zip(sources, targets):
     45         if newer(source, target):
     46             n_sources.append(source)
     47             n_targets.append(target)
     48 
     49     return n_sources, n_targets
     50 
     51 def newer_group(sources, target, missing='error'):
     52     """Return true if 'target' is out-of-date with respect to any file
     53     listed in 'sources'.
     54 
     55     In other words, if 'target' exists and is newer
     56     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     """
     66     # If the target doesn't even exist, then it's definitely out-of-date.

     67     if not os.path.exists(target):
     68         return True
     69 
     70     # 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.

     74     target_mtime = os.stat(target).st_mtime
     75 
     76     for source in sources:
     77         if not os.path.exists(source):
     78             if missing == 'error':      # blow up when we stat() the file

     79                 pass
     80             elif missing == 'ignore':   # missing source dropped from

     81                 continue                #  target's dependency list

     82             elif missing == 'newer':    # missing source means target is

     83                 return True             #  out-of-date

     84 
     85         if os.stat(source).st_mtime > target_mtime:
     86             return True
     87 
     88     return False
     89