Skip to content
Closed
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
10 changes: 5 additions & 5 deletions packages/react-native/scripts/cocoapods/rncore.rb
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ def self.nightly_tarball_url(version, configuration, dsyms = false)
artefact_name = "reactnative-core-#{dsyms ? "dSYM-" : ""}#{configuration ? configuration : "debug"}.tar.gz"
xml_url = "https://central.sonatype.com/repository/maven-snapshots/com/facebook/react/#{artefact_coordinate}/#{version}-SNAPSHOT/maven-metadata.xml"

response = Net::HTTP.get_response(URI(xml_url))
response = ReactNativePodsUtils.memoized_get_response(xml_url)
if response.is_a?(Net::HTTPSuccess)
xml = REXML::Document.new(response.body)
timestamp = xml.elements['metadata/versioning/snapshot/timestamp'].text
Expand Down Expand Up @@ -476,11 +476,11 @@ def self.artifacts_dir()
return File.join(Pod::Config.instance.project_pods_root, "ReactNativeCore-artifacts")
end

# This function checks that ReactNativeCore artifact exists on the maven repo
# This function checks that ReactNativeCore artifact exists on the maven repo.
# The probe is memoized, so repeated podspec evaluations in one `pod install`
# don't re-request the same URL.
def self.artifact_exists(tarball_url)
# -L is used to follow redirects, useful for the nightlies
# I also needed to wrap the url in quotes to avoid escaping & and ?.
return (`curl -o /dev/null --silent -Iw '%{http_code}' -L "#{tarball_url}"` == "200")
return ReactNativePodsUtils.artifact_exists?(tarball_url)
end

def self.rncore_log(message, level = :info)
Expand Down
10 changes: 5 additions & 5 deletions packages/react-native/scripts/cocoapods/rndependencies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ def self.nightly_tarball_url(version, build_type)
artifact_name = "reactnative-dependencies-#{build_type.to_s}.tar.gz"
xml_url = "https://central.sonatype.com/repository/maven-snapshots/com/facebook/react/#{artifact_coordinate}/#{version}-SNAPSHOT/maven-metadata.xml"

response = Net::HTTP.get_response(URI(xml_url))
response = ReactNativePodsUtils.memoized_get_response(xml_url)
if response.is_a?(Net::HTTPSuccess)
xml = REXML::Document.new(response.body)
timestamp = xml.elements['metadata/versioning/snapshot/timestamp'].text
Expand Down Expand Up @@ -378,11 +378,11 @@ def self.artifacts_dir()
return File.join(Pod::Config.instance.project_pods_root, "ReactNativeDependencies-artifacts")
end

# This function checks that ReactNativeDependencies artifact exists on the maven repo
# This function checks that ReactNativeDependencies artifact exists on the maven repo.
# The probe is memoized, so repeated podspec evaluations in one `pod install`
# don't re-request the same URL.
def self.artifact_exists(tarball_url)
# -L is used to follow redirects, useful for the nightlies
# I also needed to wrap the url in quotes to avoid escaping & and ?.
return (`curl -o /dev/null --silent -Iw '%{http_code}' -L "#{tarball_url}"` == "200")
return ReactNativePodsUtils.artifact_exists?(tarball_url)
end

def self.rndeps_log(message, level = :info)
Expand Down
42 changes: 42 additions & 0 deletions packages/react-native/scripts/cocoapods/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require 'shellwords'
require 'digest'
require 'uri'
require 'net/http'

