diff --git a/Lib/distutils/dep_util.py b/Lib/distutils/dep_util.py index 07b3549c6fe..b91a62eb566 100644 --- a/Lib/distutils/dep_util.py +++ b/Lib/distutils/dep_util.py @@ -9,29 +9,27 @@ __revision__ = "$Id$" import os from distutils.errors import DistutilsFileError +def newer(source, target): + """Tells if the target is newer than the source. -def newer (source, target): - """Return true if 'source' exists and is more recently modified than - 'target', or if 'source' exists and 'target' doesn't. Return false if - both exist and 'target' is the same age or younger than 'source'. - Raise DistutilsFileError if 'source' does not exist. + Return true if 'source' exists and is more recently modified than + 'target', or if 'source' exists and 'target' doesn't. + + Return false if both exist and 'target' is the same age or younger + than 'source'. Raise DistutilsFileError if 'source' does not exist. + + Note that this test is not very accurate: files created in the same second + will have the same "age". """ if not os.path.exists(source): raise DistutilsFileError("file '%s' does not exist" % os.path.abspath(source)) if not os.path.exists(target): - return 1 + return True - from stat import ST_MTIME - mtime1 = os.stat(source)[ST_MTIME] - mtime2 = os.stat(target)[ST_MTIME] + return os.stat(source).st_mtime > os.stat(target).st_mtime - return mtime1 > mtime2 - -# newer () - - -def newer_pairwise (sources, targets): +def newer_pairwise(sources, targets): """Walk two filename lists in parallel, testing if each source is newer than its corresponding target. Return a pair of lists (sources, targets) where source is newer than target, according to the semantics @@ -43,19 +41,18 @@ def newer_pairwise (sources, targets): # build a pair of lists (sources, targets) where source is newer n_sources = [] n_targets = [] - for i in range(len(sources)): - if newer(sources[i], targets[i]): - n_sources.append(sources[i]) - n_targets.append(targets[i]) + for source, target in zip(sources, targets): + if newer(source, target): + n_sources.append(source) + n_targets.append(target) - return (n_sources, n_targets) + return n_sources, n_targets -# newer_pairwise () - - -def newer_group (sources, target, missing='error'): +def newer_group(sources, target, missing='error'): """Return true if 'target' is out-of-date with respect to any file - listed in 'sources'. In other words, if 'target' exists and is newer + listed in 'sources'. + + In other words, if 'target' exists and is newer than every file in 'sources', return false; otherwise return true. 'missing' controls what we do when a source file is missing; the default ("error") is to blow up with an OSError from inside 'stat()'; @@ -68,14 +65,14 @@ def newer_group (sources, target, missing='error'): """ # If the target doesn't even exist, then it's definitely out-of-date. if not os.path.exists(target): - return 1 + return True # Otherwise we have to find out the hard way: if *any* source file # is more recent than 'target', then 'target' is out-of-date and # we can immediately return true. If we fall through to the end # of the loop, then 'target' is up-to-date and we return false. - from stat import ST_MTIME - target_mtime = os.stat(target)[ST_MTIME] + target_mtime = os.stat(target).st_mtime + for source in sources: if not os.path.exists(source): if missing == 'error': # blow up when we stat() the file @@ -83,12 +80,9 @@ def newer_group (sources, target, missing='error'): elif missing == 'ignore': # missing source dropped from continue # target's dependency list elif missing == 'newer': # missing source means target is - return 1 # out-of-date + return True # out-of-date - source_mtime = os.stat(source)[ST_MTIME] - if source_mtime > target_mtime: - return 1 - else: - return 0 + if os.stat(source).st_mtime > target_mtime: + return True -# newer_group () + return False diff --git a/Lib/distutils/tests/test_dep_util.py b/Lib/distutils/tests/test_dep_util.py new file mode 100644 index 00000000000..21fc7bc0b91 --- /dev/null +++ b/Lib/distutils/tests/test_dep_util.py @@ -0,0 +1,101 @@ +"""Tests for distutils.dep_util.""" +import unittest +import os +import time + +from distutils.dep_util import newer, newer_pairwise, newer_group +from distutils.errors import DistutilsFileError +from distutils.tests import support + +# XXX needs to be tuned for the various platforms +_ST_MIME_TIMER = 1 + +class DepUtilTestCase(support.TempdirManager, unittest.TestCase): + + def test_newer(self): + tmpdir = self.mkdtemp() + target = os.path.join(tmpdir, 'target') + source = os.path.join(tmpdir, 'source') + + # Raise DistutilsFileError if 'source' does not exist. + self.assertRaises(DistutilsFileError, newer, target, source) + + # Return true if 'source' exists and is more recently modified than + # 'target', or if 'source' exists and 'target' doesn't. + self.write_file(target) + self.assertTrue(newer(target, source)) + self.write_file(source, 'xox') + time.sleep(_ST_MIME_TIMER) # ensures ST_MTIME differs + self.write_file(target, 'xhx') + self.assertTrue(newer(target, source)) + + # Return false if both exist and 'target' is the same age or younger + # than 'source'. + self.write_file(source, 'xox'); self.write_file(target, 'xhx') + self.assertFalse(newer(target, source)) + self.write_file(target, 'xox') + time.sleep(_ST_MIME_TIMER) + self.write_file(source, 'xhx') + self.assertFalse(newer(target, source)) + + def test_newer_pairwise(self): + tmpdir = self.mkdtemp() + sources = os.path.join(tmpdir, 'sources') + targets = os.path.join(tmpdir, 'targets') + os.mkdir(sources) + os.mkdir(targets) + one = os.path.join(sources, 'one') + two = os.path.join(sources, 'two') + three = os.path.join(targets, 'three') + four = os.path.join(targets, 'four') + + self.write_file(one) + self.write_file(three) + self.write_file(four) + time.sleep(_ST_MIME_TIMER) + self.write_file(two) + + self.assertEquals(newer_pairwise([one, two], [three, four]), + ([two],[four])) + + def test_newer_group(self): + tmpdir = self.mkdtemp() + sources = os.path.join(tmpdir, 'sources') + os.mkdir(sources) + one = os.path.join(sources, 'one') + two = os.path.join(sources, 'two') + three = os.path.join(sources, 'three') + target = os.path.join(tmpdir, 'target') + + # return true if 'target' is out-of-date with respect to any file + # listed in 'sources'. + self.write_file(target) + time.sleep(_ST_MIME_TIMER) + self.write_file(one) + self.write_file(two) + self.write_file(three) + self.assertTrue(newer_group([one, two, three], target)) + + self.write_file(one) + self.write_file(three) + self.write_file(two) + time.sleep(0.1) + self.write_file(target) + self.assertFalse(newer_group([one, two, three], target)) + + # missing handling + os.remove(one) + self.assertRaises(OSError, newer_group, [one, two, three], target) + + self.assertFalse(newer_group([one, two, three], target, + missing='ignore')) + + self.assertTrue(newer_group([one, two, three], target, + missing='newer')) + + +def test_suite(): + return unittest.makeSuite(DepUtilTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite")