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
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import com.facebook.react.utils.PropertyUtils.INCLUDE_JITPACK_REPOSITORY_DEFAULT
import com.facebook.react.utils.PropertyUtils.INTERNAL_HERMES_PUBLISHING_GROUP
import com.facebook.react.utils.PropertyUtils.INTERNAL_HERMES_VERSION_NAME
import com.facebook.react.utils.PropertyUtils.INTERNAL_REACT_NATIVE_MAVEN_LOCAL_REPO
import com.facebook.react.utils.PropertyUtils.INTERNAL_REACT_NATIVE_MAVEN_MIRROR_ENABLED
import com.facebook.react.utils.PropertyUtils.INTERNAL_REACT_NATIVE_MAVEN_MIRROR_ENABLED_DEFAULT
import com.facebook.react.utils.PropertyUtils.INTERNAL_REACT_PUBLISHING_GROUP
import com.facebook.react.utils.PropertyUtils.INTERNAL_USE_HERMES_NIGHTLY
import com.facebook.react.utils.PropertyUtils.INTERNAL_VERSION_NAME
Expand All @@ -27,6 +29,8 @@ import org.gradle.api.Project
import org.gradle.api.artifacts.repositories.MavenArtifactRepository

internal object DependencyUtils {
private const val REACT_NATIVE_MAVEN_MIRROR_URL = "https://repo.reactnative.dev/maven2"
private const val REACT_NATIVE_MAVEN_MIRROR_ENABLED_ENV = "RCT_REACT_NATIVE_MAVEN_MIRROR_ENABLED"

internal data class Coordinates(
val versionString: String,
Expand Down Expand Up @@ -75,6 +79,19 @@ internal object DependencyUtils {
repo.content { it.excludeGroup("org.webkit") }
}
}
// The React Native Maven mirror must be added before Maven Central so it can serve cached
// artifacts first, while Maven Central remains the fallback.
if (
!hasProperty(INTERNAL_REACT_NATIVE_MAVEN_LOCAL_REPO) &&
isReactNativeMavenMirrorEnabled()
) {
mavenRepoFromUrl(REACT_NATIVE_MAVEN_MIRROR_URL) { repo ->
repo.content { content ->
content.includeGroupByRegex("com\\.facebook\\.react.*")
content.includeGroupByRegex("com\\.facebook\\.hermes.*")
}
}
}
repositories.mavenCentral { repo ->
// We don't want to fetch JSC from Maven Central as there are older versions there.
repo.content { it.excludeGroup("org.webkit") }
Expand Down Expand Up @@ -271,6 +288,19 @@ internal object DependencyUtils {
else -> INCLUDE_JITPACK_REPOSITORY_DEFAULT
}

internal fun Project.isReactNativeMavenMirrorEnabled(
environmentValue: String? = System.getenv(REACT_NATIVE_MAVEN_MIRROR_ENABLED_ENV)
): Boolean =
when {
hasProperty(INTERNAL_REACT_NATIVE_MAVEN_MIRROR_ENABLED) -> {
val value = property(INTERNAL_REACT_NATIVE_MAVEN_MIRROR_ENABLED).toString()
!value.equals("false", ignoreCase = true) && value != "0"
}
!environmentValue.isNullOrEmpty() ->
!environmentValue.equals("false", ignoreCase = true) && environmentValue != "0"
else -> INTERNAL_REACT_NATIVE_MAVEN_MIRROR_ENABLED_DEFAULT
}

internal fun String.isNightly(): Boolean = this.startsWith("0.0.0") || "-nightly-" in this

internal fun Project.exclusiveEnterpriseRepository() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ object PropertyUtils {
*/
const val INTERNAL_REACT_NATIVE_MAVEN_LOCAL_REPO = "react.internal.mavenLocalRepo"

/** Internal property that controls the React Native Maven mirror, which is enabled by default. */
const val INTERNAL_REACT_NATIVE_MAVEN_MIRROR_ENABLED =
"react.internal.reactNativeMavenMirrorEnabled"
const val INTERNAL_REACT_NATIVE_MAVEN_MIRROR_ENABLED_DEFAULT = true

/**
* Internal property used to specify where the Windows Bash executable is located. This is useful
* for contributors who are running Windows on their machine.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.facebook.react.utils.DependencyUtils.configureRepositories
import com.facebook.react.utils.DependencyUtils.exclusiveEnterpriseRepository
import com.facebook.react.utils.DependencyUtils.getDependencySubstitutions
import com.facebook.react.utils.DependencyUtils.isNightly
import com.facebook.react.utils.DependencyUtils.isReactNativeMavenMirrorEnabled
import com.facebook.react.utils.DependencyUtils.mavenRepoFromURI
import com.facebook.react.utils.DependencyUtils.mavenRepoFromUrl
import com.facebook.react.utils.DependencyUtils.readVersionAndGroupStrings
Expand Down Expand Up @@ -61,6 +62,22 @@ class DependencyUtilsTest {
.isNotNull()
}

@Test
fun configureRepositories_withReactNativeMavenMirrorEnabled_containsMavenMirror() {
val repositoryURI = URI.create("https://repo.reactnative.dev/maven2")
val project = createProject()
project.extensions.extraProperties.set("react.internal.reactNativeMavenMirrorEnabled", "true")

configureRepositories(project, false)

assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
.isNotNull()
}

@Test
fun configureRepositories_containsGoogleRepo() {
val repositoryURI = URI.create("https://dl.google.com/dl/android/maven2/")
Expand Down Expand Up @@ -221,6 +238,107 @@ class DependencyUtilsTest {
assertThat(indexOfLocalRepo < indexOfMavenCentral).isTrue()
}

@Test
fun configureRepositories_mavenMirrorHasHigherPriorityThanMavenCentral() {
val mavenMirrorURI = URI.create("https://repo.reactnative.dev/maven2")
val mavenCentralURI = URI.create("https://repo.maven.apache.org/maven2/")
val project = createProject()
project.extensions.extraProperties.set("react.internal.reactNativeMavenMirrorEnabled", "true")

configureRepositories(project, false)

val indexOfMavenMirror =
project.repositories.indexOfFirst {
it is MavenArtifactRepository && it.url == mavenMirrorURI
}
val indexOfMavenCentral =
project.repositories.indexOfFirst {
it is MavenArtifactRepository && it.url == mavenCentralURI
}
assertThat(indexOfMavenMirror < indexOfMavenCentral).isTrue()
}

@Test
fun configureRepositories_withProjectPropertySet_doesNotContainMavenMirror() {
val localMaven = tempFolder.newFolder("m2")
val mavenMirrorURI = URI.create("https://repo.reactnative.dev/maven2")
val project = createProject()
project.extensions.extraProperties.set("react.internal.mavenLocalRepo", localMaven.absolutePath)

configureRepositories(project, false)

assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == mavenMirrorURI
}
)
.isNull()
}

@Test
fun configureRepositories_byDefault_containsMavenMirror() {
val mavenMirrorURI = URI.create("https://repo.reactnative.dev/maven2")
val project = createProject()

configureRepositories(project, false)

assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == mavenMirrorURI
}
)
.isNotNull()
}

@Test
fun configureRepositories_withReactNativeMavenMirrorDisabled_doesNotContainMavenMirror() {
val mavenMirrorURI = URI.create("https://repo.reactnative.dev/maven2")
val project = createProject()
project.extensions.extraProperties.set("react.internal.reactNativeMavenMirrorEnabled", "false")

configureRepositories(project, false)

assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == mavenMirrorURI
}
)
.isNull()
}

@Test
fun isReactNativeMavenMirrorEnabled_withEnvironmentVariableEnabled_returnsTrue() {
val project = createProject()

assertThat(project.isReactNativeMavenMirrorEnabled("true")).isTrue()
assertThat(project.isReactNativeMavenMirrorEnabled("1")).isTrue()
}

@Test
fun isReactNativeMavenMirrorEnabled_withEnvironmentVariableDisabled_returnsFalse() {
val project = createProject()

assertThat(project.isReactNativeMavenMirrorEnabled("false")).isFalse()
assertThat(project.isReactNativeMavenMirrorEnabled("FALSE")).isFalse()
assertThat(project.isReactNativeMavenMirrorEnabled("0")).isFalse()
}

@Test
fun isReactNativeMavenMirrorEnabled_byDefault_returnsTrue() {
val project = createProject()

assertThat(project.isReactNativeMavenMirrorEnabled(null)).isTrue()
assertThat(project.isReactNativeMavenMirrorEnabled("")).isTrue()
}

@Test
fun isReactNativeMavenMirrorEnabled_withProjectProperty_ignoresEnvironmentVariable() {
val project = createProject()
project.extensions.extraProperties.set("react.internal.reactNativeMavenMirrorEnabled", "false")

assertThat(project.isReactNativeMavenMirrorEnabled("true")).isFalse()
}

@Test
fun configureRepositories_snapshotRepoHasHigherPriorityThanMavenCentral() {
val repositoryURI = URI.create("https://central.sonatype.com/repository/maven-snapshots/")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

require "test/unit"
require_relative "../utils.rb"
require_relative "../../../sdks/hermes-engine/hermes-utils.rb"

class MavenMirrorFlagTests < Test::Unit::TestCase
def setup
@original_value = ENV['RCT_REACT_NATIVE_MAVEN_MIRROR_ENABLED']
ENV.delete('RCT_REACT_NATIVE_MAVEN_MIRROR_ENABLED')
end

def teardown
if @original_value == nil
ENV.delete('RCT_REACT_NATIVE_MAVEN_MIRROR_ENABLED')
else
ENV['RCT_REACT_NATIVE_MAVEN_MIRROR_ENABLED'] = @original_value
end
end

def test_mavenMirror_isEnabledByDefault
assert_true(ReactNativePodsUtils.react_native_maven_mirror_enabled?)
assert_true(react_native_maven_mirror_enabled?)
end

def test_mavenMirror_isEnabledWhenExplicitlySetToTrue
ENV['RCT_REACT_NATIVE_MAVEN_MIRROR_ENABLED'] = 'true'

assert_true(ReactNativePodsUtils.react_native_maven_mirror_enabled?)
assert_true(react_native_maven_mirror_enabled?)
end

def test_mavenMirror_isDisabledWhenExplicitlySetToFalse
ENV['RCT_REACT_NATIVE_MAVEN_MIRROR_ENABLED'] = 'false'

assert_false(ReactNativePodsUtils.react_native_maven_mirror_enabled?)
assert_false(react_native_maven_mirror_enabled?)
end
end
24 changes: 14 additions & 10 deletions packages/react-native/scripts/cocoapods/rncore.rb
Original file line number Diff line number Diff line change
Expand Up @@ -350,16 +350,20 @@ def self.generate_plist_content(mappings)
end

def self.stable_tarball_url(version, build_type, dsyms = false)
## You can use the `ENTERPRISE_REPOSITORY` ariable to customise the base url from which artifacts will be downloaded.
## The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central.
maven_repo_url =
ENV['ENTERPRISE_REPOSITORY'] != nil && ENV['ENTERPRISE_REPOSITORY'] != "" ?
ENV['ENTERPRISE_REPOSITORY'] :
"https://repo1.maven.org/maven2"
candidates = stable_tarball_urls(version, build_type, dsyms)
return candidates.find { |url| artifact_exists(url) } || candidates.first
end

def self.stable_tarball_urls(version, build_type, dsyms = false)
group = "com/facebook/react"
# Sample url from Maven:
# https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.81.0/react-native-artifacts-0.81.0-reactnative-core-debug.tar.gz
return "#{maven_repo_url}/#{group}/react-native-artifacts/#{version}/react-native-artifacts-#{version}-reactnative-core-#{dsyms ? "dSYM-" : ""}#{build_type.to_s}.tar.gz"
return ReactNativePodsUtils.maven_repository_urls().map { |maven_repo_url|
# Sample url from Maven:
# https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.81.0/react-native-artifacts-0.81.0-reactnative-core-debug.tar.gz

# Sample url from mirror server:
# https://repo.reactnative.dev/maven2/com/facebook/react/react-native-artifacts/0.81.0/react-native-artifacts-0.81.0-reactnative-core-debug.tar.gz
"#{maven_repo_url}/#{group}/react-native-artifacts/#{version}/react-native-artifacts-#{version}-reactnative-core-#{dsyms ? "dSYM-" : ""}#{build_type.to_s}.tar.gz"
}
end

def self.nightly_tarball_url(version, configuration, dsyms = false)
Expand Down Expand Up @@ -461,7 +465,7 @@ def self.download_rncore_tarball(react_native_path, tarball_url, version, config
end

def self.release_artifact_exists(version)
return artifact_exists(stable_tarball_url(version, :debug))
return stable_tarball_urls(version, :debug).any? { |url| artifact_exists(url) }
end

def self.nightly_artifact_exists(version)
Expand Down
21 changes: 13 additions & 8 deletions packages/react-native/scripts/cocoapods/rndependencies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -226,16 +226,21 @@ def self.podspec_source_download_prebuild_release_tarball()
end

def self.release_tarball_url(version, build_type)
## You can use the `ENTERPRISE_REPOSITORY` ariable to customise the base url from which artifacts will be downloaded.
## The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central.
maven_repo_url =
ENV['ENTERPRISE_REPOSITORY'] != nil && ENV['ENTERPRISE_REPOSITORY'] != "" ?
ENV['ENTERPRISE_REPOSITORY'] :
"https://repo1.maven.org/maven2"
candidates = release_tarball_urls(version, build_type)
return candidates.find { |url| artifact_exists(url) } || candidates.first
end

def self.release_tarball_urls(version, build_type)
group = "com/facebook/react"

# Sample url from Maven:
# https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.79.0-rc.0/react-native-artifacts-0.79.0-rc.0-reactnative-dependencies-debug.tar.gz
return "#{maven_repo_url}/#{group}/react-native-artifacts/#{version}/react-native-artifacts-#{version}-reactnative-dependencies-#{build_type.to_s}.tar.gz"

# Sample url from mirror server:
# https://repo.reactnative.dev/maven2/com/facebook/react/react-native-artifacts/0.79.0-rc.0/react-native-artifacts-0.79.0-rc.0-reactnative-dependencies-debug.tar.gz
return ReactNativePodsUtils.maven_repository_urls().map { |maven_repo_url|
"#{maven_repo_url}/#{group}/react-native-artifacts/#{version}/react-native-artifacts-#{version}-reactnative-dependencies-#{build_type.to_s}.tar.gz"
}
end

def self.nightly_tarball_url(version, build_type)
Expand Down Expand Up @@ -362,7 +367,7 @@ def self.download_rndeps_tarball(react_native_path, tarball_url, version, config
end

def self.release_artifact_exists(version)
return artifact_exists(release_tarball_url(version, :debug))
return release_tarball_urls(version, :debug).any? { |url| artifact_exists(url) }
end

def self.nightly_artifact_exists(version)
Expand Down
24 changes: 24 additions & 0 deletions packages/react-native/scripts/cocoapods/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,35 @@

# Utilities class for React Native Cocoapods
class ReactNativePodsUtils
MAVEN_CENTRAL_REPOSITORY = "https://repo1.maven.org/maven2"
REACT_NATIVE_MAVEN_MIRROR_REPOSITORY = "https://repo.reactnative.dev/maven2"

# URI::File.build validates path components as ASCII, so escape the filesystem path first.
def self.local_file_uri(path)
URI::File.build(path: URI::DEFAULT_PARSER.escape(path)).to_s
end

def self.maven_repository_urls()
## You can use the `ENTERPRISE_REPOSITORY` variable to customise the base url from which artifacts will be downloaded.
## The mirror's structure must be the same of the Maven repo the react-native core team publishes on Maven Central.
if ENV['ENTERPRISE_REPOSITORY'] != nil && ENV['ENTERPRISE_REPOSITORY'] != ""
return [ENV['ENTERPRISE_REPOSITORY'].sub(/\/+$/, "")]
end

# Keep the React Native Maven mirror before Maven Central so cached artifacts are tried first
# and Maven Central remains the fallback.
return react_native_maven_mirror_enabled? ?
[REACT_NATIVE_MAVEN_MIRROR_REPOSITORY, MAVEN_CENTRAL_REPOSITORY] :
[MAVEN_CENTRAL_REPOSITORY]
end

def self.react_native_maven_mirror_enabled?()
value = ENV['RCT_REACT_NATIVE_MAVEN_MIRROR_ENABLED']
return true if value == nil || value == ""

value.downcase != "false" && value != "0"
end

def self.warn_if_not_on_arm64
if SysctlChecker.new().call_sysctl_arm64() == 1 && !Environment.new().ruby_platform().include?('arm64')
Pod::UI.warn 'Do not use "pod install" from inside Rosetta2 (x86_64 emulation on arm64).'
Expand Down
Loading
Loading