Skip to content

Commit 1899f34

Browse files
committed
Extract task registration and other simplification
1 parent 3dc7df3 commit 1899f34

3 files changed

Lines changed: 211 additions & 144 deletions

File tree

packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt

Lines changed: 125 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -175,75 +175,38 @@ class ReactPlugin : Plugin<Project> {
175175
localExtension.jsRootDir.convention(localExtension.root)
176176
}
177177

178-
// We create the task to produce schema from JS files.
179-
val generateCodegenSchemaTask =
180-
project.tasks.register(
181-
"generateCodegenSchemaFromJavaScript",
182-
GenerateCodegenSchemaTask::class.java,
183-
) { it ->
184-
it.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
185-
it.codegenDir.set(rootExtension.codegenDir)
186-
it.generatedSrcDir.set(generatedSrcDir)
187-
it.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
188-
189-
// We're reading the package.json at configuration time to properly feed
190-
// the `jsRootDir` @Input property of this task & the onlyIf. Therefore, the
191-
// parsePackageJson should be invoked inside this lambda.
192-
val packageJson = findPackageJsonFile(project, rootExtension.root)
193-
val parsedPackageJson = packageJson?.let { JsonUtils.fromPackageJson(it) }
194-
195-
val jsSrcsDirInPackageJson = parsedPackageJson?.codegenConfig?.jsSrcsDir
196-
val includesGeneratedCode =
197-
parsedPackageJson?.codegenConfig?.includesGeneratedCode ?: false
198-
if (jsSrcsDirInPackageJson != null) {
199-
it.jsRootDir.set(File(packageJson.parentFile, jsSrcsDirInPackageJson))
200-
} else {
201-
it.jsRootDir.set(localExtension.jsRootDir)
202-
}
203-
it.jsInputFiles.set(
204-
project.fileTree(it.jsRootDir) { tree ->
205-
tree.include("**/*.js")
206-
tree.include("**/*.jsx")
207-
tree.include("**/*.ts")
208-
tree.include("**/*.tsx")
178+
// We're reading the package.json at configuration time to properly feed
179+
// the `jsRootDir` @Input property of the schema task & the onlyIf for both codegen tasks.
180+
val packageJson = findPackageJsonFile(project, rootExtension.root)
181+
val parsedPackageJson = packageJson?.let { JsonUtils.fromPackageJson(it) }
209182

210-
tree.exclude("node_modules/**/*")
211-
tree.exclude("**/*.d.ts")
212-
// We want to exclude the build directory, to don't pick them up for execution
213-
// avoidance.
214-
tree.exclude("**/build/**/*")
215-
}
216-
)
217-
218-
val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root)
219-
it.onlyIf { (isLibrary || needsCodegenFromPackageJson) && !includesGeneratedCode }
220-
}
183+
val jsSrcsDirInPackageJson = parsedPackageJson?.codegenConfig?.jsSrcsDir
184+
val includesGeneratedCode = parsedPackageJson?.codegenConfig?.includesGeneratedCode ?: false
185+
val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root)
186+
val shouldRunCodegen = { (isLibrary || needsCodegenFromPackageJson) && !includesGeneratedCode }
221187

222-
// We create the task to generate Java code from schema.
188+
// We create the tasks to produce schema from JS files and generate artifacts from schema.
223189
val generateCodegenArtifactsTask =
224-
project.tasks.register(
225-
"generateCodegenArtifactsFromSchema",
226-
GenerateCodegenArtifactsTask::class.java,
227-
) { task ->
228-
task.dependsOn(generateCodegenSchemaTask)
229-
task.reactNativeDir.set(rootExtension.reactNativeDir)
230-
task.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
231-
task.generatedSrcDir.set(generatedSrcDir)
232-
task.packageJsonFile.set(findPackageJsonFile(project, rootExtension.root))
233-
task.codegenJavaPackageName.set(localExtension.codegenJavaPackageName)
234-
task.libraryName.set(localExtension.libraryName)
235-
task.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
236-
237-
// Please note that appNeedsCodegen is triggering a read of the package.json at
238-
// configuration time as we need to feed the onlyIf condition of this task.
239-
// Therefore, the appNeedsCodegen needs to be invoked inside this lambda.
240-
val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root)
241-
val packageJson = findPackageJsonFile(project, rootExtension.root)
242-
val parsedPackageJson = packageJson?.let { JsonUtils.fromPackageJson(it) }
243-
val includesGeneratedCode =
244-
parsedPackageJson?.codegenConfig?.includesGeneratedCode ?: false
245-
task.onlyIf { (isLibrary || needsCodegenFromPackageJson) && !includesGeneratedCode }
246-
}
190+
registerCodegenTasks(
191+
project = project,
192+
rootExtension = rootExtension,
193+
generatedSrcDir = generatedSrcDir,
194+
packageJsonFile = packageJson,
195+
schemaTaskName = "generateCodegenSchemaFromJavaScript",
196+
artifactsTaskName = "generateCodegenArtifactsFromSchema",
197+
configureJsRoot = { task ->
198+
if (jsSrcsDirInPackageJson != null) {
199+
task.jsRootDir.set(File(packageJson.parentFile, jsSrcsDirInPackageJson))
200+
} else {
201+
task.jsRootDir.set(localExtension.jsRootDir)
202+
}
203+
},
204+
configureCodegenArtifacts = { task ->
205+
task.codegenJavaPackageName.set(localExtension.codegenJavaPackageName)
206+
task.libraryName.set(localExtension.libraryName)
207+
},
208+
onlyIf = shouldRunCodegen,
209+
)
247210

