@callstack/react-native-brownfield 3.11.0 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/gradle-plugin/brownfield/build.gradle.kts +134 -0
- package/gradle-plugin/brownfield/config/detekt/detekt.yml +936 -0
- package/gradle-plugin/brownfield/gradle/libs.versions.toml +19 -0
- package/gradle-plugin/brownfield/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle-plugin/brownfield/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/gradle-plugin/brownfield/gradle.properties +14 -0
- package/gradle-plugin/brownfield/gradlew +249 -0
- package/gradle-plugin/brownfield/gradlew.bat +92 -0
- package/gradle-plugin/brownfield/settings.gradle +7 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/artifacts/ArtifactsResolver.kt +132 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/exceptions/NameSpaceNotFound.kt +4 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/exceptions/TaskNotFound.kt +4 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/ExpoPublishingHelper.kt +432 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/utils/BrownfieldPrimitives.kt +31 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/utils/ExpoProjectionPrimitives.kt +22 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/utils/LocalMavenUtils.kt +83 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/utils/ReflectionUtils.kt +79 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/expo/utils/VersionMediatingDependencySet.kt +100 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/CustomDependencyResolver.kt +50 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/ProjectConfigurations.kt +107 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RClassTransformer.kt +131 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNBrownfieldPlugin.kt +171 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt +149 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/AssetTaskProcessor.kt +29 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ExplodeTaskProvider.kt +63 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/JNILibsProcessor.kt +165 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ManifestTaskProcessor.kt +74 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/MergeProcessor.kt +55 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ProguardProcessor.kt +61 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/ResourceTaskProcessor.kt +26 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/VariantHelper.kt +61 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/VariantPackagesProperty.kt +21 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/VariantTaskProvider.kt +103 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/BaseProject.kt +17 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/BundleTaskProvider.kt +46 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/Constants.kt +58 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/ExplodeAarTask.kt +72 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/GradleILogger.kt +59 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/Logging.kt +24 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/shared/ModuleInfo.kt +22 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/AndroidArchiveLibrary.kt +77 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/DirectoryManager.kt +20 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/Extension.kt +44 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/StringExtensions.kt +5 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/StringMatcher.kt +21 -0
- package/gradle-plugin/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/Utils.kt +59 -0
- package/ios/Expo/ExpoHostRuntime.swift +3 -2
- package/ios/ReactNativeBrownfield.swift +1 -1
- package/ios/Vanilla/ReactNativeHostRuntime.swift +5 -2
- package/ios/swiftpm/Sources/BrownfieldBundleSupport/BrownfieldBundleURLResolver.swift +11 -5
- package/ios/swiftpm/Tests/BrownfieldBundleSupportTests/BrownfieldBundleURLResolverTests.swift +17 -5
- package/lib/commonjs/expo-config-plugin/android/utils/constants.js +1 -1
- package/lib/commonjs/expo-config-plugin/android/utils/constants.js.map +1 -1
- package/lib/commonjs/expo-config-plugin/ios/xcodeHelpers.js +2 -1
- package/lib/commonjs/expo-config-plugin/ios/xcodeHelpers.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/expo-config-plugin/android/utils/constants.js +1 -1
- package/lib/module/expo-config-plugin/android/utils/constants.js.map +1 -1
- package/lib/module/expo-config-plugin/ios/xcodeHelpers.js +2 -1
- package/lib/module/expo-config-plugin/ios/xcodeHelpers.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/expo-config-plugin/android/utils/constants.d.ts +2 -2
- package/lib/typescript/commonjs/src/expo-config-plugin/android/utils/constants.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/expo-config-plugin/ios/xcodeHelpers.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +1 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/expo-config-plugin/android/utils/constants.d.ts +2 -2
- package/lib/typescript/module/src/expo-config-plugin/android/utils/constants.d.ts.map +1 -1
- package/lib/typescript/module/src/expo-config-plugin/ios/xcodeHelpers.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +1 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +6 -4
- package/scripts/sync-gradle-plugin-source.js +58 -0
- package/src/expo-config-plugin/android/utils/constants.ts +1 -1
- package/src/expo-config-plugin/ios/xcodeHelpers.ts +14 -0
- package/src/index.ts +2 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.expo
|
|
2
|
+
|
|
3
|
+
import com.android.utils.forEach
|
|
4
|
+
import com.callstack.react.brownfield.expo.utils.DependencyInfo
|
|
5
|
+
import com.callstack.react.brownfield.expo.utils.ExpoGradleProjectProjection
|
|
6
|
+
import com.callstack.react.brownfield.expo.utils.LocalMavenUtils
|
|
7
|
+
import com.callstack.react.brownfield.expo.utils.VersionMediatingDependencySet
|
|
8
|
+
import com.callstack.react.brownfield.expo.utils.asExpoGradleProjectProjection
|
|
9
|
+
import com.callstack.react.brownfield.shared.Constants
|
|
10
|
+
import com.callstack.react.brownfield.shared.Logging
|
|
11
|
+
import groovy.json.JsonOutput
|
|
12
|
+
import groovy.json.JsonSlurper
|
|
13
|
+
import groovy.util.NodeList
|
|
14
|
+
import org.gradle.api.Project
|
|
15
|
+
import org.gradle.api.publish.PublishingExtension
|
|
16
|
+
import org.gradle.api.publish.maven.MavenPublication
|
|
17
|
+
import org.gradle.api.publish.tasks.GenerateModuleMetadata
|
|
18
|
+
import org.w3c.dom.Node
|
|
19
|
+
import java.io.File
|
|
20
|
+
import javax.xml.parsers.DocumentBuilderFactory
|
|
21
|
+
|
|
22
|
+
fun Node.getChildNodeByName(nodeName: String): Node? {
|
|
23
|
+
return childNodes
|
|
24
|
+
.let { childNodes ->
|
|
25
|
+
(0 until childNodes.length)
|
|
26
|
+
.map { index -> childNodes.item(index) }
|
|
27
|
+
.firstOrNull { node -> node.nodeName == nodeName }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
open class ExpoPublishingHelper(val brownfieldAppProject: Project) {
|
|
32
|
+
fun configure(): List<ExpoGradleProjectProjection> {
|
|
33
|
+
val discoverableExpoProjects = getDiscoverableExpoProjects()
|
|
34
|
+
|
|
35
|
+
Logging.log(
|
|
36
|
+
"Discovered ${discoverableExpoProjects.size} discoverable Expo projects: " +
|
|
37
|
+
discoverableExpoProjects.joinToString(
|
|
38
|
+
", ",
|
|
39
|
+
) { it.name },
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
val expoTransitiveDependencies =
|
|
43
|
+
discoverAllExpoTransitiveDependencies(
|
|
44
|
+
expoProjects = discoverableExpoProjects,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
Logging.log(
|
|
48
|
+
"Collected a total of ${expoTransitiveDependencies.size} unique Expo transitive " +
|
|
49
|
+
"dependencies for brownfield app project publishing",
|
|
50
|
+
)
|
|
51
|
+
expoTransitiveDependencies.forEach {
|
|
52
|
+
Logging.log(
|
|
53
|
+
"(*) dependency ${it.groupId}:${it.artifactId}:${it.version} (scope: ${it.scope}, " +
|
|
54
|
+
"${if (it.optional) "optional" else "required"})",
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
reconfigurePOM(expoTransitiveDependencies)
|
|
59
|
+
reconfigureGradleModuleJSON(expoTransitiveDependencies)
|
|
60
|
+
|
|
61
|
+
return discoverableExpoProjects
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected fun shouldExcludeDependency(
|
|
65
|
+
groupId: String,
|
|
66
|
+
artifactId: String,
|
|
67
|
+
): Boolean {
|
|
68
|
+
val isRootProjectArtifact =
|
|
69
|
+
groupId == brownfieldAppProject.rootProject.name
|
|
70
|
+
val isExpoArtifact =
|
|
71
|
+
Constants.BROWNFIELD_EXPO_TRANSITIVE_DEPS_ARTIFACTS_BLACKLIST.any {
|
|
72
|
+
it.matches(
|
|
73
|
+
groupId = groupId,
|
|
74
|
+
artifactId = artifactId,
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return (isRootProjectArtifact || isExpoArtifact)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Modifies the generated Gradle Module Metadata file to inject Expo transitive dependencies.
|
|
83
|
+
* @param discoveredExpoTransitiveDependencies Set of DependencyInfo
|
|
84
|
+
* representing Expo transitive dependencies to add.
|
|
85
|
+
*/
|
|
86
|
+
@Suppress("LongMethod")
|
|
87
|
+
protected fun reconfigureGradleModuleJSON(discoveredExpoTransitiveDependencies: VersionMediatingDependencySet) {
|
|
88
|
+
val removeDependenciesFromModuleFileTask =
|
|
89
|
+
brownfieldAppProject.tasks.register("removeDependenciesFromModuleFile")
|
|
90
|
+
removeDependenciesFromModuleFileTask.configure { task ->
|
|
91
|
+
task.doLast {
|
|
92
|
+
val moduleBuildDir = brownfieldAppProject.layout.buildDirectory.get()
|
|
93
|
+
|
|
94
|
+
File("$moduleBuildDir/publications/mavenAar/module.json").run {
|
|
95
|
+
val json = inputStream().use { JsonSlurper().parse(it) as Map<*, *> }
|
|
96
|
+
|
|
97
|
+
discoveredExpoTransitiveDependencies.forEach { dependencyToAdd ->
|
|
98
|
+
@Suppress("UNCHECKED_CAST")
|
|
99
|
+
(json["variants"] as? List<MutableMap<String, Any>>)?.forEach { variant ->
|
|
100
|
+
Logging.log(
|
|
101
|
+
"Injecting dependency to Gradle module JSON for variant " +
|
|
102
|
+
"'${variant["name"]}': ${dependencyToAdd.groupId}:" +
|
|
103
|
+
"${dependencyToAdd.artifactId}:${dependencyToAdd.version}",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
(variant["dependencies"] as? MutableList<MutableMap<String, Any>>)?.add(
|
|
107
|
+
mutableMapOf<String, Any>(
|
|
108
|
+
"group" to dependencyToAdd.groupId,
|
|
109
|
+
"module" to dependencyToAdd.artifactId,
|
|
110
|
+
).apply {
|
|
111
|
+
dependencyToAdd.version?.let { version ->
|
|
112
|
+
put(
|
|
113
|
+
"version",
|
|
114
|
+
mapOf(
|
|
115
|
+
"requires" to version,
|
|
116
|
+
),
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@Suppress("UNCHECKED_CAST")
|
|
125
|
+
(json["variants"] as? List<MutableMap<String, Any>>)?.forEach { variant ->
|
|
126
|
+
(variant["dependencies"] as? MutableList<Map<String, Any>>)?.removeAll {
|
|
127
|
+
val group = it["group"] as String
|
|
128
|
+
val module = it["module"] as String
|
|
129
|
+
|
|
130
|
+
val shouldBeExcluded =
|
|
131
|
+
shouldExcludeDependency(
|
|
132
|
+
groupId = group,
|
|
133
|
+
artifactId = module,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
if (shouldBeExcluded) {
|
|
137
|
+
Logging.log(
|
|
138
|
+
"Removing excluded dependency from Gradle module JSON: $group:$module",
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
shouldBeExcluded
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
writer().use {
|
|
146
|
+
it.write(
|
|
147
|
+
JsonOutput.prettyPrint(
|
|
148
|
+
JsonOutput.toJson(
|
|
149
|
+
json,
|
|
150
|
+
),
|
|
151
|
+
),
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
brownfieldAppProject.tasks.withType(GenerateModuleMetadata::class.java)
|
|
160
|
+
.configureEach {
|
|
161
|
+
it.finalizedBy(removeDependenciesFromModuleFileTask.get())
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Modifies the generated Maven POM file to inject Expo transitive dependencies.
|
|
167
|
+
* @param discoveredExpoTransitiveDependencies Set of DependencyInfo
|
|
168
|
+
* representing Expo transitive dependencies to add.
|
|
169
|
+
*/
|
|
170
|
+
@Suppress("LongMethod")
|
|
171
|
+
protected fun reconfigurePOM(discoveredExpoTransitiveDependencies: VersionMediatingDependencySet) {
|
|
172
|
+
brownfieldAppProject.pluginManager.withPlugin("maven-publish") {
|
|
173
|
+
brownfieldAppProject.extensions.configure(PublishingExtension::class.java) { publishing ->
|
|
174
|
+
publishing.publications.withType(MavenPublication::class.java)
|
|
175
|
+
.configureEach { pub ->
|
|
176
|
+
Logging.log(
|
|
177
|
+
"Configuring POM for publication '${pub.name}' to include Expo transitive dependencies",
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
pub.pom.withXml {
|
|
181
|
+
val root = it.asNode()
|
|
182
|
+
|
|
183
|
+
// below: obtains a view of the <dependencies> node(s)
|
|
184
|
+
// inside the POM XML; in practice, there should be only one such node
|
|
185
|
+
val dependenciesNodeList =
|
|
186
|
+
root.get("dependencies") as NodeList
|
|
187
|
+
val dependenciesNode =
|
|
188
|
+
dependenciesNodeList.first() as groovy.util.Node
|
|
189
|
+
|
|
190
|
+
// below: inject the discovered Expo transitive dependencies
|
|
191
|
+
// into the POM's <dependencies> node
|
|
192
|
+
discoveredExpoTransitiveDependencies.forEach { dependencyToAdd ->
|
|
193
|
+
Logging.log(
|
|
194
|
+
"Injecting dependency to POM: ${dependencyToAdd.groupId}:" +
|
|
195
|
+
"${dependencyToAdd.artifactId}:${dependencyToAdd.version}",
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
val childTags =
|
|
199
|
+
mutableMapOf(
|
|
200
|
+
"groupId" to dependencyToAdd.groupId,
|
|
201
|
+
"artifactId" to dependencyToAdd.artifactId,
|
|
202
|
+
"scope" to dependencyToAdd.scope,
|
|
203
|
+
"optional" to dependencyToAdd.optional.toString(),
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
if (dependencyToAdd.version?.isNotBlank() == true) {
|
|
207
|
+
childTags["version"] = dependencyToAdd.version
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
dependenciesNode.appendNode("dependency").let { newDepNode ->
|
|
211
|
+
childTags.forEach { (tagName, tagValue) ->
|
|
212
|
+
newDepNode.appendNode(tagName, tagValue)
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// below: filter out dependencies that should be excluded
|
|
218
|
+
dependenciesNode.children()
|
|
219
|
+
.filterIsInstance<groovy.util.Node>()
|
|
220
|
+
.filter { dependency ->
|
|
221
|
+
val groupId =
|
|
222
|
+
(dependency["groupId"] as NodeList).text()
|
|
223
|
+
val artifactId =
|
|
224
|
+
(dependency["artifactId"] as NodeList).text()
|
|
225
|
+
|
|
226
|
+
val shouldBeExcluded =
|
|
227
|
+
shouldExcludeDependency(
|
|
228
|
+
groupId = groupId,
|
|
229
|
+
artifactId = artifactId,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
if (shouldBeExcluded) {
|
|
233
|
+
Logging.log(
|
|
234
|
+
"Removing excluded dependency from POM: $groupId:$artifactId",
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
shouldBeExcluded
|
|
239
|
+
}
|
|
240
|
+
.forEach { dependency ->
|
|
241
|
+
dependenciesNode.remove(dependency)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
fun discoverAllExpoTransitiveDependencies(expoProjects: Iterable<ExpoGradleProjectProjection>): VersionMediatingDependencySet {
|
|
250
|
+
var discoveredExpoTransitiveDependencies = VersionMediatingDependencySet()
|
|
251
|
+
expoProjects.forEach { expoProj ->
|
|
252
|
+
val maybeTransitiveDepsForProj =
|
|
253
|
+
discoverExpoTransitiveDependenciesForPublication(
|
|
254
|
+
expoGPProjection = expoProj,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
if (maybeTransitiveDepsForProj != null) {
|
|
258
|
+
discoveredExpoTransitiveDependencies.addAll(
|
|
259
|
+
maybeTransitiveDepsForProj,
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
discoveredExpoTransitiveDependencies =
|
|
265
|
+
discoveredExpoTransitiveDependencies.filter {
|
|
266
|
+
shouldExcludeDependency(
|
|
267
|
+
groupId = it.groupId,
|
|
268
|
+
artifactId = it.artifactId,
|
|
269
|
+
).not()
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return discoveredExpoTransitiveDependencies
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
fun discoverExpoTransitiveDependenciesForPublication(expoGPProjection: ExpoGradleProjectProjection): VersionMediatingDependencySet? {
|
|
276
|
+
val publication =
|
|
277
|
+
LocalMavenUtils.getPublishingInfo(expoGPProjection, brownfieldAppProject)
|
|
278
|
+
?: error(LocalMavenUtils.publishingNotFound(expoGPProjection.name))
|
|
279
|
+
|
|
280
|
+
val pkgProjectDir = File(expoGPProjection.sourceDir)
|
|
281
|
+
val pkgProject =
|
|
282
|
+
brownfieldAppProject.rootProject.allprojects.find {
|
|
283
|
+
it.projectDir.canonicalFile == pkgProjectDir.canonicalFile
|
|
284
|
+
}
|
|
285
|
+
val expoPkgLocalMavenRepo = pkgProjectDir.parentFile.resolve("local-maven-repo")
|
|
286
|
+
val pomFile = LocalMavenUtils.getPomFile(expoPkgLocalMavenRepo, publication)
|
|
287
|
+
|
|
288
|
+
val dependencies = VersionMediatingDependencySet()
|
|
289
|
+
var depsDiscoverySource: String
|
|
290
|
+
|
|
291
|
+
if (pomFile.exists()) {
|
|
292
|
+
// firstly, try reading transitive dependencies from the POM file
|
|
293
|
+
val xml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(pomFile)
|
|
294
|
+
|
|
295
|
+
depsDiscoverySource = "POM file"
|
|
296
|
+
|
|
297
|
+
appendExpoTransitiveDependenciesFromMavenPOM(
|
|
298
|
+
xml.getElementsByTagName("dependencies"),
|
|
299
|
+
dependencies,
|
|
300
|
+
)
|
|
301
|
+
} else if (pkgProject != null) {
|
|
302
|
+
// as fallback, iterate Gradle's resolved dependencies for the Expo project
|
|
303
|
+
depsDiscoverySource = "Gradle resolved dependencies"
|
|
304
|
+
|
|
305
|
+
appendExpoTransitiveDependenciesFromGradle(pkgProject, dependencies)
|
|
306
|
+
} else {
|
|
307
|
+
// if no POM & no Gradle project have been resolved, there is no source for the data
|
|
308
|
+
|
|
309
|
+
Logging.log(
|
|
310
|
+
"WARNING: Could not discover transitive dependencies for Expo project '${expoGPProjection.name}' " +
|
|
311
|
+
"- no POM file found at expected location $pomFile and no Gradle project could be " +
|
|
312
|
+
"resolved for Expo project located at ${expoGPProjection.sourceDir}",
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
return null
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// below: the plugin already packs Expo packages inside the brownfield AAR, so only transitive
|
|
319
|
+
// deps are needed in the POM; Expo packages themselves should not be declared as dependencies
|
|
320
|
+
dependencies.removeAll { dep ->
|
|
321
|
+
shouldExcludeDependency(
|
|
322
|
+
groupId = dep.groupId,
|
|
323
|
+
artifactId = dep.artifactId,
|
|
324
|
+
)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
Logging.log(
|
|
328
|
+
"Discovered ${dependencies.size} transitive dependencies for Expo project " +
|
|
329
|
+
"'${expoGPProjection.name}' from $depsDiscoverySource",
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
return dependencies
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
protected fun appendExpoTransitiveDependenciesFromMavenPOM(
|
|
336
|
+
dependenciesNodes: org.w3c.dom.NodeList,
|
|
337
|
+
dependencies: VersionMediatingDependencySet,
|
|
338
|
+
) {
|
|
339
|
+
dependenciesNodes.forEach { depNodeList ->
|
|
340
|
+
depNodeList.childNodes.forEach { depNode ->
|
|
341
|
+
/**
|
|
342
|
+
* below: some nodes are not dependencies, but pure text, in which case their name is '#text'
|
|
343
|
+
*/
|
|
344
|
+
if (depNode.nodeName == "dependency") {
|
|
345
|
+
val groupId = depNode.getChildNodeByName("groupId")!!.textContent
|
|
346
|
+
val maybeArtifactId = depNode.getChildNodeByName("artifactId")
|
|
347
|
+
|
|
348
|
+
val artifactId = maybeArtifactId!!.textContent
|
|
349
|
+
val version = depNode.getChildNodeByName("version")?.textContent
|
|
350
|
+
val optional = depNode.getChildNodeByName("optional")?.textContent
|
|
351
|
+
val scope = depNode.getChildNodeByName("scope")?.textContent
|
|
352
|
+
val dependencyInfo =
|
|
353
|
+
DependencyInfo(
|
|
354
|
+
groupId = groupId,
|
|
355
|
+
artifactId = artifactId,
|
|
356
|
+
version = version,
|
|
357
|
+
scope = scope ?: "compile",
|
|
358
|
+
optional = optional?.toBoolean() ?: false,
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
dependencies.add(dependencyInfo)
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
protected fun appendExpoTransitiveDependenciesFromGradle(
|
|
368
|
+
pkgProject: Project,
|
|
369
|
+
dependencies: VersionMediatingDependencySet,
|
|
370
|
+
) {
|
|
371
|
+
/**
|
|
372
|
+
* Not accounting for variant specific configurations as Expo packages are not
|
|
373
|
+
* using it. Should we face any issues/needs to account for it, we can do it here.
|
|
374
|
+
*/
|
|
375
|
+
listOf("implementation", "api", "runtime").forEach {
|
|
376
|
+
val configuration = pkgProject.configurations.findByName(it)
|
|
377
|
+
configuration?.dependencies?.forEach { dep ->
|
|
378
|
+
if (dep.group != null) {
|
|
379
|
+
dependencies.add(
|
|
380
|
+
DependencyInfo.fromGradleDep(
|
|
381
|
+
groupId = dep.group!!,
|
|
382
|
+
artifactId = dep.name,
|
|
383
|
+
version = dep.version,
|
|
384
|
+
),
|
|
385
|
+
)
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Discovers Expo projects in the current brownfield app project that are marked for publication.
|
|
393
|
+
* @return List of ExpoGradleProjectProjection representing the discoverable Expo projects.
|
|
394
|
+
*/
|
|
395
|
+
fun getDiscoverableExpoProjects(): List<ExpoGradleProjectProjection> {
|
|
396
|
+
val expoExtension =
|
|
397
|
+
brownfieldAppProject.rootProject.gradle.extensions.findByType(Class.forName("expo.modules.plugin.ExpoGradleExtension"))
|
|
398
|
+
?: error("Expo Gradle extension not found. This should never happen in an Expo project.")
|
|
399
|
+
|
|
400
|
+
// expoExtension.config
|
|
401
|
+
val config =
|
|
402
|
+
expoExtension.javaClass
|
|
403
|
+
.getMethod("getConfig")
|
|
404
|
+
.invoke(expoExtension)
|
|
405
|
+
|
|
406
|
+
// ...config.allProjects - each project is actually a data class expo.modules.plugin.configuration.GradleProject
|
|
407
|
+
val allProjects =
|
|
408
|
+
config.javaClass
|
|
409
|
+
.getMethod("getAllProjects")
|
|
410
|
+
.invoke(config) as? Iterable<*>
|
|
411
|
+
|
|
412
|
+
// ...filter { it.usePublication }
|
|
413
|
+
@Suppress("UNCHECKED_CAST")
|
|
414
|
+
return allProjects!!
|
|
415
|
+
.filterNotNull()
|
|
416
|
+
// expoInternalProject is a data class - expo.modules.plugin.configuration.GradleProject
|
|
417
|
+
// since Expo itself is not provided via Maven but added via local node_modules
|
|
418
|
+
// and this plugin supports RN Vanilla projects, it is not possible to have
|
|
419
|
+
// a dependency on Expo's APIs; therefore, access happens via reflection,
|
|
420
|
+
// which in turn is hidden behind the ReflectionUtils.wrapObjectProxy abstraction
|
|
421
|
+
// here provided by the asExpoGradleProjectProjection() extension fun; effectively,
|
|
422
|
+
// this means access is provided via a proxy exposing conformant partial interfaces,
|
|
423
|
+
// to which the original entities are projected
|
|
424
|
+
.map { expoGradleProject -> expoGradleProject.asExpoGradleProjectProjection() }
|
|
425
|
+
.filter { expoGradleProjectProjection ->
|
|
426
|
+
return@filter expoGradleProjectProjection.usePublication ||
|
|
427
|
+
Constants.BROWNFIELD_EXPO_TRANSITIVE_DEPS_WHITELISTED_MODULES_FOR_DISCOVERY.contains(
|
|
428
|
+
expoGradleProjectProjection.name,
|
|
429
|
+
)
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.expo.utils
|
|
2
|
+
|
|
3
|
+
data class BrownfieldPublishingInfo(
|
|
4
|
+
val groupId: String,
|
|
5
|
+
val artifactId: String,
|
|
6
|
+
val version: String,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
data class DependencyInfo(
|
|
10
|
+
val groupId: String,
|
|
11
|
+
val artifactId: String,
|
|
12
|
+
val version: String?,
|
|
13
|
+
val scope: String,
|
|
14
|
+
val optional: Boolean,
|
|
15
|
+
) {
|
|
16
|
+
companion object {
|
|
17
|
+
fun fromGradleDep(
|
|
18
|
+
groupId: String,
|
|
19
|
+
artifactId: String,
|
|
20
|
+
version: String?,
|
|
21
|
+
): DependencyInfo {
|
|
22
|
+
return DependencyInfo(
|
|
23
|
+
groupId = groupId,
|
|
24
|
+
artifactId = artifactId,
|
|
25
|
+
version = version,
|
|
26
|
+
scope = "compile",
|
|
27
|
+
optional = false,
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.expo.utils
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Partial projection interface for data class expo.modules.plugin.configuration.GradleProject
|
|
5
|
+
* resolved via reflection.
|
|
6
|
+
*/
|
|
7
|
+
interface ExpoGradleProjectProjection {
|
|
8
|
+
val name: String
|
|
9
|
+
val publication: ExpoPublication?
|
|
10
|
+
val usePublication: Boolean
|
|
11
|
+
val sourceDir: String
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Partial projection interface for data class expo.modules.plugin.configuration.Publication
|
|
16
|
+
* resolved via reflection.
|
|
17
|
+
*/
|
|
18
|
+
interface ExpoPublication {
|
|
19
|
+
val groupId: String
|
|
20
|
+
val artifactId: String
|
|
21
|
+
val version: String
|
|
22
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.expo.utils
|
|
2
|
+
|
|
3
|
+
import com.android.build.gradle.LibraryExtension
|
|
4
|
+
import org.gradle.api.Project
|
|
5
|
+
import java.io.File
|
|
6
|
+
|
|
7
|
+
object LocalMavenUtils {
|
|
8
|
+
fun getAarFile(
|
|
9
|
+
localMavenDir: File,
|
|
10
|
+
publication: BrownfieldPublishingInfo,
|
|
11
|
+
): File {
|
|
12
|
+
return getFile(localMavenDir, publication, "aar")
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fun getPomFile(
|
|
16
|
+
localMavenDir: File,
|
|
17
|
+
publication: BrownfieldPublishingInfo,
|
|
18
|
+
): File {
|
|
19
|
+
return getFile(localMavenDir, publication, "pom")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private fun getFile(
|
|
23
|
+
localMavenDir: File,
|
|
24
|
+
publication: BrownfieldPublishingInfo,
|
|
25
|
+
extension: String,
|
|
26
|
+
): File {
|
|
27
|
+
return localMavenDir
|
|
28
|
+
.resolve(
|
|
29
|
+
"${
|
|
30
|
+
publication.groupId.replace(
|
|
31
|
+
'.',
|
|
32
|
+
'/',
|
|
33
|
+
)
|
|
34
|
+
}/${publication.artifactId}/${publication.version}/" +
|
|
35
|
+
"${publication.artifactId}-${publication.version}.$extension",
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fun getPublishingInfo(
|
|
40
|
+
expoGPProjection: ExpoGradleProjectProjection,
|
|
41
|
+
brownfieldAppProject: Project,
|
|
42
|
+
): BrownfieldPublishingInfo? {
|
|
43
|
+
return expoGPProjection.publication?.let {
|
|
44
|
+
BrownfieldPublishingInfo(
|
|
45
|
+
groupId = it.groupId,
|
|
46
|
+
artifactId = it.artifactId,
|
|
47
|
+
version = it.version,
|
|
48
|
+
)
|
|
49
|
+
} ?: run {
|
|
50
|
+
val targetProject =
|
|
51
|
+
brownfieldAppProject.rootProject.allprojects.firstOrNull {
|
|
52
|
+
it.projectDir.absoluteFile.path == expoGPProjection.sourceDir
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (targetProject == null) {
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
val targetProjectAndroidLibExt =
|
|
60
|
+
targetProject.extensions.getByType(LibraryExtension::class.java)
|
|
61
|
+
|
|
62
|
+
val packagePieces = targetProjectAndroidLibExt.namespace!!.split(".")
|
|
63
|
+
val artifactId = packagePieces.last()
|
|
64
|
+
// below: remove the trailing artifactId component -> leaves only the groupId components
|
|
65
|
+
val groupId = packagePieces.dropLast(1).joinToString(".")
|
|
66
|
+
|
|
67
|
+
(
|
|
68
|
+
BrownfieldPublishingInfo(
|
|
69
|
+
groupId = groupId,
|
|
70
|
+
artifactId = artifactId,
|
|
71
|
+
version = (
|
|
72
|
+
targetProjectAndroidLibExt.defaultConfig.versionName
|
|
73
|
+
?: targetProject.version.toString()
|
|
74
|
+
),
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
fun publishingNotFound(projectName: String): String {
|
|
81
|
+
return "Cannot configure publishing for Expo project $projectName - could not determine publishing info"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
package com.callstack.react.brownfield.expo.utils
|
|
2
|
+
|
|
3
|
+
import com.callstack.react.brownfield.shared.Logging
|
|
4
|
+
import com.callstack.react.brownfield.utils.capitalized
|
|
5
|
+
import java.lang.reflect.Method
|
|
6
|
+
import java.lang.reflect.Proxy
|
|
7
|
+
|
|
8
|
+
object ReflectionUtils {
|
|
9
|
+
fun invokeMethod(
|
|
10
|
+
obj: Any?,
|
|
11
|
+
method: Method,
|
|
12
|
+
): Any? {
|
|
13
|
+
try {
|
|
14
|
+
return obj?.javaClass
|
|
15
|
+
?.getMethod(method.name)
|
|
16
|
+
?.invoke(obj)
|
|
17
|
+
} catch (_: NoSuchMethodException) {
|
|
18
|
+
try {
|
|
19
|
+
return obj?.javaClass
|
|
20
|
+
?.getMethod("get${method.name.capitalized()}")
|
|
21
|
+
?.invoke(obj)
|
|
22
|
+
} catch (e: NoSuchMethodException) {
|
|
23
|
+
Logging.error(
|
|
24
|
+
"Method ${method.name} nor a getter for this name have not been found on ExpoGradleProjectProjection",
|
|
25
|
+
e,
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
fun <T : Any> wrapObjectProxy(
|
|
34
|
+
target: Any,
|
|
35
|
+
projection: Class<T>,
|
|
36
|
+
nested: List<Class<*>> = emptyList(),
|
|
37
|
+
): T {
|
|
38
|
+
@Suppress("UNCHECKED_CAST")
|
|
39
|
+
return Proxy.newProxyInstance(
|
|
40
|
+
projection.classLoader,
|
|
41
|
+
arrayOf(projection),
|
|
42
|
+
) { _, method, _ ->
|
|
43
|
+
val value = invokeMethod(target, method)
|
|
44
|
+
|
|
45
|
+
// wrap defined nested objects
|
|
46
|
+
if (value != null) {
|
|
47
|
+
if (nested.contains(method.returnType)) {
|
|
48
|
+
val nestedProjection = method.returnType
|
|
49
|
+
|
|
50
|
+
return@newProxyInstance when {
|
|
51
|
+
value is Iterable<*> -> {
|
|
52
|
+
value.map { wrapObjectProxy(it!!, nestedProjection) }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
else -> {
|
|
56
|
+
wrapObjectProxy(
|
|
57
|
+
value,
|
|
58
|
+
nestedProjection,
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
value
|
|
66
|
+
} as T
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fun Any.asExpoGradleProjectProjection(): ExpoGradleProjectProjection {
|
|
71
|
+
return ReflectionUtils.wrapObjectProxy(
|
|
72
|
+
this,
|
|
73
|
+
ExpoGradleProjectProjection::class.java,
|
|
74
|
+
nested =
|
|
75
|
+
listOf(
|
|
76
|
+
ExpoPublication::class.java,
|
|
77
|
+
),
|
|
78
|
+
)
|
|
79
|
+
}
|