2019-08-15 21:18:24 +00:00
/ * This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http: //mozilla.org/MPL/2.0/. */
// Substitute a local GeckoView AAR into a consuming Gradle project.
//
// To use this, in a consuming Gradle project's `/build.gradle` add a stanza like:
//
// ext.topsrcdir = '/absolute/path/to/mozilla-central'; apply from: "${ext.topsrcdir}/substitute-local-geckoview.gradle"
//
// The object directory will be determined using `mach environment` and will agree with `./mach
// gradle` and Android Studio. Or, specify the exact object directory with a stanza like:
//
// ext.topsrcdir = '/absolute/path/to/mozilla-central'
// ext.topobjdir = '/absolute/path/to/objdir'
// apply from: "${ext.topsrcdir}/substitute-local-geckoview.gradle"
//
// Substitution works with artifact and non-artifact builds.
//
// If you get errors about .jar files not being found, ensure that the consuming
// application is using a recent Android-Gradle plugin (say, 3.4+). There were
// issues with Jetifier, and issues with .jar vs. .aar extensions, in older
// versions.
import groovy.json.JsonSlurper
def log ( message ) {
logger . lifecycle ( "[substitute-local-geckoview] ${message}" )
}
2021-08-10 20:24:33 +00:00
def warn ( message ) {
logger . warn ( "[substitute-local-geckoview] Warning: ${message}" )
}
2019-08-15 21:18:24 +00:00
if ( ! project . ext . has ( 'topsrcdir' ) ) {
throw new GradleException ( "ext.topsrcdir must be specified to substitute for a local GeckoView" )
}
2021-12-07 17:53:25 +00:00
/ * *
* Loads the mozconfig and returns any variables derived from it , avoiding side effects .
*
* This method is relatively slow because it calls mach , which starts a python interpreter , will
* becomes very slow if called for numerous subprojects . Therefore , it should only be called once
* per build .
* /
def loadMozconfig ( ) {
apply from: "${topsrcdir}/mobile/android/gradle/mach_env.gradle"
// Cribbed from https://hg.mozilla.org/mozilla-central/file/tip/settings.gradle. When run in
// topobjdir, `mach environment` correctly finds the mozconfig corresponding to that object
// directory.
def commandLine = [ "${topsrcdir}/mach" , "environment" , "--format" , "json" , "--verbose" ]
def proc = commandLine . execute (
machEnv ( topsrcdir ) ,
new File ( ext . has ( 'topobjdir' ) ? ext . get ( 'topobjdir' ) : topsrcdir ) )
def standardOutput = new ByteArrayOutputStream ( )
2022-02-02 18:00:46 +00:00
def standardError = new ByteArrayOutputStream ( )
proc . consumeProcessOutput ( standardOutput , standardError )
2021-12-07 17:53:25 +00:00
proc . waitFor ( )
// Only show the output if something went wrong.
if ( proc . exitValue ( ) ! = 0 ) {
2022-02-02 18:00:46 +00:00
throw new GradleException ( "Process '${commandLine}' finished with non-zero exit value ${proc.exitValue()}:\n\n"
+ "stdout:\n${standardOutput.toString()}\n\n"
+ "stderr:\n${standardError.toString()}" )
2021-12-07 17:53:25 +00:00
}
2019-08-15 21:18:24 +00:00
2021-12-07 17:53:25 +00:00
def slurper = new JsonSlurper ( )
def mozconfig = slurper . parseText ( standardOutput . toString ( ) )
2019-08-15 21:18:24 +00:00
2021-12-07 17:53:25 +00:00
if ( topsrcdir ! = mozconfig . topsrcdir ) {
throw new GradleException ( "Specified topsrcdir ('${topsrcdir}') is not mozconfig topsrcdir ('${mozconfig.topsrcdir}')" )
}
2019-08-15 21:18:24 +00:00
2021-12-07 17:53:25 +00:00
def topobjdir
if ( ext . has ( 'topobjdir' ) ) {
topobjdir = ext . topobjdir
} else {
topobjdir = mozconfig . topobjdir
log ( "Found topobjdir ${topobjdir} from topsrcdir ${topsrcdir}" )
}
2019-08-15 21:18:24 +00:00
2021-12-07 17:53:25 +00:00
if ( mozconfig . substs . MOZ_BUILD_APP ! = 'mobile/android' ) {
throw new GradleException ( "Building with Gradle is only supported for GeckoView, i.e., MOZ_BUILD_APP == 'mobile/android'." )
}
log ( "Will substitute GeckoView (geckoview-{nightly,beta}) with local GeckoView (geckoview-default) from ${topobjdir}/gradle/build/mobile/android/geckoview/maven" )
2019-08-15 21:18:24 +00:00
2021-12-07 17:53:25 +00:00
if ( ! mozconfig . substs . COMPILE_ENVIRONMENT ) {
log ( "To update the local GeckoView, run `./mach gradle geckoview:publishWithGeckoBinariesDebugPublicationToMavenRepository` in ${topsrcdir}" )
} else {
log ( "To update the local GeckoView, run `./mach build binaries && ./mach gradle geckoview:publishWithGeckoBinariesDebugPublicationToMavenRepository` in ${topsrcdir}" )
}
return [ mozconfig , topobjdir ]
}
2019-08-15 21:18:24 +00:00
2021-12-07 17:53:25 +00:00
// This script is expected to be called for every subproject in the build (in ac, this is over 100)
// but loadMozconfig should only be called once per build (see the javadoc) so we store the output
// of that call as a global variable and re-use it when this script is called again.
def LOAD_MOZCONFIG_CACHE = "substitute-local-geckoview-mozconfig-cache"
if ( ! rootProject . ext . has ( LOAD_MOZCONFIG_CACHE ) ) {
rootProject . ext . set ( LOAD_MOZCONFIG_CACHE , loadMozconfig ( ) )
2019-08-15 21:18:24 +00:00
}
2021-12-07 17:53:25 +00:00
def ( mozconfig , topobjdir ) = rootProject . ext . get ( LOAD_MOZCONFIG_CACHE )
2019-08-15 21:18:24 +00:00
repositories {
maven {
name "Local GeckoView Maven repository"
2022-01-11 19:16:01 +00:00
url "${topobjdir}/gradle/maven"
2019-08-15 21:18:24 +00:00
}
}
configurations . all { config - >
// Like `geckoview-nightly` for a multi-architecture fat AAR or
// `geckoview-nightly-armeabi-v7a` for an architecture-specific AAR.
def geckoviewModules = [
'geckoview-nightly' ,
'geckoview-nightly-armeabi-v7a' ,
'geckoview-nightly-arm64-v8a' ,
'geckoview-nightly-x86' ,
'geckoview-nightly-x86_64' ,
'geckoview-beta' ,
'geckoview-beta-armeabi-v7a' ,
'geckoview-beta-arm64-v8a' ,
'geckoview-beta-x86' ,
'geckoview-beta-x86_64' ,
]
2021-07-20 22:19:17 +00:00
def geckoviewOmniModules = [
'geckoview-nightly-omni' ,
'geckoview-nightly-omni-armeabi-v7a' ,
'geckoview-nightly-omni-arm64-v8a' ,
'geckoview-nightly-omni-x86' ,
'geckoview-nightly-omni-x86_64' ,
'geckoview-beta-omni' ,
'geckoview-beta-omni-armeabi-v7a' ,
'geckoview-beta-omni-arm64-v8a' ,
'geckoview-beta-omni-x86' ,
'geckoview-beta-omni-x86_64' ,
]
2019-08-15 21:18:24 +00:00
if ( config . isCanBeResolved ( ) ) {
config . resolutionStrategy { strategy - >
dependencySubstitution {
all { dependency - >
// We could restrict based on target architecture, but there doesn't seem to
// be much advantage to doing so right now.
if ( ! ( dependency . requested instanceof ModuleComponentSelector ) ) {
// We can only substitute for a module: we're never going to substitute
// for a project.
return
}
def group = dependency . requested . group
2021-07-20 22:19:17 +00:00
def module = dependency . requested . module
if ( group = = 'org.mozilla.geckoview'
& & ( geckoviewModules . contains ( module ) | | geckoviewOmniModules . contains ( module ) ) ) {
def name = ''
2021-08-10 20:24:33 +00:00
def isLite = mozconfig . substs . MOZ_ANDROID_GECKOVIEW_LITE
if ( isLite ) {
2021-07-20 22:19:17 +00:00
name = 'geckoview-default'
2021-08-10 20:24:33 +00:00
} else {
name = 'geckoview-default-omni'
2021-07-20 22:19:17 +00:00
}
2021-08-10 20:24:33 +00:00
if ( geckoviewModules . contains ( module ) & & ! isLite ) {
warn ( "Substituting a geckoview omni build into a lite dependency. Add ac_add_options --enable-geckoview-lite to ${mozconfig.mozconfig.path} to fix this." )
} else if ( geckoviewOmniModules . contains ( module ) & & isLite ) {
// Substituting lite into omni is unlikely to work at
// all so we just error out here.
throw new GradleException ( "Substituting a geckoview lite build into an omni dependency. Remove ac_add_options --enable-geckoview-lite in ${mozconfig.mozconfig.path} to fix this." )
}
2019-08-15 21:18:24 +00:00
log ( "Substituting ${group}:${dependency.requested.module} with local GeckoView ${group}:${name} in ${config}" )
dependency . useTarget ( [ group: group , name: name , version: '+' ] )
// We substitute with a dynamic version ('+'). It seems that Gradle
// discovers the underlying AAR is out of date correctly based on file
// timestamp already, but let's try to avoid some class of cache
// invalidation error while we're here.
strategy . cacheDynamicVersionsFor 0 , 'seconds'
2019-12-11 21:29:44 +00:00
strategy . cacheChangingModulesFor 0 , 'seconds'
2019-08-15 21:18:24 +00:00
}
}
}
}
}
}