Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update README.md to use new plugins DSL #77

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,29 @@ class and in the Android manifest file.

Groovy:
```groovy
buildscript {
dependencies {
classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1"
}
plugins {
id "com.google.android.libraries.mapsplatform.secrets-gradle-plugin" version "2.0.1" apply false
}
```

Kotlin:
```kotlin
buildscript {
dependencies {
classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1")
}
plugins {
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") version "2.0.1" apply false
}
```

With a TOML version catalog:
```toml
[versions]
secrets = "2.0.1"

[plugins]
secrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secrets" }
```
```kotlin
plugins {
alias(libs.plugins.secrets) apply false
}
```

Expand All @@ -54,6 +64,13 @@ plugins {
}
```

With a TOML version catalog:
```kotlin
plugins {
alias(libs.plugins.secrets)
}
```

This plugin also supports library module type (`com.android.library`). Just install the plugin in your library-level `build.gradle` file and keys will be visible inside that module as well.

### Snapshot Releases
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

@file:Suppress("UnstableApiUsage")

package com.google.android.libraries.mapsplatform.secrets_gradle_plugin

import com.android.build.api.variant.ApplicationAndroidComponentsExtension
import com.android.build.api.variant.BuildConfigField
import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.android.build.api.variant.Variant
import com.android.build.gradle.AppExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.internal.core.InternalBaseVariant
import org.gradle.api.Project
import java.io.FileNotFoundException
import java.util.Properties

fun Project.androidAppComponent(): ApplicationAndroidComponentsExtension? =
extensions.findByType(ApplicationAndroidComponentsExtension::class.java)

fun Project.androidLibraryComponent(): LibraryAndroidComponentsExtension? =
extensions.findByType(LibraryAndroidComponentsExtension::class.java)

fun Project.androidProject(): AppExtension? =
extensions.findByType(AppExtension::class.java)

fun Project.libraryProject(): LibraryExtension? =
extensions.findByType(LibraryExtension::class.java)

fun Project.loadPropertiesFile(fileName: String): Properties {
// Load file
val propertiesFile = file(fileName)
if (!propertiesFile.exists()) {
throw FileNotFoundException(
"The file '${propertiesFile.absolutePath}' could not be found"
)
}

// Load contents into properties object
val properties = Properties()
properties.load(propertiesFile.inputStream())
return properties
}

private val javaVarRegexp = Regex(pattern = "((?![a-zA-Z_\$0-9]).)")

fun Variant.inject(properties: Properties, ignore: List<String>) {
val ignoreRegexs = ignore.map { Regex(pattern = it) }
properties.keys.map { key ->
key as String
}.filter { key ->
key.isNotEmpty() && !ignoreRegexs.any { it.containsMatchIn(key) }
}.forEach { key ->
val value = properties.getProperty(key).removeSurrounding("\"")
val translatedKey = key.replace(javaVarRegexp, "")
buildConfigFields.put(
translatedKey,
BuildConfigField("String", value.addParenthesisIfNeeded(), null)
)
manifestPlaceholders.put(translatedKey, value)
}
}

fun InternalBaseVariant.inject(properties: Properties, ignore: List<String>) {
val ignoreRegexs = ignore.map { Regex(pattern = it) }
properties.keys.map { key ->
key as String
}.filter { key ->
key.isNotEmpty() && !ignoreRegexs.any { it.containsMatchIn(key) }
}.forEach { key ->
val value = properties.getProperty(key).removeSurrounding("\"")
val translatedKey = key.replace(javaVarRegexp, "")
buildConfigField("String", translatedKey, value.addParenthesisIfNeeded())
mergedFlavor.manifestPlaceholders[translatedKey] = value
}
}

fun String.addParenthesisIfNeeded(): String {
if (isEmpty()) {
return this
}
val charArray = this.toCharArray()
if (length > 1 && charArray[0] == '"' && charArray[charArray.size - 1] == '"') {
return this
}
return "\"$this\""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@file:Suppress("UnstableApiUsage")

package com.google.android.libraries.mapsplatform.secrets_gradle_plugin

import com.android.build.api.variant.Variant
import com.android.build.gradle.internal.core.InternalBaseVariant
import org.gradle.api.Plugin
import org.gradle.api.Project
import java.io.FileNotFoundException
import java.util.Properties

/**
* Plugin that reads secrets from a properties file and injects manifest build and BuildConfig
* variables into an Android project. Since property keys are turned into Java variables,
* invalid variable characters from the property key are removed.
*
* e.g.
* A key defined as "sdk.dir" in the properties file will be converted to "sdkdir".
*/
class SecretsPlugin : Plugin<Project> {

private val extensionName = "secrets"

override fun apply(project: Project) {
val extension = project.extensions.create(
extensionName,
SecretsPluginExtension::class.java
)
val supportedComponents =
listOf(project.androidAppComponent(), project.androidLibraryComponent())
supportedComponents.forEach { component ->
component?.onVariants { variant ->
val defaultProperties = extension.defaultPropertiesFileName?.let {
project.rootProject.loadPropertiesFile(it)
}

val properties: Properties? = try {
project.rootProject.loadPropertiesFile(
extension.propertiesFileName
)
} catch (e: FileNotFoundException) {
defaultProperties ?: throw e
}
generateConfigKey(project, extension, defaultProperties, properties, variant)
}
}
}

private fun generateConfigKey(
project: Project,
extension: SecretsPluginExtension,
defaultProperties: Properties?,
properties: Properties?,
variant: Variant
) {
// Inject defaults first
defaultProperties?.let {
variant.inject(it, extension.ignoreList)
}

properties?.let {
variant.inject(properties, extension.ignoreList)
}

// Inject build-type specific properties
val buildTypeFileName = "${variant.buildType}.properties"
val buildTypeProperties = try {
project.rootProject.loadPropertiesFile(buildTypeFileName)
} catch (e: FileNotFoundException) {
null
}
buildTypeProperties?.let {
variant.inject(it, extension.ignoreList)
}

// Inject flavor-specific properties
val flavorFileName = "${variant.flavorName}.properties"
val flavorProperties = try {
project.rootProject.loadPropertiesFile(flavorFileName)
} catch (e: FileNotFoundException) {
null
}
flavorProperties?.let {
variant.inject(it, extension.ignoreList)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.android.libraries.mapsplatform.secrets_gradle_plugin

/**
* Configuration object for [SecretsPlugin].
*/
open class SecretsPluginExtension {
/**
* The name of the properties file containing secrets. Defaults to "$defaultPropertiesFile"
*/
var propertiesFileName: String = defaultPropertiesFile

/**
* A list of keys this plugin should ignore and not inject. Defaults to $defaultIgnoreList
*/
var ignoreList: MutableList<String> = defaultIgnoreList

/**
* The name of the properties file containing secrets' default values.
*/
var defaultPropertiesFileName: String? = null

companion object {
const val defaultPropertiesFile = "local.properties"
val defaultIgnoreList = mutableListOf("sdk.dir")
}
}
Loading