From c3e7ea0b5b487a943ac60437a059e387ea2ddeea Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Mon, 18 Oct 2021 04:32:45 -0700 Subject: [PATCH] Export prepareGlog to an internal task (#32421) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/32421 This diff refactors the `prepareGlog` task to a separate Gradle task in the `.internal` package. The reason for this change is that `prepareGlog` was defining a `doLast` action and would result in being invalidated whenever the `build.gradle` file would change. This means that the Glog headers/source files would have been extracted again, effectively invalidating the timestamps for the native build. Changelog: [Internal] [Changed] - Export prepareGlog to an internal task Reviewed By: ShikaSD Differential Revision: D31661668 fbshipit-source-id: efcd5505a67d6c9f02fcab7a5c3255a160215661 --- ReactAndroid/build.gradle | 42 +----- .../react/tasks/internal/PrepareGlogTask.kt | 79 +++++++++++ .../tasks/internal/PrepareGlogTaskTest.kt | 130 ++++++++++++++++++ 3 files changed, 216 insertions(+), 35 deletions(-) create mode 100644 packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/PrepareGlogTask.kt create mode 100644 packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/PrepareGlogTaskTest.kt diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 513d76c64f1..e385fe40855 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -12,6 +12,8 @@ plugins { id("de.undercouch.download") } +import com.facebook.react.tasks.internal.* + import java.nio.file.Paths import de.undercouch.gradle.tasks.download.Download @@ -169,41 +171,11 @@ task downloadGlog(dependsOn: createNativeDepsDirectories, type: Download) { // Prepare glog sources to be compiled, this task will perform steps that normally should've been // executed by automake. This way we can avoid dependencies on make/automake -task prepareGlog(dependsOn: dependenciesPath ? [] : [downloadGlog], type: Copy) { - duplicatesStrategy("warn") - from(dependenciesPath ?: tarTree(downloadGlog.dest)) - from("src/main/jni/third-party/glog/") - include("glog-${GLOG_VERSION}/src/**/*", "Android.mk", "config.h") - includeEmptyDirs = false - filesMatching("**/*.h.in") { - filter(ReplaceTokens, tokens: [ - ac_cv_have_unistd_h : "1", - ac_cv_have_stdint_h : "1", - ac_cv_have_systypes_h : "1", - ac_cv_have_inttypes_h : "1", - ac_cv_have_libgflags : "0", - ac_google_start_namespace : "namespace google {", - ac_cv_have_uint16_t : "1", - ac_cv_have_u_int16_t : "1", - ac_cv_have___uint16 : "0", - ac_google_end_namespace : "}", - ac_cv_have___builtin_expect : "1", - ac_google_namespace : "google", - ac_cv___attribute___noinline : "__attribute__ ((noinline))", - ac_cv___attribute___noreturn : "__attribute__ ((noreturn))", - ac_cv___attribute___printf_4_5: "__attribute__((__format__ (__printf__, 4, 5)))" - ]) - it.path = (it.name - ".in") - } - into("$thirdPartyNdkDir/glog") - - doLast { - copy { - from(fileTree(dir: "$thirdPartyNdkDir/glog", includes: ["stl_logging.h", "logging.h", "raw_logging.h", "vlog_is_on.h", "**/src/glog/log_severity.h"]).files) - includeEmptyDirs = false - into("$thirdPartyNdkDir/glog/exported/glog") - } - } +final def prepareGlog = tasks.register("prepareGlog", PrepareGlogTask) { + it.dependsOn(dependenciesPath ? [] : [downloadGlog]) + it.glogPath.setFrom(dependenciesPath ?: tarTree(downloadGlog.dest)) + it.glogVersion.set(GLOG_VERSION) + it.outputDir.set(new File(thirdPartyNdkDir, "glog")) } // Create Android.mk library module based on jsc from npm diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/PrepareGlogTask.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/PrepareGlogTask.kt new file mode 100644 index 00000000000..6344b66f429 --- /dev/null +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/PrepareGlogTask.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.tasks.internal + +import java.io.File +import org.apache.tools.ant.filters.ReplaceTokens +import org.gradle.api.DefaultTask +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.DuplicatesStrategy +import org.gradle.api.provider.Property +import org.gradle.api.tasks.* + +/** + * A task that takes care of extracting Glog from a source folder/zip and preparing it to be + * consumed by the NDK. This task will also take care of applying the mapping for Glog parameters. + */ +abstract class PrepareGlogTask : DefaultTask() { + + @get:InputFiles abstract val glogPath: ConfigurableFileCollection + + @get:Input abstract val glogVersion: Property + + @get:OutputDirectory abstract val outputDir: DirectoryProperty + + @TaskAction + fun taskAction() { + project.copy { + it.from(glogPath) + it.from(project.file("src/main/jni/third-party/glog/")) + it.include("glog-${glogVersion.get()}/src/**/*", "Android.mk", "config.h") + it.duplicatesStrategy = DuplicatesStrategy.WARN + it.includeEmptyDirs = false + it.filesMatching("**/*.h.in") { matchedFile -> + matchedFile.filter( + mapOf( + "tokens" to + mapOf( + "ac_cv_have_unistd_h" to "1", + "ac_cv_have_stdint_h" to "1", + "ac_cv_have_systypes_h" to "1", + "ac_cv_have_inttypes_h" to "1", + "ac_cv_have_libgflags" to "0", + "ac_google_start_namespace" to "namespace google {", + "ac_cv_have_uint16_t" to "1", + "ac_cv_have_u_int16_t" to "1", + "ac_cv_have___uint16" to "0", + "ac_google_end_namespace" to "}", + "ac_cv_have___builtin_expect" to "1", + "ac_google_namespace" to "google", + "ac_cv___attribute___noinline" to "__attribute__ ((noinline))", + "ac_cv___attribute___noreturn" to "__attribute__ ((noreturn))", + "ac_cv___attribute___printf_4_5" to + "__attribute__((__format__ (__printf__, 4, 5)))")), + ReplaceTokens::class.java) + matchedFile.path = (matchedFile.name.removeSuffix(".in")) + } + it.into(outputDir) + } + val exportedDir = File(outputDir.asFile.get(), "exported/glog/").apply { mkdirs() } + project.copy { + it.from(outputDir) + it.include( + "stl_logging.h", + "logging.h", + "raw_logging.h", + "vlog_is_on.h", + "**/src/glog/log_severity.h") + it.eachFile { file -> file.path = file.name } + it.includeEmptyDirs = false + it.into(exportedDir) + } + } +} diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/PrepareGlogTaskTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/PrepareGlogTaskTest.kt new file mode 100644 index 00000000000..782bac3dce7 --- /dev/null +++ b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/PrepareGlogTaskTest.kt @@ -0,0 +1,130 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.tasks.internal + +import com.facebook.react.tests.createProject +import com.facebook.react.tests.createTestTask +import java.io.* +import org.junit.Assert.* +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder + +class PrepareGlogTaskTest { + + @get:Rule val tempFolder = TemporaryFolder() + + @Test(expected = IllegalStateException::class) + fun prepareGlogTask_withMissingConfiguration_fails() { + val task = createTestTask() + + task.taskAction() + } + + @Test + fun prepareGlogTask_copiesMakefile() { + val glogpath = tempFolder.newFolder("glogpath") + val output = tempFolder.newFolder("output") + val project = createProject() + val task = + createTestTask(project = project) { + it.glogPath.setFrom(glogpath) + it.glogVersion.set("1.0.0") + it.outputDir.set(output) + } + File(project.projectDir, "src/main/jni/third-party/glog/Android.mk").apply { + parentFile.mkdirs() + createNewFile() + } + task.taskAction() + + assertTrue(output.listFiles()!!.any { it.name == "Android.mk" }) + } + + @Test + fun prepareGlogTask_copiesConfigHeaderFile() { + val glogpath = tempFolder.newFolder("glogpath") + val output = tempFolder.newFolder("output") + val project = createProject() + val task = + createTestTask(project = project) { + it.glogPath.setFrom(glogpath) + it.glogVersion.set("1.0.0") + it.outputDir.set(output) + } + File(project.projectDir, "src/main/jni/third-party/glog/config.h").apply { + parentFile.mkdirs() + createNewFile() + } + task.taskAction() + + assertTrue(output.listFiles()!!.any { it.name == "config.h" }) + } + + @Test + fun prepareGlogTask_copiesSourceCode() { + val glogpath = tempFolder.newFolder("glogpath") + val output = tempFolder.newFolder("output") + val task = + createTestTask { + it.glogPath.setFrom(glogpath) + it.glogVersion.set("1.0.0") + it.outputDir.set(output) + } + File(glogpath, "glog-1.0.0/src/glog.cpp").apply { + parentFile.mkdirs() + createNewFile() + } + + task.taskAction() + + assertTrue(File(output, "glog-1.0.0/src/glog.cpp").exists()) + } + + @Test + fun prepareGlogTask_replacesTokenCorrectly() { + val glogpath = tempFolder.newFolder("glogpath") + val output = tempFolder.newFolder("output") + val task = + createTestTask { + it.glogPath.setFrom(glogpath) + it.glogVersion.set("1.0.0") + it.outputDir.set(output) + } + File(glogpath, "glog-1.0.0/src/glog.h.in").apply { + parentFile.mkdirs() + writeText("ac_google_start_namespace") + } + + task.taskAction() + + val expectedFile = File(output, "glog.h") + assertTrue(expectedFile.exists()) + assertEquals("ac_google_start_namespace", expectedFile.readText()) + } + + @Test + fun prepareGlogTask_exportsHeaderCorrectly() { + val glogpath = tempFolder.newFolder("glogpath") + val output = tempFolder.newFolder("output") + val task = + createTestTask { + it.glogPath.setFrom(glogpath) + it.glogVersion.set("1.0.0") + it.outputDir.set(output) + } + File(glogpath, "glog-1.0.0/src/logging.h.in").apply { + parentFile.mkdirs() + writeText("ac_google_start_namespace") + } + + task.taskAction() + + assertTrue(File(output, "exported/glog/logging.h").exists()) + } +}