Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modernize stat usage #4627

Merged
merged 4 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
Only object-like macros are replaced (not function-like), and
only on a whole-word basis; recursion is limited to five levels
and does not error out if that limit is reached (issue #4523).
- Minor modernization: make use of stat object's st_mode, st_mtime
and other attributes rather than indexing into stat return.
- The update-release-info test is adapted to accept changed help output
introduced in Python 3.12.8/3.13.1.

Expand Down
4 changes: 4 additions & 0 deletions RELEASE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ FIXES
only on a whole-word basis; recursion is limited to five levels
and does not error out if that limit is reached (issue #4523).

- Minor modernization: make use of stat object's st_mode, st_mtime
and other attributes rather than indexing into stat return.


IMPROVEMENTS
------------

Expand Down
2 changes: 1 addition & 1 deletion SCons/CacheDir.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def CacheRetrieveFunc(target, source, env) -> int:
except OSError:
pass
st = fs.stat(cachefile)
fs.chmod(t.get_internal_path(), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
fs.chmod(t.get_internal_path(), stat.S_IMODE(st.st_mode) | stat.S_IWRITE)
return 0

def CacheRetrieveString(target, source, env) -> str:
Expand Down
2 changes: 2 additions & 0 deletions SCons/Node/FS.py
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,8 @@ def getmtime(self):
st = self.stat()

if st:
# TODO: switch to st.st_mtime, however this changes granularity
# (ST_MTIME is an int for backwards compat, st_mtime is float)
return st[stat.ST_MTIME]
else:
return None
Expand Down
2 changes: 2 additions & 0 deletions SCons/Node/FSTests.py
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,7 @@ def test_update(self) -> None:

ni.update(fff)

# TODO: flip this to st.st_mtime when Node/FS.py does
mtime = st[stat.ST_MTIME]
assert ni.timestamp == mtime, (ni.timestamp, mtime)
size = st.st_size
Expand All @@ -786,6 +787,7 @@ def test_update(self) -> None:

st = os.stat('fff')

# TODO: flip this to st.st_mtime when Node/FS.py does
mtime = st[stat.ST_MTIME]
assert ni.timestamp != mtime, (ni.timestamp, mtime)
size = st.st_size
Expand Down
4 changes: 2 additions & 2 deletions SCons/Tool/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def copyFunc(dest, source, env) -> int:
else:
copy2(source, dest)
st = os.stat(source)
os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
os.chmod(dest, stat.S_IMODE(st.st_mode) | stat.S_IWRITE)

return 0

Expand Down Expand Up @@ -204,7 +204,7 @@ def copyFuncVersionedLib(dest, source, env) -> int:
pass
copy2(source, dest)
st = os.stat(source)
os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
os.chmod(dest, stat.S_IMODE(st.st_mode) | stat.S_IWRITE)
installShlibLinks(dest, source, env)

return 0
Expand Down
2 changes: 1 addition & 1 deletion site_scons/Utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def whereis(filename):
st = os.stat(f_ext)
except:
continue
if stat.S_IMODE(st[stat.ST_MODE]) & 0o111:
if stat.S_IMODE(st.st_mode) & stat.S_IXUSR:
return f_ext
return None

Expand Down
2 changes: 1 addition & 1 deletion test/Actions/append.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def after(env, target, source):

test.run(arguments='.')
test.must_match('before.txt', 'Bar\n')
os.chmod(after_exe, os.stat(after_exe)[stat.ST_MODE] | stat.S_IXUSR)
os.chmod(after_exe, os.stat(after_exe).st_mode | stat.S_IXUSR)
test.run(program=after_exe, stdout="Foo\n")
test.pass_test()

Expand Down
4 changes: 2 additions & 2 deletions test/Actions/pre-post.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def before(env, target, source):
a=str(target[0])
with open(a, "wb") as f:
f.write(b"Foo\\n")
os.chmod(a, os.stat(a)[stat.ST_MODE] | stat.S_IXUSR)
os.chmod(a, os.stat(a).st_mode | stat.S_IXUSR)
with open("before.txt", "ab") as f:
f.write((os.path.splitext(str(target[0]))[0] + "\\n").encode())

Expand All @@ -59,7 +59,7 @@ def after(env, target, source):
a = "after_" + t
with open(t, "rb") as fin, open(a, "wb") as fout:
fout.write(fin.read())
os.chmod(a, os.stat(a)[stat.ST_MODE] | stat.S_IXUSR)
os.chmod(a, os.stat(a).st_mode | stat.S_IXUSR)

foo = env.Program(source='foo.c', target='foo')
AddPreAction(foo, before)
Expand Down
77 changes: 39 additions & 38 deletions test/Chmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def cat(env, source, target):
f.write(infp.read())

Cat = Action(cat)
DefaultEnvironment(tools=[]) # test speedup
env = Environment()
env.Command(
'bar.out',
Expand Down Expand Up @@ -154,92 +155,92 @@ def cat(env, source, target):
""")
test.run(options = '-n', arguments = '.', stdout = expect)

s = stat.S_IMODE(os.stat(test.workpath('f1'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f1')).st_mode)
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f1-File'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f1-File')).st_mode)
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('d2'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d2')).st_mode)
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('d2-Dir'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d2-Dir')).st_mode)
test.fail_test(s != 0o555)
test.must_not_exist('bar.out')
s = stat.S_IMODE(os.stat(test.workpath('f3'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f3')).st_mode)
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('d4'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d4')).st_mode)
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('f5'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f5')).st_mode)
test.fail_test(s != 0o444)
test.must_not_exist('f6.out')
test.must_not_exist('f7.out')
s = stat.S_IMODE(os.stat(test.workpath('Chmod-f7.in'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('Chmod-f7.in')).st_mode)
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f7.out-Chmod'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f7.out-Chmod')).st_mode)
test.fail_test(s != 0o444)
test.must_not_exist('f8.out')
s = stat.S_IMODE(os.stat(test.workpath('f9'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f9')).st_mode)
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f10'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f10')).st_mode)
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('d11'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d11')).st_mode)
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('d12'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d12')).st_mode)
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('f13'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f13')).st_mode)
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f14'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f14')).st_mode)
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f15'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f15')).st_mode)
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('d16'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d16')).st_mode)
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('d17'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d17')).st_mode)
test.fail_test(s != 0o555)
s = stat.S_IMODE(os.stat(test.workpath('d18'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d18')).st_mode)
test.fail_test(s != 0o555)

test.run()

s = stat.S_IMODE(os.stat(test.workpath('f1'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f1')).st_mode)
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('f1-File'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f1-File')).st_mode)
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('d2'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d2')).st_mode)
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('d2-Dir'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d2-Dir')).st_mode)
test.fail_test(s != 0o777)
test.must_match('bar.out', "bar.in\n")
s = stat.S_IMODE(os.stat(test.workpath('f3'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f3')).st_mode)
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('d4'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d4')).st_mode)
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('f5'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f5')).st_mode)
test.fail_test(s != 0o666)
test.must_match('f6.out', "f6.in\n")
test.must_match('f7.out', "f7.in\n")
s = stat.S_IMODE(os.stat(test.workpath('Chmod-f7.in'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('Chmod-f7.in')).st_mode)
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('f7.out-Chmod'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f7.out-Chmod')).st_mode)
test.fail_test(s != 0o666)
test.must_match('f8.out', "f8.in\n")
s = stat.S_IMODE(os.stat(test.workpath('f9'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f9')).st_mode)
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('f10'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f10')).st_mode)
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('d11'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d11')).st_mode)
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('d12'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d12')).st_mode)
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('f13'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f13')).st_mode)
test.fail_test(s != 0o444)
s = stat.S_IMODE(os.stat(test.workpath('f14'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f14')).st_mode)
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('f15'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('f15')).st_mode)
test.fail_test(s != 0o666)
s = stat.S_IMODE(os.stat(test.workpath('d16'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d16')).st_mode)
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('d17'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d17')).st_mode)
test.fail_test(s != 0o777)
s = stat.S_IMODE(os.stat(test.workpath('d18'))[stat.ST_MODE])
s = stat.S_IMODE(os.stat(test.workpath('d18')).st_mode)
test.fail_test(s != 0o777)

test.pass_test()
Expand Down
2 changes: 1 addition & 1 deletion test/Decider/MD5-timestamp-Repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
test.sleep() # delay for timestamps
test.write(['Repository','content1.in'], "content1.in 2\n")
test.touch(['Repository','content2.in'])
time_content = os.stat(os.path.join(repository,'content3.in'))[stat.ST_MTIME]
time_content = os.stat(os.path.join(repository,'content3.in')).st_mtime
test.write(['Repository','content3.in'], "content3.in 2\n")
test.touch(['Repository','content3.in'], time_content)

Expand Down
2 changes: 1 addition & 1 deletion test/Decider/MD5-timestamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
test.write('content1.in', "content1.in 2\n")
test.touch('content2.in')

time_content = os.stat('content3.in')[stat.ST_MTIME]
time_content = os.stat('content3.in').st_mtime
test.write('content3.in', "content3.in 2\n")
test.touch('content3.in', time_content)

Expand Down
4 changes: 2 additions & 2 deletions test/Decider/timestamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
test.run(arguments = '.')
test.up_to_date(arguments = '.')

time_match = os.stat('match2.out')[stat.ST_MTIME]
time_newer = os.stat('newer2.out')[stat.ST_MTIME]
time_match = os.stat('match2.out').st_mtime
time_newer = os.stat('newer2.out').st_mtime

# Now make all the source files newer than (different timestamps from)
# the last time the targets were built, and touch the target files
Expand Down
6 changes: 3 additions & 3 deletions test/Removed/BuildDir/Old/BuildDir.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,16 +224,16 @@ def filter_tempnam(err):
def equal_stats(x,y):
x = os.stat(x)
y = os.stat(y)
return (stat.S_IMODE(x[stat.ST_MODE]) == stat.S_IMODE(y[stat.ST_MODE]) and
x[stat.ST_MTIME] == y[stat.ST_MTIME])
return (stat.S_IMODE(x.st_mode) == stat.S_IMODE(y.st_mode) and
x.st_mtime == y.st_mtime)

# Make sure we did duplicate the source files in build/var2,
# and that their stats are the same:
test.must_exist(['work1', 'build', 'var2', 'f1.c'])
test.must_exist(['work1', 'build', 'var2', 'f2.in'])
test.fail_test(not equal_stats(test.workpath('work1', 'build', 'var2', 'f1.c'), test.workpath('work1', 'src', 'f1.c')))
test.fail_test(not equal_stats(test.workpath('work1', 'build', 'var2', 'f2.in'), test.workpath('work1', 'src', 'f2.in')))

# Make sure we didn't duplicate the source files in build/var3.
test.must_not_exist(['work1', 'build', 'var3', 'f1.c'])
test.must_not_exist(['work1', 'build', 'var3', 'f2.in'])
Expand Down
22 changes: 11 additions & 11 deletions test/Removed/BuildDir/Old/SConscript-build_dir.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/env python
#
# __COPYRIGHT__
# MIT License
#
# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
Expand All @@ -20,9 +22,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

"""
Verify that specifying a build_dir argument to SConscript still works.
Expand Down Expand Up @@ -108,7 +107,7 @@ def cat(env, source, target):
# VariantDir('build/var9', '.')
# SConscript('build/var9/src/SConscript')
SConscript('src/SConscript', build_dir='build/var9', src_dir='.')
""")
""")

test.subdir(['test', 'src'], ['test', 'alt'])

Expand Down Expand Up @@ -152,8 +151,8 @@ def cat(env, source, target):
def equal_stats(x,y):
x = os.stat(x)
y = os.stat(y)
return (stat.S_IMODE(x[stat.ST_MODE]) == stat.S_IMODE(y[stat.ST_MODE]) and
x[stat.ST_MTIME] == y[stat.ST_MTIME])
return (stat.S_IMODE(x.st_mode) == stat.S_IMODE(y.st_mode) and
x.st_mtime == y.st_mtime)

# Make sure we did duplicate the source files in build/var1,
# and that their stats are the same:
Expand All @@ -168,12 +167,12 @@ def equal_stats(x,y):
test.must_exist(test.workpath('test', 'build', 'var2', file))
test.fail_test(not equal_stats(test.workpath('test', 'build', 'var2', file),
test.workpath('test', 'src', file)))

# Make sure we didn't duplicate the source files in build/var3.
test.must_not_exist(test.workpath('test', 'build', 'var3', 'aaa.in'))
test.must_not_exist(test.workpath('test', 'build', 'var3', 'bbb.in'))
test.must_not_exist(test.workpath('test', 'build', 'var3', 'ccc.in'))

#XXX We can't support var4 and var5 yet, because our VariantDir linkage
#XXX is to an entire source directory. We haven't yet generalized our
#XXX infrastructure to be able to take the SConscript file from one source
Expand All @@ -200,12 +199,12 @@ def equal_stats(x,y):
test.must_exist(test.workpath('build', 'var6', file))
test.fail_test(not equal_stats(test.workpath('build', 'var6', file),
test.workpath('test', 'src', file)))

# Make sure we didn't duplicate the source files in build/var7.
test.must_not_exist(test.workpath('build', 'var7', 'aaa.in'))
test.must_not_exist(test.workpath('build', 'var7', 'bbb.in'))
test.must_not_exist(test.workpath('build', 'var7', 'ccc.in'))

# Make sure we didn't duplicate the source files in build/var8.
test.must_not_exist(test.workpath('build', 'var8', 'aaa.in'))
test.must_not_exist(test.workpath('build', 'var8', 'bbb.in'))
Expand All @@ -219,6 +218,7 @@ def equal_stats(x,y):
""")

test.write(['test2', 'SConscript'], """\
DefaultEnvironment(tools=[]) # test speedup
env = Environment()
foo_obj = env.Object('foo.c')
env.Program('foo', [foo_obj, 'bar.c'])
Expand Down
Loading
Loading