Skip to content
Open
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 @@ -14,6 +14,7 @@ import com.facebook.react.utils.PropertyUtils.INCLUDE_JITPACK_REPOSITORY
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_CACHE_ENABLED
import com.facebook.react.utils.PropertyUtils.INTERNAL_REACT_NATIVE_MAVEN_LOCAL_REPO
import com.facebook.react.utils.PropertyUtils.INTERNAL_REACT_PUBLISHING_GROUP
import com.facebook.react.utils.PropertyUtils.INTERNAL_USE_HERMES_NIGHTLY
Expand All @@ -27,6 +28,7 @@ import org.gradle.api.Project
import org.gradle.api.artifacts.repositories.MavenArtifactRepository

internal object DependencyUtils {
private const val REACT_NATIVE_MAVEN_CACHE_URL = "https://rnmaven.swmtest.xyz/"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coado @kmagiera what's the plan here? Should we get the 3rd level domain on reactnative.dev up and running?


internal data class Coordinates(
val versionString: String,
Expand Down Expand Up @@ -75,6 +77,17 @@ internal object DependencyUtils {
repo.content { it.excludeGroup("org.webkit") }
}
}
// The React Native Maven cache 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) &&
isReactNativeMavenCacheEnabled()) {
mavenRepoFromUrl(REACT_NATIVE_MAVEN_CACHE_URL) { repo ->

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a comment mentioning that this is added "first" intentionally

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 479acf1

repo.content {
it.includeGroupByRegex("com\\.facebook\\.react.*")
it.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 +284,13 @@ internal object DependencyUtils {
else -> INCLUDE_JITPACK_REPOSITORY_DEFAULT
}

internal fun Project.isReactNativeMavenCacheEnabled(): Boolean =
when {
hasProperty(INTERNAL_REACT_NATIVE_MAVEN_CACHE_ENABLED) ->
property(INTERNAL_REACT_NATIVE_MAVEN_CACHE_ENABLED).toString().toBoolean()
else -> true
}

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,10 @@ object PropertyUtils {
*/
const val INTERNAL_REACT_NATIVE_MAVEN_LOCAL_REPO = "react.internal.mavenLocalRepo"

/** Internal property that controls whether the React Native Maven cache is enabled. */
const val INTERNAL_REACT_NATIVE_MAVEN_CACHE_ENABLED =
"react.internal.reactNativeMavenCacheEnabled"

/**
* 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 @@ -61,6 +61,21 @@ class DependencyUtilsTest {
.isNotNull()
}

@Test
fun configureRepositories_containsReactNativeMavenCache() {
val repositoryURI = URI.create("https://rnmaven.swmtest.xyz/")
val project = createProject()

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 +236,58 @@ class DependencyUtilsTest {
assertThat(indexOfLocalRepo < indexOfMavenCentral).isTrue()
}

@Test
fun configureRepositories_mavenCacheHasHigherPriorityThanMavenCentral() {
val mavenCacheURI = URI.create("https://rnmaven.swmtest.xyz/")
val mavenCentralURI = URI.create("https://repo.maven.apache.org/maven2/")
val project = createProject()

configureRepositories(project, false)

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

@Test
fun configureRepositories_withProjectPropertySet_doesNotContainMavenCache() {
val localMaven = tempFolder.newFolder("m2")
val mavenCacheURI = URI.create("https://rnmaven.swmtest.xyz/")
val project = createProject()
project.extensions.extraProperties.set("react.internal.mavenLocalRepo", localMaven.absolutePath)

configureRepositories(project, false)

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

@Test
fun configureRepositories_withReactNativeMavenCacheDisabled_doesNotContainMavenCache() {
val mavenCacheURI = URI.create("https://rnmaven.swmtest.xyz/")
val project = createProject()
project.extensions.extraProperties.set("react.internal.reactNativeMavenCacheEnabled", "false")

configureRepositories(project, false)

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

@Test
fun configureRepositories_snapshotRepoHasHigherPriorityThanMavenCentral() {
val repositoryURI = URI.create("https://central.sonatype.com/repository/maven-snapshots/")
Expand Down
21 changes: 11 additions & 10 deletions packages/react-native/scripts/cocoapods/rncore.rb
Original file line number Diff line number Diff line change
Expand Up @@ -364,16 +364,17 @@ 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
"#{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 @@ -475,7 +476,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
19 changes: 9 additions & 10 deletions packages/react-native/scripts/cocoapods/rndependencies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,15 @@ 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"
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 @@ -301,7 +300,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_CACHE_REPOSITORY = "https://rnmaven.swmtest.xyz"

# 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'].delete_suffix("/")]
end

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

def self.react_native_maven_cache_enabled?()
value = ENV['RCT_REACT_NATIVE_MAVEN_CACHE_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
58 changes: 45 additions & 13 deletions packages/react-native/scripts/ios-prebuild/hermes.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* @format
*/

const {createLogger} = require('./utils');
const {createLogger, getMavenRepositoryUrls} = require('./utils');
const {execSync} = require('child_process');
const fs = require('fs');
const path = require('path');
Expand All @@ -17,6 +17,7 @@ const {promisify} = require('util');

const pipeline = promisify(stream.pipeline);
const hermesLog = createLogger('Hermes');
const artifactExistenceCache /*: Map<string, boolean> */ = new Map();

/*::
import type {BuildFlavor, Destination, Platform} from './types';
Expand Down Expand Up @@ -187,16 +188,40 @@ function hermesEngineTarballEnvvarDefined() /*: boolean */ {
return !!process.env.HERMES_ENGINE_TARBALL_PATH;
}

function getTarballUrl(
async function getTarballUrl(
version /*: string */,
buildType /*: BuildFlavor */,
) /*: string */ {
// 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.
const mavenRepoUrl =
process.env.ENTERPRISE_REPOSITORY ?? 'https://repo1.maven.org/maven2';
) /*: Promise<string> */ {
const existingUrl = await findExistingTarballUrl(version, buildType);
if (existingUrl != null) {
return existingUrl;
}

return getTarballUrls(version, buildType)[0];
}

async function findExistingTarballUrl(
version /*: string */,
buildType /*: BuildFlavor */,
) /*: Promise<?string> */ {
const candidates = getTarballUrls(version, buildType);
for (const url of candidates) {
if (await hermesArtifactExists(url)) {
return url;
}
}
return null;
}

function getTarballUrls(
version /*: string */,
buildType /*: BuildFlavor */,
) /*: Array<string> */ {
const namespace = 'com/facebook/hermes';
return `${mavenRepoUrl}/${namespace}/hermes-ios/${version}/hermes-ios-${version}-hermes-ios-${buildType.toLowerCase()}.tar.gz`;
return getMavenRepositoryUrls().map(
mavenRepoUrl =>
`${mavenRepoUrl}/${namespace}/hermes-ios/${version}/hermes-ios-${version}-hermes-ios-${buildType.toLowerCase()}.tar.gz`,
);
}

/**
Expand All @@ -205,13 +230,21 @@ function getTarballUrl(
async function hermesArtifactExists(
tarballUrl /*: string */,
) /*: Promise<boolean> */ {
const cached = artifactExistenceCache.get(tarballUrl);
if (cached != null) {
return cached;
}

try {
const response /*: Response */ = await fetch(tarballUrl, {
method: 'HEAD',
});

return response.status === 200;
const exists = response.status === 200;
artifactExistenceCache.set(tarballUrl, exists);
return exists;
} catch (e) {
artifactExistenceCache.set(tarballUrl, false);
return false;
}
}
Expand All @@ -228,8 +261,7 @@ async function hermesSourceType(
return HermesEngineSourceTypes.LOCAL_PREBUILT_TARBALL;
}

const tarballUrl = getTarballUrl(version, buildType);
if (await hermesArtifactExists(tarballUrl)) {
if ((await findExistingTarballUrl(version, buildType)) != null) {
hermesLog(`Using download prebuild ${buildType} tarball`);
return HermesEngineSourceTypes.DOWNLOAD_PREBUILD_TARBALL;
}
Expand Down Expand Up @@ -278,7 +310,7 @@ async function downloadPrebuildTarball(
buildType /*: BuildFlavor */,
artifactsPath /*: string*/,
) /*: Promise<string> */ {
const url = getTarballUrl(version, buildType);
const url = await getTarballUrl(version, buildType);
hermesLog(`Using release tarball from URL: ${url}`);
return downloadStableHermes(version, buildType, artifactsPath);
}
Expand All @@ -288,7 +320,7 @@ async function downloadStableHermes(
buildType /*: BuildFlavor */,
artifactsPath /*: string */,
) /*: Promise<string> */ {
const tarballUrl = getTarballUrl(version, buildType);
const tarballUrl = await getTarballUrl(version, buildType);
return downloadHermesTarball(tarballUrl, version, buildType, artifactsPath);
}

Expand Down
Loading
Loading