tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit aef968f913e56025ffde51ac337202463b3f07a9
parent a3bd4af336aa43a95a19d3be0fa9434934ad725c
Author: Alex Hochheiden <ahochheiden@mozilla.com>
Date:   Thu,  4 Dec 2025 17:28:42 +0000

Bug 2001450 - Configuration time optimizations for `NimbusGradlePlugin` r=nalexander,geckoview-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D273494

Diffstat:
Mmobile/android/gradle/plugins/nimbus-gradle-plugin/src/main/groovy/org/mozilla/appservices/tooling/nimbus/NimbusAssembleToolsTask.groovy | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Mmobile/android/gradle/plugins/nimbus-gradle-plugin/src/main/groovy/org/mozilla/appservices/tooling/nimbus/NimbusFmlCommandTask.groovy | 13+++++--------
Mmobile/android/gradle/plugins/nimbus-gradle-plugin/src/main/groovy/org/mozilla/appservices/tooling/nimbus/NimbusGradlePlugin.groovy | 180++++++++++++++++++++++++++++++++++++-------------------------------------------
3 files changed, 137 insertions(+), 106 deletions(-)

diff --git a/mobile/android/gradle/plugins/nimbus-gradle-plugin/src/main/groovy/org/mozilla/appservices/tooling/nimbus/NimbusAssembleToolsTask.groovy b/mobile/android/gradle/plugins/nimbus-gradle-plugin/src/main/groovy/org/mozilla/appservices/tooling/nimbus/NimbusAssembleToolsTask.groovy @@ -13,6 +13,8 @@ import org.gradle.api.file.RegularFileProperty import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.provider.ProviderFactory import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.LocalState @@ -43,6 +45,9 @@ abstract class NimbusAssembleToolsTask extends DefaultTask { @Inject abstract ArchiveOperations getArchiveOperations() + @Inject + abstract ProviderFactory getProviders() + @Nested abstract FetchSpec getFetchSpec() @@ -64,6 +69,51 @@ abstract class NimbusAssembleToolsTask extends DefaultTask { @OutputFile abstract RegularFileProperty getFmlBinary() + /** The platform string (e.g. "x86_64-pc-windows-gnu"). */ + @Input + abstract Property<String> getPlatform() + + NimbusAssembleToolsTask() { + platform.convention(detectPlatform(providers)) + } + + private static Provider<String> detectPlatform(ProviderFactory providers) { + def osProvider = providers.systemProperty("os.name").map { it.toLowerCase() } + def archProvider = providers.systemProperty("os.arch").map { it.toLowerCase() } + + return osProvider.zip(archProvider) { os, arch -> + String osPart + if (os.contains("win")) { + osPart = "pc-windows-gnu" + } else if (os.contains("nix") || os.contains("nux") || os.contains("aix")) { + osPart = "unknown-linux" + } else if (os.contains("mac")) { + osPart = "apple-darwin" + } else { + osPart = "unknown" + } + + String archPart + if (arch.contains("x86_64")) { + archPart = "x86_64" + } else if (arch.contains("amd64")) { + archPart = "x86_64" + } else if (arch.contains("aarch")) { + archPart = "aarch64" + } else { + archPart = "unknown" + } + return "${archPart}-${osPart}" + } + } + + static String getBinaryName(String platform) { + if (platform.contains("windows")) { + return "nimbus-fml.exe" + } + return "nimbus-fml" + } + /** * Configures the task to download the archive. * diff --git a/mobile/android/gradle/plugins/nimbus-gradle-plugin/src/main/groovy/org/mozilla/appservices/tooling/nimbus/NimbusFmlCommandTask.groovy b/mobile/android/gradle/plugins/nimbus-gradle-plugin/src/main/groovy/org/mozilla/appservices/tooling/nimbus/NimbusFmlCommandTask.groovy @@ -6,11 +6,13 @@ package org.mozilla.tooling.nimbus import org.gradle.api.DefaultTask import org.gradle.api.GradleException +import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.ProjectLayout import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Optional import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity @@ -41,9 +43,6 @@ abstract class NimbusFmlCommandTask extends DefaultTask { abstract ProjectLayout getProjectLayout() @Input - abstract Property<String> getProjectDir() - - @Input @Optional abstract Property<String> getApplicationServicesDir() @@ -68,18 +67,16 @@ abstract class NimbusFmlCommandTask extends DefaultTask { void execute() { execOperations.exec { spec -> spec.with { - // Absolutize `projectDir`, so that we can resolve our paths - // against it. If it's already absolute, it'll be used as-is. - def projectDir = projectLayout.projectDirectory.dir(projectDir.get()) + def projDir = projectLayout.projectDirectory def localAppServices = applicationServicesDir.getOrNull() if (localAppServices == null) { if (!fmlBinary.get().asFile.exists()) { throw new GradleException("`nimbus-fml` wasn't downloaded and `nimbus.applicationServicesDir` isn't set") } - workingDir projectDir + workingDir projDir commandLine fmlBinary.get().asFile } else { - def cargoManifest = projectDir.file("$localAppServices/$APPSERVICES_FML_HOME/Cargo.toml").asFile + def cargoManifest = projDir.file("$localAppServices/$APPSERVICES_FML_HOME/Cargo.toml").asFile commandLine 'cargo' args 'run' diff --git a/mobile/android/gradle/plugins/nimbus-gradle-plugin/src/main/groovy/org/mozilla/appservices/tooling/nimbus/NimbusGradlePlugin.groovy b/mobile/android/gradle/plugins/nimbus-gradle-plugin/src/main/groovy/org/mozilla/appservices/tooling/nimbus/NimbusGradlePlugin.groovy @@ -4,6 +4,7 @@ package org.mozilla.tooling.nimbus +import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.file.Directory @@ -11,6 +12,33 @@ import org.gradle.api.provider.ListProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider +import org.gradle.api.provider.ValueSource +import org.gradle.api.provider.ValueSourceParameters + +abstract class ApplicationServicesVersionSource implements ValueSource<String, ApplicationServicesVersionSource.Parameters> { + interface Parameters extends ValueSourceParameters { + Property<String> getTopsrcdir() + Property<String> getLocalPropertiesVersion() + } + + @Override + String obtain() { + // Check for override from local properties first + def localVersion = parameters.localPropertiesVersion.getOrNull() + if (localVersion != null) { + return localVersion + } + // Extract from a generated .kt file + def topsrcdir = parameters.topsrcdir.get() + def appServicesFile = new File(topsrcdir, "mobile/android/android-components/plugins/dependencies/src/main/java/ApplicationServices.kt") + def versionLine = appServicesFile.readLines().find { it.startsWith("val VERSION = ") } + if (versionLine) { + // Extract version from: val VERSION = "143.20250816050436" + return versionLine.split('"')[1] + } + throw new GradleException("Could not determine application-services version from ${appServicesFile.absolutePath}") + } +} abstract class NimbusPluginExtension { /** @@ -93,21 +121,21 @@ class NimbusPlugin implements Plugin<Project> { // We need to locate our nimbus-fml tool - prior to app-services moving into mozilla-firefox, we // download this tool from taskcluster. After the move of app-services, we expect the tool to exist - // locally having been build by `./mach build`. + // locally having been built by `./mach build`. if (project.gradle.ext.mozconfig.substs.MOZ_APPSERVICES_IN_TREE) { // we assume the binary has been built by mach. def mozconfig = project.gradle.mozconfig - def fmlBinary = "${mozconfig.topobjdir}/dist/host/bin/nimbus-fml" + def fmlBinaryFile = project.layout.projectDirectory.file("${mozconfig.topobjdir}/dist/host/bin/nimbus-fml") // Configure the task with proper file type validateTask.configure { task -> - task.fmlBinary = project.file(fmlBinary) + task.fmlBinary = fmlBinaryFile } // Set up Android variants for both application and library plugins setupAndroidVariants(project, validateTask) { generateTask -> generateTask.configure { task -> - task.fmlBinary = project.file(fmlBinary) + task.fmlBinary = fmlBinaryFile task.dependsOn validateTask } } @@ -159,31 +187,44 @@ class NimbusPlugin implements Plugin<Project> { // Setup the tasks to download the binary. def setupAssembleNimbusTools(Project project) { def applicationServicesDir = project.nimbus.applicationServicesDir + def asVersionProvider = getProjectVersionProvider(project) + return project.tasks.register('assembleNimbusTools', NimbusAssembleToolsTask) { task -> group "Nimbus" description "Fetch the Nimbus FML tools from Application Services" - def asVersion = getProjectVersion(project) - def fmlRoot = getFMLRoot(project, asVersion) + def fmlRoot = project.layout.buildDirectory.dir(asVersionProvider.map { version -> + "bin/nimbus/$version" + }) archiveFile = fmlRoot.map { it.file('nimbus-fml.zip') } hashFile = fmlRoot.map { it.file('nimbus-fml.sha256') } - fmlBinary = fmlRoot.map { it.file(getFMLFile()) } + fmlBinary = fmlRoot.zip(platform) { root, plat -> + root.file(NimbusAssembleToolsTask.getBinaryName(plat)) + } fetch { // Try archive.mozilla.org release first - archive = "https://archive.mozilla.org/pub/app-services/releases/$asVersion/nimbus-fml.zip" - hash = "https://archive.mozilla.org/pub/app-services/releases/$asVersion/nimbus-fml.sha256" + archive = asVersionProvider.map { asVersion -> + "https://archive.mozilla.org/pub/app-services/releases/$asVersion/nimbus-fml.zip" + } + hash = asVersionProvider.map { asVersion -> + "https://archive.mozilla.org/pub/app-services/releases/$asVersion/nimbus-fml.sha256" + } // Fall back to a nightly release fallback { - archive = "https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/project.application-services.v2.nimbus-fml.$asVersion/artifacts/public/build/nimbus-fml.zip" - hash = "https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/project.application-services.v2.nimbus-fml.$asVersion/artifacts/public/build/nimbus-fml.sha256" + archive = asVersionProvider.map { asVersion -> + "https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/project.application-services.v2.nimbus-fml.$asVersion/artifacts/public/build/nimbus-fml.zip" + } + hash = asVersionProvider.map { asVersion -> + "https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/project.application-services.v2.nimbus-fml.$asVersion/artifacts/public/build/nimbus-fml.sha256" + } } } unzip { - include "${getArchOs()}*/release/nimbus-fml*" + include "${platform.get()}*/release/nimbus-fml*" } onlyIf('`applicationServicesDir` == null') { @@ -192,68 +233,28 @@ class NimbusPlugin implements Plugin<Project> { } } - /** - * The directory where nimbus-fml will live. - * We put it in a build directory so we refresh it on a clean build. - * @param project - * @param version - * @return - */ - static Provider<Directory> getFMLRoot(Project project, String version) { - return project.layout.buildDirectory.dir("bin/nimbus/$version") - } - - static def getArchOs() { - String osPart - String os = System.getProperty("os.name").toLowerCase() - if (os.contains("win")) { - osPart = "pc-windows-gnu" - } else if (os.contains("nix") || os.contains("nux") || os.contains("aix")) { - osPart = "unknown-linux" - } else if (os.contains("mac")) { - osPart = "apple-darwin" - } else { - osPart = "unknown" - } + Provider<String> getProjectVersionProvider(Project project) { + def topsrcdir = project.gradle.mozconfig.topsrcdir + def localPropertiesVersion = project.gradle.hasProperty("localProperties.branchBuild.application-services.version") + ? project.gradle["localProperties.branchBuild.application-services.version"] + : null - String arch = System.getProperty("os.arch").toLowerCase() - String archPart - if (arch.contains("x86_64")) { - archPart = "x86_64" - } else if (arch.contains("amd64")) { - archPart = "x86_64" - } else if (arch.contains("aarch")) { - archPart = "aarch64" - } else { - archPart = "unknown" + return project.providers.of(ApplicationServicesVersionSource) { spec -> + spec.parameters.topsrcdir.set(topsrcdir) + spec.parameters.localPropertiesVersion.set(localPropertiesVersion) } - println("OS and architecture detected as $os on $arch") - return "${archPart}-${osPart}" } - static String getFMLFile() { - String os = System.getProperty("os.name").toLowerCase() - String binaryName = "nimbus-fml" - if (os.contains("win")) { - binaryName = "nimbus-fml.exe" + private void configureCommonTaskProperties(task, Project project, String cacheDirSuffix) { + task.repoFiles = project.files(project.nimbus.repoFiles) + task.applicationServicesDir = project.nimbus.applicationServicesDir + task.inputFile = project.layout.projectDirectory.file(project.nimbus.manifestFile) + // Each task gets its own cache subdirectory because Gradle discourages + // "overlapping outputs" which inhibit caching and parallelization + // (https://github.com/gradle/gradle/issues/28394). + task.cacheDir = project.layout.buildDirectory.dir(project.nimbus.cacheDir).map { + it.dir(cacheDirSuffix) } - return binaryName - } - - String getProjectVersion(Project project) { - // Check for override from local properties first - if (project.gradle.hasProperty("localProperties.branchBuild.application-services.version")) { - return project.gradle["localProperties.branchBuild.application-services.version"] - } - // This in particular is, um, sad. Extract from a generated .kt - def topsrcdir = project.gradle.mozconfig.topsrcdir - def appServicesFile = new File(topsrcdir, "mobile/android/android-components/plugins/dependencies/src/main/java/ApplicationServices.kt") - def versionLine = appServicesFile.readLines().find { it.startsWith("val VERSION = ") } - if (versionLine) { - // Extract version from: val VERSION = "143.20250816050436" - return versionLine.split('"')[1] - } - throw new RuntimeException("Could not determine application-services version from ${appServicesFile.absolutePath}") } def setupNimbusFeatureTasks(Object variant, Project project) { @@ -262,29 +263,18 @@ class NimbusPlugin implements Plugin<Project> { group = "Nimbus" doFirst { - println("Nimbus FML generating Kotlin") - println("manifest ${inputFile.get().asFile}") - println("cache dir ${cacheDir.get().asFile}") - println("repo file(s) ${repoFiles.files.join()}") - println("channel ${channel.get()}") + logger.info("Nimbus FML generating Kotlin") + logger.info("manifest {}", inputFile.get().asFile) + logger.info("cache dir {}", cacheDir.get().asFile) + logger.info("repo file(s) {}", repoFiles.files.join()) + logger.info("channel {}", channel.get()) } doLast { - println("outputFile ${outputDir.get().asFile}") + logger.info("outputFile {}", outputDir.get().asFile) } - projectDir = project.rootDir.toString() - repoFiles = project.files(project.nimbus.repoFiles) - applicationServicesDir = project.nimbus.applicationServicesDir - inputFile = project.layout.projectDirectory.file(project.nimbus.manifestFile) - cacheDir = project.layout.buildDirectory.dir(project.nimbus.cacheDir).map { - // The `nimbusFeatures*` and `nimbusValidate` tasks can - // technically use the same cache directory, but Gradle - // discourages this, because such "overlapping outputs" - // inhibit caching and parallelization - // (https://github.com/gradle/gradle/issues/28394). - it.dir("features${variant.name.capitalize()}") - } + configureCommonTaskProperties(delegate, project, "features${variant.name.capitalize()}") channel = project.nimbus.channels.getting(variant.name).orElse(variant.name) outputDir = project.layout.buildDirectory.dir("generated/source/nimbus/${variant.name}/kotlin") } @@ -296,19 +286,13 @@ class NimbusPlugin implements Plugin<Project> { group = "Nimbus" doFirst { - println("Nimbus FML: validating manifest") - println("manifest ${inputFile.get().asFile}") - println("cache dir ${cacheDir.get().asFile}") - println("repo file(s) ${repoFiles.files.join()}") + logger.info("Nimbus FML: validating manifest") + logger.info("manifest {}", inputFile.get().asFile) + logger.info("cache dir {}", cacheDir.get().asFile) + logger.info("repo file(s) {}", repoFiles.files.join()) } - projectDir = project.rootDir.toString() - repoFiles = project.files(project.nimbus.repoFiles) - applicationServicesDir = project.nimbus.applicationServicesDir - inputFile = project.layout.projectDirectory.file(project.nimbus.manifestFile) - cacheDir = project.layout.buildDirectory.dir(project.nimbus.cacheDir).map { - it.dir('validate') - } + configureCommonTaskProperties(delegate, project, 'validate') // `nimbusValidate` doesn't have any outputs, so Gradle will always // run it, even if its inputs haven't changed. This predicate tells