248211
// We update the android configuration to include the generated sources.
249212
// This equivalent to this DSL:
@@ -266,6 +229,68 @@ class ReactPlugin : Plugin<Project> {
266229
project.tasks.named("preBuild", Task::class.java).dependsOn(generateCodegenArtifactsTask)
267230
}
268231

232+
private fun registerCodegenTasks(
233+
project: Project,
234+
rootExtension: PrivateReactExtension,
235+
generatedSrcDir: Provider<Directory>,
236+
packageJsonFile: File?,
237+
schemaTaskName: String,
238+
artifactsTaskName: String,
239+
configureJsRoot: (GenerateCodegenSchemaTask) -> Unit,
240+
configureCodegenArtifacts: (GenerateCodegenArtifactsTask) -> Unit,
241+
onlyIf: () -> Boolean = { true },
242+
): TaskProvider<GenerateCodegenArtifactsTask> {
243+
// We create the task to produce schema from JS files.
244+
val generateCodegenSchemaTask =
245+
project.tasks.register(
246+
schemaTaskName,
247+
GenerateCodegenSchemaTask::class.java,
248+
) { task ->
249+
task.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
250+
task.codegenDir.set(rootExtension.codegenDir)
251+
task.generatedSrcDir.set(generatedSrcDir)
252+
task.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
253+
254+
configureJsRoot(task)
255+
256+
task.jsInputFiles.set(
257+
project.fileTree(task.jsRootDir) { tree ->
258+
tree.include("**/*.js")
259+
tree.include("**/*.jsx")
260+
tree.include("**/*.ts")
261+
tree.include("**/*.tsx")
262+
263+
tree.exclude("node_modules/**/*")
264+
tree.exclude("**/*.d.ts")
265+
// We want to exclude the build directory, to don't pick them up for execution
266+
// avoidance.
267+
tree.exclude("**/build/**/*")
268+
}
269+
)
270+
task.onlyIf { onlyIf() }
271+
}
272+
273+
// We create the task to generate Java code from schema.
274+
return project.tasks.register(
275+
artifactsTaskName,
276+
GenerateCodegenArtifactsTask::class.java,
277+
) { task ->
278+
task.dependsOn(generateCodegenSchemaTask)
279+
task.reactNativeDir.set(rootExtension.reactNativeDir)
280+
task.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
281+
task.generatedSrcDir.set(generatedSrcDir)
282+
task.packageJsonFile.set(packageJsonFile)
283+
task.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
284+
285+
configureCodegenArtifacts(task)
286+
287+
// The caller decides whether codegen should run. For app/library projects this depends on
288+
// package.json and includesGeneratedCode. Pure C++ dependencies are filtered before task
289+
// registration, so their generated tasks can always run.
290+
task.onlyIf { onlyIf() }
291+
}
292+
}
293+
269294
/** This function sets up Autolinking for App users */
270295
private fun configureAutolinking(
271296
project: Project,
@@ -293,18 +318,6 @@ class ReactPlugin : Plugin<Project> {
293318
generatedPureCxxSourceDir,
294319
pureCxxDependencies,
295320
)
296-
val pureCxxCmakeListsPaths =
297-
pureCxxDependencies
298-
.mapNotNull { dependency ->
299-
val libraryName = dependency.platforms?.android?.libraryName ?: return@mapNotNull null
300-
libraryName to
301-
generatedPureCxxSourceDir
302-
.get()
303-
.file("$libraryName/jni/CMakeLists.txt")
304-
.asFile
305-
.absolutePath
306-
}
307-
.toMap()
308321

309322
// We add a task called generateAutolinkingPackageList to do not clash with the existing task
310323
// called generatePackageList. This can to be renamed once we unlink the rn <-> cli
@@ -338,7 +351,11 @@ class ReactPlugin : Plugin<Project> {
338351
) { task ->
339352
task.autolinkInputFile.set(rootGeneratedAutolinkingFile)
340353
task.generatedOutputDirectory.set(generatedAutolinkingJniDir)
341-
task.generatedPureCxxCmakeListsPaths.set(pureCxxCmakeListsPaths)
354+
355+
if (pureCxxDependencies.isNotEmpty()) {
356+
task.generatedPureCxxSourceDirectory.set(generatedPureCxxSourceDir)
357+
}
358+
342359
task.dependsOn(pureCxxCodegenTasks)
343360
}
344361
project.tasks
@@ -370,61 +387,42 @@ class ReactPlugin : Plugin<Project> {
370387
generatedPureCxxSourceDir: Provider<Directory>,
371388
dependencies: List<ModelAutolinkingDependenciesJson>,
372389
): List<TaskProvider<GenerateCodegenArtifactsTask>> {
373-
return dependencies.map { dependency ->
374-
val android = dependency.platforms?.android!!
375-
val libraryName = android.libraryName!!
390+
// Pure C++ dependencies are not included as Gradle subprojects, so configureCodegen won't run
391+
// for them. The app owns these generated codegen artifacts and links them from autolinking.
392+
return dependencies.mapNotNull { dependency ->
393+
val android = dependency.platforms?.android ?: return@mapNotNull null
394+
val libraryName = android.libraryName ?: return@mapNotNull null
376395
val dependencyRoot = File(dependency.root)
377396
val packageJson = File(dependencyRoot, "package.json")
378397
val parsedPackageJson = JsonUtils.fromPackageJson(packageJson)
379398
val jsSrcsDir = parsedPackageJson?.codegenConfig?.jsSrcsDir
380399
val generatedSrcDir = generatedPureCxxSourceDir.map { it.dir(libraryName) }
381400
val taskNameSuffix = taskNameSuffixForDependency(dependency)
382-
val generateCodegenSchemaTask =
383-
project.tasks.register(
384-
"generate${taskNameSuffix}CodegenSchemaFromJavaScript",
385-
GenerateCodegenSchemaTask::class.java,
386-
) { task ->
387-
task.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
388-
task.codegenDir.set(rootExtension.codegenDir)
389-
task.generatedSrcDir.set(generatedSrcDir)
390-
task.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
401+
402+
registerCodegenTasks(
403+
project = project,
404+
rootExtension = rootExtension,
405+
generatedSrcDir = generatedSrcDir,
406+
packageJsonFile = packageJson,
407+
schemaTaskName = "generate${taskNameSuffix}CodegenSchemaFromJavaScript",
408+
artifactsTaskName = "generate${taskNameSuffix}CodegenArtifactsFromSchema",
409+
configureJsRoot = { task ->
391410
if (jsSrcsDir != null) {
392411
task.jsRootDir.set(File(packageJson.parentFile, jsSrcsDir))
393412
} else {
394413
task.jsRootDir.set(dependencyRoot)
395414
}
396-
task.jsInputFiles.set(
397-
project.fileTree(task.jsRootDir) { tree ->
398-
tree.include("**/*.js")
399-
tree.include("**/*.jsx")
400-
tree.include("**/*.ts")
401-
tree.include("**/*.tsx")
402-
403-
tree.exclude("node_modules/**/*")
404-
tree.exclude("**/*.d.ts")
405-
tree.exclude("**/build/**/*")
406-
}
407-
)
408-
}
409-
410-
project.tasks.register(
411-
"generate${taskNameSuffix}CodegenArtifactsFromSchema",
412-
GenerateCodegenArtifactsTask::class.java,
413-
) { task ->
414-
task.dependsOn(generateCodegenSchemaTask)
415-
task.reactNativeDir.set(rootExtension.reactNativeDir)
416-
task.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
417-
task.generatedSrcDir.set(generatedSrcDir)
418-
task.packageJsonFile.set(packageJson)
419-
val codegenJavaPackageName = parsedPackageJson?.codegenConfig?.android?.javaPackageName
420-
if (codegenJavaPackageName != null) {
421-
task.codegenJavaPackageName.set(codegenJavaPackageName)
422-
} else {
423-
task.codegenJavaPackageName.set(extension.codegenJavaPackageName)
424-
}
425-
task.libraryName.set(libraryName)
426-
task.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
427-
}
415+
},
416+
configureCodegenArtifacts = { task ->
417+
val codegenJavaPackageName = parsedPackageJson?.codegenConfig?.android?.javaPackageName
418+
if (codegenJavaPackageName != null) {
419+
task.codegenJavaPackageName.set(codegenJavaPackageName)
420+
} else {
421+
task.codegenJavaPackageName.set(extension.codegenJavaPackageName)
422+
}
423+
task.libraryName.set(libraryName)
424+
},
425+
)
428426
}
429427
}
430428

@@ -449,8 +447,8 @@ class ReactPlugin : Plugin<Project> {
449447
}
450448

451449
private fun taskNameSuffixForDependency(dependency: ModelAutolinkingDependenciesJson): String =
452-
dependency.nameCleansed
453-
.split(Regex("[^A-Za-z0-9]+"))
454-
.filter { it.isNotEmpty() }
455-
.joinToString("") { it.replaceFirstChar { char -> char.titlecase() } }
450+
dependency.name
451+
.map { char -> if (char.isLetterOrDigit()) char.toString() else "_${char.code}_" }
452+
.joinToString("")
453+
.replaceFirstChar { char -> char.titlecase() }
456454
}

packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateAutolinkingNewArchitecturesFileTask.kt

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,23 @@ import java.io.File
1414
import org.gradle.api.DefaultTask
1515
import org.gradle.api.file.DirectoryProperty
1616
import org.gradle.api.file.RegularFileProperty
17-
import org.gradle.api.provider.MapProperty
18-
import org.gradle.api.tasks.Input
17+
import org.gradle.api.tasks.InputDirectory
1918
import org.gradle.api.tasks.InputFile
19+
import org.gradle.api.tasks.Optional
2020
import org.gradle.api.tasks.OutputDirectory
2121
import org.gradle.api.tasks.TaskAction
2222

2323
abstract class GenerateAutolinkingNewArchitecturesFileTask : DefaultTask() {
2424

2525
init {
2626
group = "react"
27-
generatedPureCxxCmakeListsPaths.convention(emptyMap<String, String>())
2827
}
2928

3029
@get:InputFile abstract val autolinkInputFile: RegularFileProperty
3130

3231
@get:OutputDirectory abstract val generatedOutputDirectory: DirectoryProperty
3332

34-
@get:Input abstract val generatedPureCxxCmakeListsPaths: MapProperty<String, String>
33+
@get:Optional @get:InputDirectory abstract val generatedPureCxxSourceDirectory: DirectoryProperty
3534

3635
@TaskAction
3736
fun taskAction() {
@@ -63,7 +62,8 @@ abstract class GenerateAutolinkingNewArchitecturesFileTask : DefaultTask() {
6362
val cmakeListsPath = cmakeListsPathForDependency(dep)
6463
val cxxModuleCMakeListsPath = dep.cxxModuleCMakeListsPath
6564
if (libraryName != null && cmakeListsPath != null) {
66-
// If user provided a custom cmakeListsPath, let's honor it.
65+
// If user provided a custom cmakeListsPath, let's honor it. Otherwise, pure C++
66+
// dependencies use the app-owned generated codegen directory.
6767
val nativeFolderPath = sanitizeCmakeListsPath(cmakeListsPath)
6868
addDirectoryString +=
6969
"""
@@ -104,7 +104,23 @@ abstract class GenerateAutolinkingNewArchitecturesFileTask : DefaultTask() {
104104
private fun cmakeListsPathForDependency(
105105
dep: ModelAutolinkingDependenciesPlatformAndroidJson
106106
): String? {
107-
return dep.cmakeListsPath ?: dep.libraryName?.let { generatedPureCxxCmakeListsPaths.get()[it] }
107+
if (dep.cmakeListsPath != null) {
108+
return dep.cmakeListsPath
109+
}
110+
111+
if (
112+
dep.isPureCxxDependency != true ||
113+
dep.libraryName == null ||
114+
!generatedPureCxxSourceDirectory.isPresent
115+
) {
116+
return null
117+
}
118+
119+
return generatedPureCxxSourceDirectory
120+
.get()
121+
.file("${dep.libraryName}/jni/CMakeLists.txt")
122+
.asFile
123+
.absolutePath
108124
}
109125

110126
internal fun generateCppFileContent(

0 commit comments

Comments
 (0)