Backed out changeset 2d88daa2e4bc (bug 1899848) for conflicting with the backout...
[gecko.git] / substitute-local-geckoview.gradle
bloba32dc5ae8a05f2006460c85dbb2af8e92848a97f
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 // Substitute a local GeckoView AAR into a consuming Gradle project.
6 //
7 // To use this, in a consuming Gradle project's `/build.gradle` add a stanza like:
8 //
9 // ext.topsrcdir = '/absolute/path/to/mozilla-central'; apply from: "${ext.topsrcdir}/substitute-local-geckoview.gradle"
11 // The object directory will be determined using `mach environment` and will agree with `./mach
12 // gradle` and Android Studio.  Or, specify the exact object directory with a stanza like:
14 // ext.topsrcdir = '/absolute/path/to/mozilla-central'
15 // ext.topobjdir = '/absolute/path/to/objdir'
16 // apply from: "${ext.topsrcdir}/substitute-local-geckoview.gradle"
18 // Substitution works with artifact and non-artifact builds.
20 // If you get errors about .jar files not being found, ensure that the consuming
21 // application is using a recent Android-Gradle plugin (say, 3.4+).  There were
22 // issues with Jetifier, and issues with .jar vs. .aar extensions, in older
23 // versions.
25 import groovy.json.JsonSlurper
27 def log(message) {
28     logger.lifecycle("[substitute-local-geckoview] ${message}")
31 def warn(message) {
32     logger.warn("[substitute-local-geckoview] Warning: ${message}")
35 if (!project.ext.has('topsrcdir')) {
36     throw new GradleException("ext.topsrcdir must be specified to substitute for a local GeckoView")
39 /**
40  * Loads the mozconfig and returns any variables derived from it, avoiding side effects.
41  *
42  * This method is relatively slow because it calls mach, which starts a python interpreter, will
43  * becomes very slow if called for numerous subprojects. Therefore, it should only be called once
44  * per build.
45  */
46 def loadMozconfig() {
47     apply from: "${topsrcdir}/mobile/android/gradle/mach_env.gradle"
49     // Cribbed from https://hg.mozilla.org/mozilla-central/file/tip/settings.gradle.  When run in
50     // topobjdir, `mach environment` correctly finds the mozconfig corresponding to that object
51     // directory.
52     def commandLine = ["${topsrcdir}/mach", "environment", "--format", "json", "--verbose"]
53     def proc = commandLine.execute(
54             machEnv(topsrcdir),
55             new File(ext.has('topobjdir') ? ext.get('topobjdir') : topsrcdir))
56     def standardOutput = new ByteArrayOutputStream()
57     def standardError = new ByteArrayOutputStream()
58     proc.consumeProcessOutput(standardOutput, standardError)
59     proc.waitFor()
61     // Only show the output if something went wrong.
62     if (proc.exitValue() != 0) {
63         throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${proc.exitValue()}:\n\n"
64                 + "stdout:\n${standardOutput.toString()}\n\n"
65                 + "stderr:\n${standardError.toString()}")
66     }
68     def slurper = new JsonSlurper()
69     def mozconfig = slurper.parseText(standardOutput.toString())
71     if (topsrcdir != mozconfig.topsrcdir) {
72         throw new GradleException("Specified topsrcdir ('${topsrcdir}') is not mozconfig topsrcdir ('${mozconfig.topsrcdir}')")
73     }
75     def topobjdir
76     if (ext.has('topobjdir')) {
77         topobjdir = ext.topobjdir
78     } else {
79         topobjdir = mozconfig.topobjdir
80         log("Found topobjdir ${topobjdir} from topsrcdir ${topsrcdir}")
81     }
83     if (mozconfig.substs.MOZ_BUILD_APP != 'mobile/android') {
84         throw new GradleException("Building with Gradle is only supported for GeckoView, i.e., MOZ_BUILD_APP == 'mobile/android'.")
85     }
87     log("Will substitute GeckoView (geckoview-{nightly,beta}) with local GeckoView (geckoview-default) from ${topobjdir}/gradle/build/mobile/android/geckoview/maven")
89     if (!mozconfig.substs.COMPILE_ENVIRONMENT) {
90         log("To update the local GeckoView, run `./mach gradle geckoview:publishWithGeckoBinariesDebugPublicationToMavenRepository` in ${topsrcdir}")
91     } else {
92         log("To update the local GeckoView, run `./mach build binaries && ./mach gradle geckoview:publishWithGeckoBinariesDebugPublicationToMavenRepository` in ${topsrcdir}")
93     }
95     return [mozconfig, topobjdir]
98 // This script is expected to be called for every subproject in the build (in ac, this is over 100)
99 // but loadMozconfig should only be called once per build (see the javadoc) so we store the output
100 // of that call as a global variable and re-use it when this script is called again.
101 def LOAD_MOZCONFIG_CACHE = "substitute-local-geckoview-mozconfig-cache"
102 if (!rootProject.ext.has(LOAD_MOZCONFIG_CACHE)) {
103     rootProject.ext.set(LOAD_MOZCONFIG_CACHE, loadMozconfig())
105 def (mozconfig, topobjdir) = rootProject.ext.get(LOAD_MOZCONFIG_CACHE)
107 repositories {
108     maven {
109         name "Local GeckoView Maven repository"
110         url "${topobjdir}/gradle/maven"
111     }
114 configurations.all { config ->
115     // Like `geckoview-nightly` for a multi-architecture fat AAR or
116     // `geckoview-nightly-armeabi-v7a` for an architecture-specific AAR.
117     def geckoviewModules = [
118         'geckoview-nightly',
119         'geckoview-nightly-armeabi-v7a',
120         'geckoview-nightly-arm64-v8a',
121         'geckoview-nightly-x86',
122         'geckoview-nightly-x86_64',
123         'geckoview-beta',
124         'geckoview-beta-armeabi-v7a',
125         'geckoview-beta-arm64-v8a',
126         'geckoview-beta-x86',
127         'geckoview-beta-x86_64',
128     ]
130     def geckoviewOmniModules = [
131         'geckoview-nightly-omni',
132         'geckoview-nightly-omni-armeabi-v7a',
133         'geckoview-nightly-omni-arm64-v8a',
134         'geckoview-nightly-omni-x86',
135         'geckoview-nightly-omni-x86_64',
136         'geckoview-beta-omni',
137         'geckoview-beta-omni-armeabi-v7a',
138         'geckoview-beta-omni-arm64-v8a',
139         'geckoview-beta-omni-x86',
140         'geckoview-beta-omni-x86_64',
141     ]
143     if (config.isCanBeResolved()) {
144         config.resolutionStrategy { strategy ->
145             dependencySubstitution {
146                 all { dependency ->
147                     // We could restrict based on target architecture, but there doesn't seem to
148                     // be much advantage to doing so right now.
150                     if (!(dependency.requested instanceof ModuleComponentSelector)) {
151                         // We can only substitute for a module: we're never going to substitute
152                         // for a project.
153                         return
154                     }
156                     def group = dependency.requested.group
157                     def module = dependency.requested.module
158                     if (group == 'org.mozilla.geckoview'
159                           && (geckoviewModules.contains(module) || geckoviewOmniModules.contains(module))) {
160                         def name = ''
161                         def isLite = mozconfig.substs.MOZ_ANDROID_GECKOVIEW_LITE
163                         if (isLite) {
164                           name = 'geckoview-default'
165                         } else {
166                           name = 'geckoview-default-omni'
167                         }
169                         if (geckoviewModules.contains(module) && !isLite) {
170                           warn("Substituting a geckoview omni build into a lite dependency. Add ac_add_options --enable-geckoview-lite to ${mozconfig.mozconfig.path} to fix this.")
171                         } else if (geckoviewOmniModules.contains(module) && isLite) {
172                           // Substituting lite into omni is unlikely to work at
173                           // all so we just error out here.
174                           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.")
175                         }
177                         log("Substituting ${group}:${dependency.requested.module} with local GeckoView ${group}:${name} in ${config}")
179                         dependency.useTarget([group: group, name: name, version: '+'])
181                         // We substitute with a dynamic version ('+').  It seems that Gradle
182                         // discovers the underlying AAR is out of date correctly based on file
183                         // timestamp already, but let's try to avoid some class of cache
184                         // invalidation error while we're here.
185                         strategy.cacheDynamicVersionsFor 0, 'seconds'
186                         strategy.cacheChangingModulesFor 0, 'seconds'
187                     }
188                 }
189             }
190         }
191     }