Skip to content

Commit 93f0f36

Browse files
committed
Refactor: Modernize gradle task inputs for configuration cache compatibility
1 parent ac0dd45 commit 93f0f36

3 files changed

Lines changed: 111 additions & 60 deletions

File tree

secretsvaultplugin/src/main/kotlin/com/commencis/secretsvaultplugin/KeepSecretsTask.kt

Lines changed: 82 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
11
package com.commencis.secretsvaultplugin
22

3-
import com.android.build.api.dsl.CommonExtension
4-
import com.commencis.secretsvaultplugin.extensions.SecretsVaultExtension
53
import com.commencis.secretsvaultplugin.utils.CHECK_APP_SIGNATURE_PLACEHOLDER
64
import com.commencis.secretsvaultplugin.utils.CodeGenerator
75
import com.commencis.secretsvaultplugin.utils.EMPTY_STRING
86
import com.commencis.secretsvaultplugin.utils.Utils
97
import com.commencis.secretsvaultplugin.utils.capitalize
108
import kotlinx.serialization.json.Json
119
import org.gradle.api.DefaultTask
10+
import org.gradle.api.file.Directory
11+
import org.gradle.api.file.DirectoryProperty
12+
import org.gradle.api.file.ProjectLayout
13+
import org.gradle.api.file.RegularFileProperty
14+
import org.gradle.api.provider.ListProperty
1215
import org.gradle.api.provider.Property
16+
import org.gradle.api.tasks.Input
1317
import org.gradle.api.tasks.InputDirectory
14-
import org.gradle.api.tasks.Internal
18+
import org.gradle.api.tasks.InputFile
19+
import org.gradle.api.tasks.Optional
1520
import org.gradle.api.tasks.TaskAction
1621
import java.io.File
1722
import java.io.IOException
1823
import java.nio.charset.Charset
1924
import java.util.Locale
25+
import javax.inject.Inject
2026

2127
internal const val MAIN_SOURCE_SET_NAME = "main"
2228

