summaryrefslogtreecommitdiffstats
path: root/SCons/Node
diff options
context:
space:
mode:
authorMats Wichmann <mats@linux.com>2022-03-21 15:45:55 (GMT)
committerMats Wichmann <mats@linux.com>2022-05-06 12:48:09 (GMT)
commit769edf8d42ef2c05ac5e9c768f1d9e8f3cedbfcf (patch)
treea2daa46094184d99d293878787b973d9f693379c /SCons/Node
parent3e7b8ad568dfbfec9c92d59ef5276b1975725ce4 (diff)
downloadSCons-769edf8d42ef2c05ac5e9c768f1d9e8f3cedbfcf.zip
SCons-769edf8d42ef2c05ac5e9c768f1d9e8f3cedbfcf.tar.gz
SCons-769edf8d42ef2c05ac5e9c768f1d9e8f3cedbfcf.tar.bz2
Fix content-timestamp decider for symlinks
The base filesystem node class has getmtime() and getsize() functions. Those were changed in an early commit to use the lstat() method if the node represented a symbolic link. However, we actually want the information of the file the symlink points to, or we can't detect changes to the mtime or size of the underlying file, and miss rebuilds if content-timestamp is used. Added a testcase which shows the failure to rebuild from the symlinked source. Fixes #3880 Signed-off-by: Mats Wichmann <mats@linux.com>
Diffstat (limited to 'SCons/Node')
-rw-r--r--SCons/Node/FS.py24
-rw-r--r--SCons/Node/FSTests.py12
2 files changed, 15 insertions, 21 deletions
diff --git a/SCons/Node/FS.py b/SCons/Node/FS.py
index c1bfd6a..a7e25b9 100644
--- a/SCons/Node/FS.py
+++ b/SCons/Node/FS.py
@@ -255,7 +255,7 @@ else:
def _copy_func(fs, src, dest):
shutil.copy2(src, dest)
st = fs.stat(src)
- fs.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
+ fs.chmod(dest, stat.S_IMODE(st.st_mode) | stat.S_IWRITE)
Valid_Duplicates = ['hard-soft-copy', 'soft-hard-copy',
@@ -733,39 +733,33 @@ class Base(SCons.Node.Node):
return SCons.Node._rexists_map[self._func_rexists](self)
def getmtime(self):
- if self.islink():
- st = self.lstat()
- else:
- st = self.stat()
+ st = self.stat()
if st:
- return st[stat.ST_MTIME]
+ return st.st_mtime
else:
return None
def getsize(self):
- if self.islink():
- st = self.lstat()
- else:
- st = self.stat()
+ st = self.stat()
if st:
- return st[stat.ST_SIZE]
+ return st.st_size
else:
return None
def isdir(self):
st = self.stat()
- return st is not None and stat.S_ISDIR(st[stat.ST_MODE])
+ return st is not None and stat.S_ISDIR(st.st_mode)
def isfile(self):
st = self.stat()
- return st is not None and stat.S_ISREG(st[stat.ST_MODE])
+ return st is not None and stat.S_ISREG(st.st_mode)
if hasattr(os, 'symlink'):
def islink(self):
st = self.lstat()
- return st is not None and stat.S_ISLNK(st[stat.ST_MODE])
+ return st is not None and stat.S_ISLNK(st.st_mode)
else:
def islink(self):
return False # no symlinks
@@ -2793,7 +2787,7 @@ class File(Base):
return size
@SCons.Memoize.CountMethodCall
- def get_timestamp(self) -> int:
+ def get_timestamp(self) -> float:
try:
return self._memo['get_timestamp']
except KeyError:
diff --git a/SCons/Node/FSTests.py b/SCons/Node/FSTests.py
index b93efc8..da606e2 100644
--- a/SCons/Node/FSTests.py
+++ b/SCons/Node/FSTests.py
@@ -408,8 +408,8 @@ class VariantDirTestCase(unittest.TestCase):
None)
os.chmod(test.workpath('src/foo'), stat.S_IRUSR | stat.S_IWRITE)
st = os.stat(test.workpath('build/foo'))
- assert (stat.S_IMODE(st[stat.ST_MODE]) & stat.S_IWRITE), \
- stat.S_IMODE(st[stat.ST_MODE])
+ assert (stat.S_IMODE(st.st_mode) & stat.S_IWRITE), \
+ stat.S_IMODE(st.st_mode)
# This used to generate a UserError when we forbid the source
# directory from being outside the top-level SConstruct dir.
@@ -769,9 +769,9 @@ class FileNodeInfoTestCase(_tempdirTestCase):
ni.update(fff)
- mtime = st[stat.ST_MTIME]
+ mtime = st.st_mtime
assert ni.timestamp == mtime, (ni.timestamp, mtime)
- size = st[stat.ST_SIZE]
+ size = st.st_size
assert ni.size == size, (ni.size, size)
import time
@@ -781,9 +781,9 @@ class FileNodeInfoTestCase(_tempdirTestCase):
st = os.stat('fff')
- mtime = st[stat.ST_MTIME]
+ mtime = st.st_mtime
assert ni.timestamp != mtime, (ni.timestamp, mtime)
- size = st[stat.ST_SIZE]
+ size = st.st_size
assert ni.size != size, (ni.size, size)