@@ -699,19 +699,11 @@ def sstate_package(ss, d):
if not os.path.exists(siginfo):
bb.siggen.dump_this_task(siginfo, d)
else:
- try:
- os.utime(siginfo, None)
- except PermissionError:
- pass
- except OSError as e:
- # Handle read-only file systems gracefully
- import errno
- if e.errno != errno.EROFS:
- raise e
+ sstate_touch(siginfo, d.getVar("SSTATE_ATIME_UPDATE_AFTER"))
return
-sstate_package[vardepsexclude] += "SSTATE_SIG_KEY SSTATE_PKG"
+sstate_package[vardepsexclude] += "SSTATE_SIG_KEY SSTATE_PKG SSTATE_ATIME_UPDATE_AFTER"
def pstaging_fetch(sstatefetch, d):
import bb.fetch
@@ -799,10 +791,15 @@ python sstate_create_and_sign_package () {
from pathlib import Path
import errno
+ update_after = d.getVar("SSTATE_ATIME_UPDATE_AFTER")
+
# Best effort touch
def touch(file):
try:
- file.touch()
+ if file.exists():
+ sstate_touch(file, update_after)
+ else:
+ file.touch()
except:
pass
@@ -933,16 +930,44 @@ sstate_unpack_package () {
tar -I "$ZSTD" -xvpf ${SSTATE_PKG}
+ touch_opts=""
+ if [ -n "${SSTATE_ATIME_UPDATE_AFTER}" ]; then
+ # the files below are installed together, so decide once for all of them
+ cutoff=$(date -d "-${SSTATE_ATIME_UPDATE_AFTER} seconds" +%s 2>/dev/null || echo 0)
+ atime=$(stat -c %X ${SSTATE_PKG} 2>/dev/null || echo 0)
+ if [ "$cutoff" -gt 0 ] && [ "$atime" -gt "$cutoff" ]; then
+ return 0
+ fi
+ touch_opts="-a"
+ fi
+
# Update both any file and any symlink pointing to the file for sigs as well as the file
for file in ${SSTATE_PKG} ${SSTATE_PKG}.sig ${SSTATE_PKG}.siginfo
do
- [ ! -e $file ] || touch $file 2>/dev/null || true
- [ ! -e $file ] || touch --no-dereference $file 2>/dev/null || true
+ [ ! -e $file ] || touch $touch_opts $file 2>/dev/null || true
+ [ ! -e $file ] || touch $touch_opts --no-dereference $file 2>/dev/null || true
done
}
BB_HASHCHECK_FUNCTION = "sstate_checkhashes"
+def sstate_touch(path, minage):
+ # Without minage the modification time is reset along with the access time.
+ # With it, only the access time is refreshed, and only once the existing one
+ # is at least minage seconds old.
+ import time
+ if not minage:
+ oe.utils.touch(path)
+ return
+ try:
+ stat_info = os.stat(path)
+ now = time.time()
+ if now - stat_info.st_atime < float(minage):
+ return
+ os.utime(path, (now, stat_info.st_mtime))
+ except OSError:
+ pass
+
def sstate_checkhashes(sq_data, d, siginfo=False, currentcount=0, summary=True, **kwargs):
import itertools
@@ -973,15 +998,17 @@ def sstate_checkhashes(sq_data, d, siginfo=False, currentcount=0, summary=True,
spec, extrapath, tname = getpathcomponents(tid, d)
return extrapath + generate_sstatefn(spec, gethash(tid), tname, siginfo, d)
+ update_after = d.getVar("SSTATE_ATIME_UPDATE_AFTER")
+
for tid in sq_data['hash']:
sstatefile = d.expand("${SSTATE_DIR}/" + getsstatefile(tid, siginfo, d))
if os.path.exists(sstatefile):
- oe.utils.touch(sstatefile)
+ sstate_touch(sstatefile, update_after)
for ext in ['.sig', '.siginfo']:
if os.path.exists(sstatefile + ext):
- oe.utils.touch(sstatefile + ext)
+ sstate_touch(sstatefile + ext, update_after)
found.add(tid)
bb.debug(2, "SState: Found valid sstate file %s" % sstatefile)
else:
@@ -1223,7 +1250,7 @@ python sstate_eventhandler() {
if not os.path.exists(siginfo):
bb.siggen.dump_this_task(siginfo, d)
else:
- oe.utils.touch(siginfo)
+ sstate_touch(siginfo, d.getVar("SSTATE_ATIME_UPDATE_AFTER"))
}
SSTATE_PRUNE_OBSOLETEWORKDIR ?= "1"