@@ -52,62 +58,83 @@ private const val ANSI_COLOR_YELLOW = "\u001B[33m"
5258
* replaces them with obfuscated keys from the provided json file.
5359
*/
5460
@Suppress("TooManyFunctions", "UnnecessaryAbstractClass")
55-
internal abstract class KeepSecretsTask : DefaultTask() {
61+
internal abstract class KeepSecretsTask @Inject constructor(private val projectLayout: ProjectLayout) : DefaultTask() {
5662

5763
/**
58-
* Map containing the secrets
64+
* Plugin source directory that has the cpp and kotlin files
5965
*/
60-
private var secretsMap: Map<SecretsSourceSet, List<Secret>>? = null
66+
@get:InputDirectory
67+
abstract val pluginSourceFolder: DirectoryProperty
6168

6269
/**
63-
* Map containing the source sets and their respective secrets file names
70+
* The secrets file to read from
6471
*/
65-
private var sourceSetToSecretFileMap: Map<SecretsSourceSet, Pair<SecretsFileName, CMakeArgument>>? = null
72+
@get:InputFile
73+
abstract val secretsFile: RegularFileProperty
6674

6775
/**
68-
* Plugin source folder that has the cpp and kotlin files
76+
* Optional mapping file for source sets to secret file names
6977
*/
70-
@get:InputDirectory
71-
abstract val pluginSourceFolder: Property<File>
78+
@get:InputFile
79+
@get:Optional
80+
abstract val sourceSetSecretsMappingFile: RegularFileProperty
7281

7382
/**
74-
* Represents the JSON property of the class it's abstracted in.
83+
* The obfuscation key
7584
*/
76-
@get:Internal
77-
abstract val json: Property<Json>
85+
@get:Input
86+
abstract val obfuscationKey: Property<String>
7887

7988
/**
80-
* Provides lazy access to the [SecretsVaultExtension] of the project.
89+
* List of application signatures
8190
*/
82-
private val secretsVaultExtension by lazy {
83-
project.extensions.getByType(SecretsVaultExtension::class.java)
84-
}
91+
@get:Input
92+
abstract val appSignatures: ListProperty<String>
8593

8694
/**
87-
* Provides lazy access to the [CMakeExtension] of the project.
95+
* The package name
8896
*/
89-
private val cMakeExtension by lazy {
90-
secretsVaultExtension.cmake.get()
91-
}
97+
@get:Input
98+
abstract val packageName: Property<String>
9299

93100
/**
94-
* Get the package name of the module on which this plugin is used
95-
*
96-
* The function will first attempt to get the package name from the [SecretsVaultExtension].
97-
* If it's not provided (i.e., it's an empty string), the function will attempt to get the namespace
98-
* from the [CommonExtension] of the project.
101+
* Whether to make the generated class injectable
99102
*/
100-
private val packageName: String by lazy {
101-
secretsVaultExtension.packageName.getOrElse(EMPTY_STRING).ifEmpty {
102-
project.extensions.getByType(CommonExtension::class.java).namespace.orEmpty()
103-
}
104-
}
103+
@get:Input
104+
abstract val makeInjectable: Property<Boolean>
105+
106+
/**
107+
* CMake project name
108+
*/
109+
@get:Input
110+
abstract val cmakeProjectName: Property<String>
111+
112+
/**
113+
* CMake version
114+
*/
115+
@get:Input
116+
abstract val cmakeVersion: Property<String>
117+
118+
private val projectDirectory: Directory
119+
get() = projectLayout.projectDirectory
105120

106121
/**
107122
* Lazily initialized instance of [CodeGenerator].
108123
*/
109124
private val codeGenerator by lazy { CodeGenerator() }
110125

126+
private val json = Json { encodeDefaults = true }
127+
128+
/**
129+
* Map containing the secrets
130+
*/
131+
private var secretsMap: Map<SecretsSourceSet, List<Secret>>? = null
132+
133+
/**
134+
* Map containing the source sets and their respective secrets file names
135+
*/
136+
private var sourceSetToSecretFileMap: Map<SecretsSourceSet, Pair<SecretsFileName, CMakeArgument>>? = null
137+
111138
/**
112139
* The main task action which is responsible for keeping secrets
113140
*/
@@ -135,7 +162,7 @@ internal abstract class KeepSecretsTask : DefaultTask() {
135162
*/
136163
@Throws(IllegalArgumentException::class)
137164
private fun getSecretsFile(): File {
138-
val secretsFile = secretsVaultExtension.secretsFile.get()
165+
val secretsFile = secretsFile.get().asFile
139166
require(secretsFile.exists() && secretsFile.isFile) {
140167
"${secretsFile.name} does not exist or is not a valid file!"
141168
}
@@ -150,7 +177,7 @@ internal abstract class KeepSecretsTask : DefaultTask() {
150177
*/
151178
@Throws(IllegalArgumentException::class)
152179
private fun getSourceSetToSecretMappingFile(): File? {
153-
val mappingFile = secretsVaultExtension.sourceSetSecretsMappingFile.orNull
180+
val mappingFile = sourceSetSecretsMappingFile.orNull?.asFile
154181
if (mappingFile != null) {
155182
require(mappingFile.exists() && mappingFile.isFile) {
156183
"${mappingFile.name} does not exist or is not a valid file!"
@@ -167,7 +194,7 @@ internal abstract class KeepSecretsTask : DefaultTask() {
167194
private fun initSecretsFromFile(secretsFile: File) {
168195
val content = secretsFile.readText(Charsets.UTF_8)
169196
runCatching {
170-
secretsMap = json.get().decodeFromString<Secrets>(content).secrets.groupBy { it.sourceSet }
197+
secretsMap = json.decodeFromString<Secrets>(content).secrets.groupBy { it.sourceSet }
171198
}.onFailure { throwable ->
172199
logger.error(
173200
"""
@@ -193,7 +220,7 @@ internal abstract class KeepSecretsTask : DefaultTask() {
193220
private fun initSourceSetToSecretFileMap(mappingFile: File) {
194221
val content = mappingFile.readText(Charsets.UTF_8)
195222
runCatching {
196-
sourceSetToSecretFileMap = json.get().decodeFromString<SourceSetToSecretFileMappingArray>(content).toMap()
223+
sourceSetToSecretFileMap = json.decodeFromString<SourceSetToSecretFileMappingArray>(content).toMap()
197224
if (sourceSetToSecretFileMap?.any { it.value.first.name == MAIN_SOURCE_SET_SECRETS_FILE_NAME } == true) {
198225
logger.error(
199226
"""
@@ -236,7 +263,9 @@ internal abstract class KeepSecretsTask : DefaultTask() {
236263
fileName: String,
237264
pathSuffix: String = EMPTY_STRING,
238265
): File {
239-
return project.file(SOURCE_SET_TEMPLATE.format(sourceSet.sourceSet, "cpp") + pathSuffix + fileName)
266+
return projectDirectory
267+
.file(SOURCE_SET_TEMPLATE.format(sourceSet.sourceSet, "cpp") + pathSuffix + fileName)
268+
.asFile
240269
}
241270

242271
/**
@@ -249,11 +278,11 @@ internal abstract class KeepSecretsTask : DefaultTask() {
249278
private fun getKotlinDestination(sourceSet: SecretsSourceSet, fileName: String): File {
250279
val kotlinPath = SOURCE_SET_TEMPLATE.format(sourceSet.sourceSet, "kotlin")
251280
val javaPath = SOURCE_SET_TEMPLATE.format(sourceSet.sourceSet, "java")
252-
val basePath = kotlinPath.takeIf { project.file(kotlinPath).exists() } ?: javaPath
253-
val packagePath = packageName.replace(".", File.separator)
281+
val basePath = kotlinPath.takeIf { projectDirectory.file(kotlinPath).asFile.exists() } ?: javaPath
282+
val packagePath = packageName.get().replace(".", File.separator)
254283
val fullPath = basePath + packagePath
255284

256-
val directory = project.file(fullPath)
285+
val directory = projectDirectory.file(fullPath).asFile
257286
if (directory.exists().not()) {
258287
logger.lifecycle("Directory $fullPath does not exist in the project, creating it.")
259288
directory.mkdirs()
@@ -267,18 +296,18 @@ internal abstract class KeepSecretsTask : DefaultTask() {
267296
*/
268297
private fun copyCommonCppFiles() {
269298
runCatching {
270-
val appSignaturesCodeBlock = secretsVaultExtension.appSignatures.get().map { appSignature ->
299+
val appSignaturesCodeBlock = appSignatures.get().map { appSignature ->
271300
Utils.encodeSecret(
272301
secretKey = appSignature.replace(":", EMPTY_STRING),
273-
obfuscationKey = secretsVaultExtension.obfuscationKey.get(),
302+
obfuscationKey = obfuscationKey.get(),
274303
)
275304
}.let { encodedAppSignatures ->
276305
codeGenerator.getAppSignatureCheck(encodedAppSignatures)
277306
}
278-
project.file("${pluginSourceFolder.get().path}/cpp/common/").listFiles()?.forEach { file ->
307+
pluginSourceFolder.dir("cpp/common/").get().asFile.listFiles()?.forEach { file ->
279308
var text = file.readText(Charset.defaultCharset())
280309
if (file.name == SECRETS_UTIL_CPP_FILE_NAME) {
281-
text = text.replace(OBFUSCATION_KEY_PLACEHOLDER, secretsVaultExtension.obfuscationKey.get())
310+
text = text.replace(OBFUSCATION_KEY_PLACEHOLDER, obfuscationKey.get())
282311
.replace(CHECK_APP_SIGNATURE_PLACEHOLDER, appSignaturesCodeBlock)
283312
}
284313
val destination = getCppDestination(
@@ -302,7 +331,7 @@ internal abstract class KeepSecretsTask : DefaultTask() {
302331
*/
303332
private fun copySecretCppFile(sourceSet: SecretsSourceSet) {
304333
runCatching {
305-
val secretsFile = project.file("${pluginSourceFolder.get().path}/cpp/$SECRETS_CPP_FILE_NAME")
334+
val secretsFile = pluginSourceFolder.dir("cpp/$SECRETS_CPP_FILE_NAME").get().asFile
306335
val text = secretsFile.readText(Charset.defaultCharset()).replace(
307336
oldValue = COMMON_FOLDER_PATH_PREFIX_PLACEHOLDER,
308337
newValue = if (sourceSet == SecretsSourceSet(MAIN_SOURCE_SET_NAME)) {
@@ -328,11 +357,11 @@ internal abstract class KeepSecretsTask : DefaultTask() {
328357
private fun copyCMakeListsFile(sourceSets: Set<SecretsSourceSet>) {
329358
runCatching {
330359
val mainSourceSet = SecretsSourceSet(MAIN_SOURCE_SET_NAME)
331-
val file = project.file("${pluginSourceFolder.get().path}/cpp/$C_MAKE_LISTS_FILE_NAME")
360+
val file = pluginSourceFolder.dir("cpp/$C_MAKE_LISTS_FILE_NAME").get().asFile
332361
val textBuilder = StringBuilder(
333362
file.readText(Charset.defaultCharset())
334-
.replace(PROJECT_NAME_PLACEHOLDER, cMakeExtension.projectName.get())
335-
.replace(CMAKE_VERSION_PLACEHOLDER, cMakeExtension.version.get())
363+
.replace(PROJECT_NAME_PLACEHOLDER, cmakeProjectName.get())
364+
.replace(CMAKE_VERSION_PLACEHOLDER, cmakeVersion.get())
336365
)
337366
if (sourceSets.contains(mainSourceSet)) {
338367
val fileName = getKotlinSecretsFileName(mainSourceSet).removeSuffix(KOTLIN_FILE_NAME_SUFFIX)
@@ -378,18 +407,18 @@ internal abstract class KeepSecretsTask : DefaultTask() {
378407

379408
private fun copyKotlinFile(sourceSet: SecretsSourceSet) {
380409
runCatching {
381-
val kotlinFileName = if (secretsVaultExtension.makeInjectable.get()) {
410+
val kotlinFileName = if (makeInjectable.get()) {
382411
TEMP_KOTLIN_INJECTABLE_FILE_NAME
383412
} else {
384413
TEMP_KOTLIN_NOT_INJECTABLE_FILE_NAME
385414
}
386-
val kotlinFiles = project.file("${pluginSourceFolder.get().path}/kotlin/").listFiles()
415+
val kotlinFiles = pluginSourceFolder.dir("kotlin").get().asFile.listFiles()
387416
val kotlinFile = kotlinFiles?.find { file ->
388417
file.name == kotlinFileName
389418
} ?: throw IOException("Kotlin file that will be copied not found")
390419
var text = kotlinFile.readText(Charset.defaultCharset())
391420
val fileName = getKotlinSecretsFileName(sourceSet)
392-
text = text.replace(PACKAGE_PLACEHOLDER, packageName)
421+
text = text.replace(PACKAGE_PLACEHOLDER, packageName.get())
393422
.replace(SECRETS_CLASS_NAME_PLACEHOLDER, fileName.removeSuffix(KOTLIN_FILE_NAME_SUFFIX))
394423
val destination = getKotlinDestination(
395424
sourceSet = sourceSet,
@@ -480,13 +509,13 @@ internal abstract class KeepSecretsTask : DefaultTask() {
480509
var kotlinPackage = Utils.getKotlinFilePackage(secretsKotlin)
481510
if (kotlinPackage.isNullOrEmpty()) {
482511
logWarning("Empty package in $fileName")
483-
kotlinPackage = packageName
512+
kotlinPackage = packageName.get()
484513
}
485514

486515
val secretsCpp = getCppDestination(sourceSet = sourceSet, fileName = SECRETS_CPP_FILE_NAME)
487516
secrets.forEach { secret ->
488517
val (key, value) = secret
489-
val obfuscatedValue = Utils.encodeSecret(value, secretsVaultExtension.obfuscationKey.get())
518+
val obfuscatedValue = Utils.encodeSecret(value, obfuscationKey.get())
490519
val cppText = secretsCpp.readText(Charset.defaultCharset())
491520
val keyName = "$JVM_NAME_PREFIX${secretKeyToIndexMap[key]}"
492521
if (cppText.contains(keyName)) {

secretsvaultplugin/src/main/kotlin/com/commencis/secretsvaultplugin/SecretsVaultPlugin.kt

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package com.commencis.secretsvaultplugin
22

3+
import com.android.build.api.dsl.CommonExtension
34
import com.commencis.secretsvaultplugin.extensions.CMakeExtension
45
import com.commencis.secretsvaultplugin.extensions.SecretsVaultExtension
6+
import com.commencis.secretsvaultplugin.utils.EMPTY_STRING
57
import com.commencis.secretsvaultplugin.utils.Utils
6-
import kotlinx.serialization.json.Json
78
import org.gradle.api.Plugin
89
import org.gradle.api.Project
910
import org.gradle.api.tasks.Copy
@@ -57,14 +58,35 @@ internal class SecretsVaultPlugin : Plugin<Project> {
5758
into(project.layout.buildDirectory.dir("intermediates/secrets_vault_plugin"))
5859
}
5960

61+
val secretsVaultExtension = project.extensions.getByType(SecretsVaultExtension::class.java)
62+
6063
/**
6164
* Create a gradle task to keep secrets from a json file.
6265
*/
6366
project.tasks.register(TASK_KEEP_SECRETS_FROM_JSON_FILE, KeepSecretsTask::class.java).configure {
6467
group = TASK_GROUP
6568
description = "Re-generate and obfuscate keys from the json file and add it to your Android project"
66-
pluginSourceFolder.set(unzipTaskProvider.map { task -> task.destinationDir })
67-
json.set(Json { encodeDefaults = true })
69+
pluginSourceFolder.set(
70+
unzipTaskProvider.map {
71+
project.layout.projectDirectory.dir(it.destinationDir.path)
72+
}
73+
)
74+
secretsFile.set(secretsVaultExtension.secretsFile)
75+
sourceSetSecretsMappingFile.set(secretsVaultExtension.sourceSetSecretsMappingFile)
76+
obfuscationKey.set(secretsVaultExtension.obfuscationKey)
77+
appSignatures.set(secretsVaultExtension.appSignatures)
78+
makeInjectable.set(secretsVaultExtension.makeInjectable)
79+
80+
// Provide the package name in the extension unless it is not specified or empty,
81+
// in which case the namespace is used.
82+
packageName.set(
83+
secretsVaultExtension.packageName.getOrElse(EMPTY_STRING).ifEmpty {
84+
project.extensions.getByType(CommonExtension::class.java).namespace.orEmpty()
85+
}
86+
)
87+
88+
cmakeProjectName.set(secretsVaultExtension.cmake.flatMap { it.projectName })
89+
cmakeVersion.set(secretsVaultExtension.cmake.flatMap { it.version })
6890
}
6991
}
7092

@@ -91,7 +113,7 @@ internal class SecretsVaultPlugin : Plugin<Project> {
91113
private fun createSecretsVaultExtension(project: Project, cmakeExtension: CMakeExtension): SecretsVaultExtension {
92114
return project.extensions.create(EXTENSION_NAME_SECRETS_VAULT, SecretsVaultExtension::class.java).apply {
93115
obfuscationKey.convention(Utils.generateObfuscationKey())
94-
secretsFile.convention(project.file(DEFAULT_SECRETS_FILE_NAME))
116+
secretsFile.convention(project.layout.projectDirectory.file(DEFAULT_SECRETS_FILE_NAME))
95117
appSignatures.convention(emptyList())
96118
makeInjectable.convention(DEFAULT_MAKE_INJECTABLE_VALUE)
97119
cmake.convention(cmakeExtension)

secretsvaultplugin/src/main/kotlin/com/commencis/secretsvaultplugin/extensions/SecretsVaultExtension.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package com.commencis.secretsvaultplugin.extensions
22

33
import com.commencis.secretsvaultplugin.utils.EMPTY_STRING
4+
import org.gradle.api.file.RegularFileProperty
45
import org.gradle.api.provider.ListProperty
56
import org.gradle.api.provider.Property
6-
import java.io.File
77

88
/**
99
* Provides extension properties for the SecretVault, allowing configurations to be set.
@@ -25,8 +25,8 @@ import java.io.File
2525
*/
2626
interface SecretsVaultExtension {
2727
val obfuscationKey: Property<String>
28-
val secretsFile: Property<File>
29-
val sourceSetSecretsMappingFile: Property<File>
28+
val secretsFile: RegularFileProperty
29+
val sourceSetSecretsMappingFile: RegularFileProperty
3030
val appSignatures: ListProperty<String>
3131
val packageName: Property<String>
3232
val makeInjectable: Property<Boolean>

0 commit comments

Comments
 (0)