Skip to content

Name the Hermes source archive after the Hermes version - #59715

Open
fairysword wants to merge 1 commit into
react:mainfrom
fairysword:fix/hermes-source-tarball-per-version
Open

fairysword wants to merge 1 commit into
react:mainfrom
fairysword:fix/hermes-source-tarball-per-version

Conversation

@fairysword

Copy link
Copy Markdown
Contributor

Summary:

downloadHermes always writes to downloadsDir/hermes.tar.gz, so every Hermes version shares a single destination file. The download plugin's ETag store, packages/react-native/ReactAndroid/hermes-engine/build/download-task/etags.json, is keyed by URL only:

{"https://github.com":{"/meta/hermes/tarball/250829098.0.0-stable":{"ETag":"..."},"/meta/hermes/tarball/hermes-v250829098.0.17":{"ETag":"..."}}}

Once a build has downloaded a given Hermes tag, returning to that tag answers 304 Not Modified, so downloadHermes keeps the file that is already on disk. That file now holds a different version's bytes, because the previous tag wrote to the same name. unzipHermes then extracts the wrong Hermes source and the build silently compiles a Hermes version that does not match sdks/.hermesv1version.

This needs no unusual setup. downloadsDir defaults to packages/react-native/sdks/download, which sits outside the Gradle build directory, and CI points REACT_NATIVE_DOWNLOADS_DIR at a shared /opt/react-native-downloads. Anyone who moves between Hermes versions — testing a Hermes bump, switching branches, bisecting — can hit it.

useETag was added in daefeb1 ("Ensure local hermes.tar.gz doesn't get stale between subsequent runs.", Dec 2022) to stop the shared file from going stale when a Hermes commit landed. This change removes the remaining case, where ETag caching itself keeps the shared file stale, by giving each version its own file.

Every other third-party source downloaded into the same directory is already named after its version:

  • boost_${BOOST_VERSION}.tar.gz
  • double-conversion-${DOUBLE_CONVERSION_VERSION}.tar.gz
  • folly-${FOLLY_VERSION}.tar.gz
  • fast_float-${FAST_FLOAT_VERSION}.tar.gz
  • fmt-${FMT_VERSION}.tar.gz
  • glog-${GLOG_VERSION}.tar.gz

Hermes now follows the same convention and becomes hermes-<version>.tar.gz. The hermes-v prefix is stripped from the tag so the name stays hermes-<version>.tar.gz for both a release tag (hermes-v250829098.0.17) and the default value (250829098.0.0-stable); scripts/hermes/bump-hermes-version.js normalizes the same prefix.

Versions no longer overwrite each other, so switching back to a version that is already on disk needs no download at all.

Changelog:

[INTERNAL] [FIXED] - Name the downloaded Hermes source archive after the Hermes version so that switching Hermes versions cannot reuse another version's source archive

Test Plan:

Both runs below use a clean downloadsDir and a clean ETag store, and build Hermes from source:

./gradlew :packages:react-native:ReactAndroid:hermes-engine:downloadHermes \
  -Preact.internal.useHermesStable=false -Preact.internal.useHermesNightly=false

Each step changes only packages/react-native/sdks/.hermesv1version, then re-runs that command. The two Hermes versions used are:

Hermes version archive md5 size
250829098.0.0-stable (default, no version file) d212f870733227513a2907dab0a59166 22317635
hermes-v250829098.0.17 e598a0fd04d093365c7f24a31281dc59 22315764

Before

Step File in downloadsDir md5
build 250829098.0.0-stable hermes.tar.gz d212f870...
switch to hermes-v250829098.0.17 hermes.tar.gz e598a0fd...
switch back to 250829098.0.0-stable hermes.tar.gz e598a0fd...

The third step is the bug: downloadHermes does not run, and the build uses the hermes-v250829098.0.17 source while .hermesv1version asks for 250829098.0.0-stable. Reproduced on a clean checkout with the default downloadsDir and no REACT_NATIVE_DOWNLOADS_DIR set.

After

Step Files in downloadsDir md5
build 250829098.0.0-stable hermes-250829098.0.0-stable.tar.gz d212f870...
switch to hermes-v250829098.0.17 both archives kept d212f870... / e598a0fd...
switch back to 250829098.0.0-stable both archives kept, no download d212f870... / e598a0fd...

Each version resolves to its own archive, and returning to a version already on disk downloads nothing.

Also verified:

  • ./gradlew :packages:react-native:ReactAndroid:hermes-engine:unzipHermes succeeds with the new archive name and extracts the Hermes source tree (CMakeLists.txt, API, android, cmake, ...) into packages/react-native/sdks/hermes.
  • The changed lines match ktfmt output. yarn format-check-kotlin skips this file because of the **/hermes-engine/** ignore entry in scripts/format-kotlin.js, so ktfmt was run against the file directly.

The archive is always downloaded to `downloadsDir/hermes.tar.gz`, so every
Hermes version shares one destination file while `build/download-task/etags.json`
remembers an ETag per URL. After a build has already seen a version's tarball URL,
switching back to it answers 304 and the download is skipped, leaving the other
version's bytes on disk and building the wrong Hermes source.

Name the archive `hermes-<version>.tar.gz`, the way the other third-party sources
in that directory are named.
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 31, 2026
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 31, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant