Skip to content

Commit c572b04

Browse files
author
Adrián García
authored
Add support for library modules (#19)
* Add support for library modules * Update CHANGELOG and README with latest changes * Apply suggestions from code review
1 parent 6cf726d commit c572b04

File tree

3 files changed

+168
-53
lines changed

3 files changed

+168
-53
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222

2323
## [Unreleased]
2424
### Added
25-
- Add support for configuring non-standard resource directory path via `defaultResPath`. _Thanks to [@rafid059](https://github.com/rafid059) for the contribution!_
25+
- Add support for using the plug-in in library modules.
26+
- Add support for configuring non-standard resource directory path via `defaultResPath`. _Thanks to [@rafid059](https://github.com/rafid059) for the contribution!_
2627
<details open><summary>Groovy</summary>
2728

2829
```groovy

README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ Attribute | Description
8181
```apiToken``` | PoEditor API Token.
8282
```projectId``` | PoEditor project ID.
8383
```defaultLang``` | The lang to be used to build default ```strings.xml``` (```/values``` folder)
84+
```defaultResPath``` | (Since 1.3.0) (Optional) Path where the plug-in should dump strings. Defaults to the module's default (or build variant) `res` path.
8485

8586
After the configuration is done, just run the new ```importPoEditorStrings``` task via Android Studio or command line:
8687

@@ -180,6 +181,46 @@ configuration: `importFreePoEditorStrings`, `importPaidPoEditorStrings`, `import
180181
Now the `importPoEditorStrings` task will import the main strings configured in the `poEditor` block and also the
181182
strings for each defined flavor or build type.
182183

184+
## Handling library modules
185+
> Requires version 1.3.0 of the plug-in
186+
187+
You can also apply the plug-in to library modules. Here's an example:
188+
Apply and configure the plug-in in your library's `build.gradle` file:
189+
<details open><summary>Groovy</summary>
190+
191+
```groovy
192+
apply plugin: "com.android.library"
193+
apply plugin: "com.bq.poeditor"
194+
195+
poEditor {
196+
apiToken = "your_api_token"
197+
projectId = 12345
198+
defaultLang = "en"
199+
}
200+
```
201+
202+
</details>
203+
204+
<details><summary>Kotlin</summary>
205+
206+
```kt
207+
plugins {
208+
id "com.android.library"
209+
id "com.bq.poeditor"
210+
}
211+
212+
poEditor {
213+
apiToken = "your_api_token"
214+
projectId = 12345
215+
defaultLang = "en"
216+
}
217+
```
218+
219+
</details>
220+
221+
You can also apply flavor and build type-specific configurations as you would do when setting them up with application modules.
222+
The plug-in will generate the proper tasks needed to import the strings under your module: `:<your_module>:import<your_flavor_or_build_type_if_any>PoEditorStrings`
223+
183224

184225
## Handling tablet specific strings
185226

@@ -254,6 +295,7 @@ If you want a similar solution for your iOS projects, check this out: [poeditor-
254295
## Authors & Collaborators
255296
* **[Iván Martínez](https://github.com/imartinez)** - *Initial work*
256297
* **[Adrián García](https://github.com/adriangl)** - *Maintainer*
298+
* **[sonnet](https://github.com/rafid059)** - *Contributor*
257299

258300
## License
259301
This project is licensed under the Apache Software License, Version 2.0.

src/main/kotlin/com/bq/poeditor/gradle/PoEditorPlugin.kt

Lines changed: 124 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@
1717
package com.bq.poeditor.gradle
1818

1919
import com.android.build.gradle.AppPlugin
20+
import com.android.build.gradle.LibraryExtension
21+
import com.android.build.gradle.LibraryPlugin
2022
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
2123
import com.bq.poeditor.gradle.ktx.registerNewTask
2224
import com.bq.poeditor.gradle.tasks.DummyImportPoEditorStringsTask
2325
import com.bq.poeditor.gradle.tasks.ImportPoEditorStringsTask
2426
import com.bq.poeditor.gradle.utils.*
27+
import org.gradle.api.NamedDomainObjectContainer
2528
import org.gradle.api.Plugin
2629
import org.gradle.api.Project
2730
import org.gradle.api.plugins.ExtensionAware
@@ -53,64 +56,49 @@ class PoEditorPlugin : Plugin<Project> {
5356
PLUGIN_GROUP,
5457
arrayOf(mainPoEditorExtension, mainResourceDirectory))
5558

59+
// Add flavor and build-type configurations if the project has the "com.android.application" plugin
5660
project.plugins.withType<AppPlugin> {
57-
applyInternal(project, mainPoEditorExtension)
61+
applyInternalApp(project, mainPoEditorExtension)
62+
}
63+
64+
// Add flavor and build-type configurations if the project has the "com.android.library" plugin
65+
project.plugins.withType<LibraryPlugin> {
66+
applyInternalLib(project, mainPoEditorExtension)
5867
}
5968

6069
project.afterEvaluate {
61-
if (project.plugins.findPlugin(AppPlugin::class.java) == null) {
70+
val projectHasApplicationPlugin = project.plugins.findPlugin(AppPlugin::class.java) != null
71+
val projectHasLibraryPlugin = project.plugins.findPlugin(LibraryPlugin::class.java) != null
72+
73+
val projectHasAnyAndroidPlugin = projectHasApplicationPlugin || projectHasLibraryPlugin
74+
75+
if (!projectHasAnyAndroidPlugin) {
6276
throw IllegalStateException(
63-
"The Android Gradle Plugin was not applied. " +
64-
"PoEditor plugin cannot be configured.")
77+
"The Android Application Gradle plug-in or the Android Library Gradle plug-in were not applied. " +
78+
"PoEditor plug-in cannot be configured.")
6579
}
6680
}
6781
}
6882

69-
private fun applyInternal(project: Project,
70-
mainPoEditorExtension: PoEditorPluginExtension) {
83+
private fun applyInternalApp(project: Project,
84+
mainExtension: PoEditorPluginExtension) {
7185
// Add android.poEditorConfig extension container so we can set-up flavors and build types
72-
// configurations.
73-
val configsPoEditorExtensionContainer = project.container<PoEditorPluginExtension>()
86+
// configurations with Android app modules.
87+
val configsExtensionContainer = project.container<PoEditorPluginExtension>()
7488
val androidExtension = project.the<BaseAppModuleExtension>()
75-
(androidExtension as ExtensionAware).extensions.add(POEDITOR_CONFIG_NAME, configsPoEditorExtensionContainer)
89+
(androidExtension as ExtensionAware).extensions.add(POEDITOR_CONFIG_NAME, configsExtensionContainer)
7690

7791
val configPoEditorTaskProvidersMap: MutableMap<ConfigName, TaskProvider<*>> = mutableMapOf()
7892

7993
// Add tasks for every build variant
8094
androidExtension.onVariants {
81-
val flavors = this.productFlavors.map { it.second }
82-
val buildType = this.buildType
83-
val configs = (flavors + buildType).filterNotNull().toSet()
84-
85-
configs.forEach { configName ->
86-
val configTaskName = getPoEditorTaskName(configName)
87-
88-
// Only create the task if no other task is registered with the same name (would mean it's already
89-
// created.
90-
project.tasks.findByName(configTaskName) ?: run {
91-
val configResourceDirectory = getResourceDirectory(project, configName)
92-
val configExtension = buildExtensionForConfig(
93-
configName,
94-
configsPoEditorExtensionContainer,
95-
mainPoEditorExtension)
96-
97-
val newConfigPoEditorTask = if (configExtension != null) {
98-
project.registerNewTask<ImportPoEditorStringsTask>(
99-
getPoEditorTaskName(configName),
100-
getMainPoEditorDescription(),
101-
PLUGIN_GROUP,
102-
arrayOf(configExtension, configResourceDirectory))
103-
} else {
104-
project.registerNewTask<DummyImportPoEditorStringsTask>(
105-
getPoEditorTaskName(configName),
106-
getMainPoEditorDescription(),
107-
PLUGIN_GROUP,
108-
arrayOf(configName))
109-
}
110-
111-
configPoEditorTaskProvidersMap.put(configName, newConfigPoEditorTask)
112-
}
113-
}
95+
val configs = getConfigs(this.productFlavors.map { it.second }, this.buildType)
96+
97+
generatePoEditorTasks(configs,
98+
project,
99+
configsExtensionContainer,
100+
mainExtension,
101+
configPoEditorTaskProvidersMap)
114102
}
115103

116104
project.afterEvaluate {
@@ -120,21 +108,105 @@ class PoEditorPlugin : Plugin<Project> {
120108
}
121109
}
122110

123-
for (configName in configsPoEditorExtensionContainer.names) {
124-
if (configName !in allPossibleConfigNames) {
125-
logger.warn("$TAG: " +
126-
"'$POEDITOR_CONFIG_NAME' object '$configName' " +
127-
"does not match a flavor or build type.")
111+
verifyAndLinkTasks(configsExtensionContainer,
112+
allPossibleConfigNames,
113+
configPoEditorTaskProvidersMap,
114+
project)
115+
}
116+
}
117+
118+
private fun applyInternalLib(project: Project,
119+
mainExtension: PoEditorPluginExtension) {
120+
// Add android.poEditorConfig extension container so we can set-up flavors and build types
121+
// configurations with Android library modules.
122+
val configsExtensionContainer = project.container<PoEditorPluginExtension>()
123+
val androidExtension = project.the<LibraryExtension>()
124+
(androidExtension as ExtensionAware).extensions.add(POEDITOR_CONFIG_NAME, configsExtensionContainer)
125+
126+
val configPoEditorTaskProvidersMap: MutableMap<ConfigName, TaskProvider<*>> = mutableMapOf()
127+
128+
// Add tasks for every build variant
129+
androidExtension.onVariants {
130+
val configs = getConfigs(this.productFlavors.map { it.second }, this.buildType)
131+
132+
generatePoEditorTasks(configs,
133+
project,
134+
configsExtensionContainer,
135+
mainExtension,
136+
configPoEditorTaskProvidersMap)
137+
}
138+
139+
project.afterEvaluate {
140+
val allPossibleConfigNames: Set<String> by lazy {
141+
androidExtension.libraryVariants.flatMapTo(mutableSetOf()) {
142+
listOf(it.buildType.name) + it.productFlavors.map { it.name }
128143
}
129144
}
130145

131-
logger.debug("$TAG: Configurations to add: $configPoEditorTaskProvidersMap")
146+
verifyAndLinkTasks(configsExtensionContainer,
147+
allPossibleConfigNames,
148+
configPoEditorTaskProvidersMap,
149+
project)
150+
}
151+
}
152+
153+
private fun getConfigs(productFlavors: List<String>,
154+
buildType: String?): Set<String> = (productFlavors + buildType).filterNotNull().toSet()
155+
156+
private fun generatePoEditorTasks(configs: Set<String>,
157+
project: Project,
158+
configsExtensionContainer: NamedDomainObjectContainer<PoEditorPluginExtension>,
159+
mainExtension: PoEditorPluginExtension,
160+
configPoEditorTaskProvidersMap: MutableMap<ConfigName, TaskProvider<*>>) {
161+
configs.forEach { configName ->
162+
val configTaskName = getPoEditorTaskName(configName)
163+
164+
// Only create the task if no other task is registered with the same name (would mean it's already
165+
// created.
166+
project.tasks.findByName(configTaskName) ?: run {
167+
val configResourceDirectory = getResourceDirectory(project, configName)
168+
val configExtension = buildExtensionForConfig(
169+
configName,
170+
configsExtensionContainer,
171+
mainExtension)
172+
173+
val newConfigPoEditorTask = if (configExtension != null) {
174+
project.registerNewTask<ImportPoEditorStringsTask>(
175+
getPoEditorTaskName(configName),
176+
getMainPoEditorDescription(),
177+
PLUGIN_GROUP,
178+
arrayOf(configExtension, configResourceDirectory))
179+
} else {
180+
project.registerNewTask<DummyImportPoEditorStringsTask>(
181+
getPoEditorTaskName(configName),
182+
getMainPoEditorDescription(),
183+
PLUGIN_GROUP,
184+
arrayOf(configName))
185+
}
186+
187+
configPoEditorTaskProvidersMap.put(configName, newConfigPoEditorTask)
188+
}
189+
}
190+
}
132191

133-
// Link all other tasks to main task so they also get executed when executing the main one
134-
configPoEditorTaskProvidersMap.values.forEach { task ->
135-
project.tasks.named(getPoEditorTaskName()) { dependsOn(task) }
192+
private fun verifyAndLinkTasks(configsExtensionContainer: NamedDomainObjectContainer<PoEditorPluginExtension>,
193+
allPossibleConfigNames: Set<String>,
194+
configPoEditorTaskProvidersMap: MutableMap<ConfigName, TaskProvider<*>>,
195+
project: Project) {
196+
for (configName in configsExtensionContainer.names) {
197+
if (configName !in allPossibleConfigNames) {
198+
logger.warn("$TAG: " +
199+
"'$POEDITOR_CONFIG_NAME' object '$configName' " +
200+
"does not match a flavor or build type.")
136201
}
137202
}
203+
204+
logger.debug("$TAG: Configurations to add: $configPoEditorTaskProvidersMap")
205+
206+
// Link all other tasks to main task so they also get executed when executing the main one
207+
configPoEditorTaskProvidersMap.values.forEach { task ->
208+
project.tasks.named(getPoEditorTaskName()) { dependsOn(task) }
209+
}
138210
}
139211

140212
private fun getPoEditorTaskName(configName: ConfigName = "") = "import${configName.capitalize()}PoEditorStrings"
@@ -149,4 +221,4 @@ class PoEditorPlugin : Plugin<Project> {
149221
private fun getPoEditorDescriptionForConfig(configName: ConfigName): String = """
150222
Imports all PoEditor strings for configuration $configName.
151223
""".trimIndent()
152-
}
224+
}

0 commit comments

Comments
 (0)