require_relative "./helpers.rb"
require_relative "./jsengine.rb"
Expand Down Expand Up @@ -757,6 +758,47 @@ def self.resolve_use_frameworks(spec, header_mappings_dir: nil, module_name: nil
end
end

# ============================ #
# Network request memoization #
# ============================ #
# CocoaPods evaluates the prebuilt podspecs several times during a single
# `pod install`, and every evaluation re-resolves the artifact URLs from
# scratch: existence probes against the mirror/Maven Central and nightly
# metadata lookups. The answers should not change within one install, so
# each request is issued at most once per process and then served from
# these in-memory caches.
@@artifact_exists_cache = {}
@@get_response_cache = {}

# Memoized existence probe (HTTP HEAD) for a prebuilt artifact URL.
# Only conclusive answers are cached. If curl never got an HTTP status
# (DNS failure, no route, ...) the probe is left uncached so that a
# transient hiccup doesn't permanently mark the artifact as missing.
def self.artifact_exists?(tarball_url)
unless @@artifact_exists_cache.key?(tarball_url)
# -L is used to follow redirects, useful for the nightlies
# The url is wrapped in quotes to avoid escaping & and ?.
http_code = `curl -o /dev/null --silent -Iw '%{http_code}' -L "#{tarball_url}"`
return false if !$?.success? || http_code == "000"
@@artifact_exists_cache[tarball_url] = (http_code == "200")
end
return @@artifact_exists_cache[tarball_url]
end

# Memoized HTTP GET for small metadata lookups (Maven snapshot metadata).
# Returns the Net::HTTPResponse. Only successful responses are cached:
# raised network errors propagate uncached, and non-2xx responses (a
# transient 5xx, a 404) are returned without being stored, so a later
# call within the same process can retry.
def self.memoized_get_response(url)
unless @@get_response_cache.key?(url)
response = Net::HTTP.get_response(URI(url))
return response unless response.is_a?(Net::HTTPSuccess)
@@get_response_cache[url] = response
end
return @@get_response_cache[url]
end

# ==================== #
# Shared download cache #
# ==================== #
Expand Down
27 changes: 22 additions & 5 deletions packages/react-native/sdks/hermes-engine/hermes-utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@
MAVEN_CENTRAL_REPOSITORY = "https://repo1.maven.org/maven2"
REACT_NATIVE_MAVEN_MIRROR_REPOSITORY = "https://repo.reactnative.dev/maven2"

# Memoized results of requests to the Maven repositories (mirror or central).
# hermes-engine.podspec is evaluated several times during a single
# `pod install`, and every evaluation re-resolves the artifact source from
# scratch; without memoization that re-issues identical artifact existence
# probes. The answers should not change within one install, so each request
# is issued at most once per process.
HERMES_ARTIFACT_EXISTS_CACHE = {}

module HermesEngineSourceType
LOCAL_PREBUILT_TARBALL = :local_prebuilt_tarball
DOWNLOAD_PREBUILD_RELEASE_TARBALL = :download_prebuild_release_tarball
Expand Down Expand Up @@ -339,14 +347,23 @@ def resolve_url_redirects(url)

# This function checks that Hermes artifact exists.
# As of now it should check it on the Maven repo.
# The probe is memoized, so repeated podspec evaluations in one `pod install`
# don't re-request the same URL. Only conclusive answers are cached: if curl
# never got an HTTP status (DNS failure, no route, ...) the probe is left
# uncached so a transient hiccup doesn't permanently mark the artifact as
# missing.
#
# Parameters
# - version: the version of React Native
# - build_type: debug or release
# - tarball_url: the URL of the Hermes artifact to probe
def hermes_artifact_exists(tarball_url)
# -L is used to follow redirects, useful for the nightlies
# I also needed to wrap the url in quotes to avoid escaping & and ?.
return (`curl -o /dev/null --silent -Iw '%{http_code}' -L "#{tarball_url}"` == "200")
unless HERMES_ARTIFACT_EXISTS_CACHE.key?(tarball_url)
# -L is used to follow redirects, useful for the nightlies
# I also needed to wrap the url in quotes to avoid escaping & and ?.
http_code = `curl -o /dev/null --silent -Iw '%{http_code}' -L "#{tarball_url}"`
return false if !$?.success? || http_code == "000"
HERMES_ARTIFACT_EXISTS_CACHE[tarball_url] = (http_code == "200")
end
return HERMES_ARTIFACT_EXISTS_CACHE[tarball_url]
end

def hermes_log(message, level = :warning)
Expand Down
Loading