diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 050f3ac..3856d19 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,10 +101,11 @@ jobs: .deps/iroh/target # Everything that invalidates artifacts wholesale is in the key: # the toolchain, the profiles, the resolved dependency versions, - # and the gate's cargo invocations. A key that misses still + # the gate's cargo invocations, and the mtime policy the restored + # artifacts were judged fresh against. A key that misses still # restores the newest entry under the prefix, so cargo rebuilds # what changed instead of everything. - key: build-dirs-${{ hashFiles('rust-toolchain.toml', 'Cargo.toml', 'Cargo.lock', '.deps/iroh/Cargo.toml', '.deps/iroh/Cargo.lock', 'justfile', '.github/justfile', '.github/workflows/ci.yml') }} + key: build-dirs-${{ hashFiles('rust-toolchain.toml', 'Cargo.toml', 'Cargo.lock', '.deps/iroh/Cargo.toml', '.deps/iroh/Cargo.lock', 'justfile', '.github/justfile', '.github/workflows/ci.yml', 'scripts/restore-mtimes.py') }} restore-keys: build-dirs- - name: Run the gate diff --git a/scripts/restore-mtimes.py b/scripts/restore-mtimes.py index 09a29a1..089947a 100755 --- a/scripts/restore-mtimes.py +++ b/scripts/restore-mtimes.py @@ -12,12 +12,21 @@ file would hide the modification from cargo and produce a build that does not match the source. +Each file also gets a sub-second offset derived from its path. Cargo records +a path dependency's freshness as the newest mtime in the package *and the name +of the file that carried it*, and a commit that touched several files would +otherwise give them one identical timestamp — leaving the newest file to be +decided by directory order, which differs between clones. The package then +looks changed on a machine that walked its directory differently, and every +crate above it rebuilds. + Usage: restore-mtimes.py [REPO ...] """ import os import subprocess import sys +import zlib def git(repo, *args): @@ -64,8 +73,9 @@ def restore(repo): continue pending.discard(line) path = os.path.join(repo, line) + stamp = timestamp * 10**9 + zlib.crc32(line.encode()) % 10**9 try: - os.utime(path, (timestamp, timestamp)) + os.utime(path, ns=(stamp, stamp)) stamped += 1 except OSError: pass