<|start_filename|>localization-plugin/src/main/kotlin/co/thebeat/localization/tasks/DownloadLocalizationsTask.kt<|end_filename|>
package co.thebeat.localization.tasks

import co.thebeat.localization.extensions.TransifexLocalizationExtension
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.support.serviceOf
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkerExecutor
import java.io.File
import java.util.concurrent.TimeUnit
import javax.inject.Inject

@Suppress("UnstableApiUsage")
internal abstract class DownloadLocalizationsTask @Inject constructor(
        private val extension: TransifexLocalizationExtension
) : DefaultTask() {

    companion object {
        const val NAME = "fetchLocalization"
    }

    @TaskAction
    fun downloadLocalizations() {
        require(!extension.apiToken.get().isBlank()) {
            """
                An Auth token needs to be configured in order to use this plugin.
                ```
                transifexLocalization {
                    authToken = "<PASSWORD>"
                }
                ```
            """.trimIndent()
        }

        project.serviceOf<WorkerExecutor>()
                .noIsolation()
                .submit(DownloadTranslationsWorkAction::class.java) {
                    apiToken.set(extension.apiToken.get())
                    parentFolder.set(extension.srcDir.get())
                    projectSlug.set(extension.projectSlug.get())
                    resourceSlug.set(extension.resourceSlug.get())
                    localeMap.set(extension.localesMap.get())
                }
    }

    @Suppress("UnstableApiUsage")
    interface DownloadTranslationWorkParameters : WorkParameters {
        val apiToken: Property<String>
        val parentFolder: Property<String>
        val projectSlug: Property<String>
        val resourceSlug: Property<String>
        val localeMap: MapProperty<String, String>
    }

    @Suppress("UnstableApiUsage")
    abstract class DownloadTranslationsWorkAction : WorkAction<DownloadTranslationWorkParameters> {

        private val logger: Logger = Logging.getLogger(
                "TheBEAT:GradleLocalizationPlugin:${DownloadLocalizationsTask::class.java.simpleName}"
        )

        override fun execute() {
            val apiToken = "api:${parameters.apiToken.get()}"
            val localesMap = parameters.localeMap.get()
            val filesMap = mutableMapOf<String, String>()

            localesMap.forEach { (folder, locale) ->
                logger.debug("Will download pair of: $folder - $locale")

                val localeRequestUrl = buildTranslationRequestUrl(currentLocale = locale)

                logger.debug("Built request url: $localeRequestUrl")

                val process = ProcessBuilder(
                        "curl",
                        "-L",
                        "--user",
                        apiToken,
                        "-X",
                        "GET",
                        localeRequestUrl
                ).start()

                logger.debug("Process has started")

                process.inputStream.reader(Charsets.UTF_8).use {
                    val text = it.readText().trim()
                    // We need to use the 4-space indentation because the file is usually changed by humans
                    // That makes the git diff inspection easier
                    val content = text.replace(
                            """\n(\s+)((<string.+</string>)|<!--.+-->)""".toRegex(),
                            "\n    \$2"
                    )
                    filesMap[folder] = content
                }
                process.waitFor(10L, TimeUnit.SECONDS)
            }

            if (filesMap.size == localesMap.size) {
                localesMap.forEach { (folder, _) ->
                    val stringsFile = File("${parameters.parentFolder.get()}/$folder/strings.xml")
                    stringsFile.writeText(filesMap[folder].toString())
                }

                logger.debug("All translations downloaded")
            } else {
                throw GradleException("Error downloading strings.xml")
            }
        }

        private fun buildTranslationRequestUrl(currentLocale: String): String = "https://www.transifex.com/api/2/" +
                "project/" +
                "${parameters.projectSlug.get()}/" +
                "resource/" +
                "${parameters.resourceSlug.get()}/" +
                "translation/" +
                "$currentLocale?mode=default&file=xml"
    }
}


<|start_filename|>localization-plugin/src/main/kotlin/co/thebeat/localization/extensions/TransifexLocalizationExtension.kt<|end_filename|>
package co.thebeat.localization.extensions

import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal

@Suppress("UnstableApiUsage")
open class TransifexLocalizationExtension @JvmOverloads constructor(
        // Needed for Gradle
        @get:Internal
        internal val name: String = "default",
        objects: ObjectFactory
) {

    companion object {
        const val NAME = "transifexLocalization"
    }

    @get:Input
    val apiToken: Property<String> = objects.property(String::class.java)

    @get:Input
    val resourceSlug: Property<String> = objects.property(String::class.java)

    @get:Input
    val localesMap: MapProperty<String, String> = objects.mapProperty(String::class.java, String::class.java)

    @get:Input
    val srcDir: Property<String> = objects.property(String::class.java)

    @get:Input
    val projectSlug: Property<String> = objects.property(String::class.java)
}


<|start_filename|>test-consumer/settings.gradle.kts<|end_filename|>
includeBuild("../localization-plugin")


<|start_filename|>localization-plugin/src/main/kotlin/co/thebeat/localization/DownloadLocalizationsPlugin.kt<|end_filename|>
package co.thebeat.localization

import co.thebeat.localization.extensions.TransifexLocalizationExtension
import co.thebeat.localization.tasks.DownloadLocalizationsTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.create

/**
 * Created by <NAME> on 17/07/2018.
 */
open class DownloadLocalizationsPlugin : Plugin<Project> {

    override fun apply(project: Project) {
        val transifexExt = project
                .extensions
                .create<TransifexLocalizationExtension>(TransifexLocalizationExtension.NAME)
        project.tasks.register(DownloadLocalizationsTask.NAME, DownloadLocalizationsTask::class.java, transifexExt)
    }
}


<|start_filename|>localization-plugin/settings.gradle.kts<|end_filename|>
rootProject.name = "localization-plugin"



<|start_filename|>localization-plugin/build.gradle.kts<|end_filename|>
val kotlinVersion: String by extra { "1.3.61" }
val junitVersion: String by extra { "5.5.1" }

plugins {
    `kotlin-dsl`
    id("com.gradle.plugin-publish") version "0.11.0"
    kotlin("jvm") version "1.3.61"
}

repositories {
    google()
    mavenCentral()
    jcenter()
}

group = "co.thebeat.localization"
version = "0.4.1"

dependencies {
    implementation(gradleApi())
    implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")

    testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion")
}

gradlePlugin {
    plugins {
        create("downloadLocalizationsPlugin") {
            id = "co.thebeat.localization"
            displayName = "Download localization files plugin"
            description = "Interact with localization providers (such as Transifex) and automate downloading " +
                    "localized files (such as string.xml for android applications)."
            implementationClass = "co.thebeat.localization.DownloadLocalizationsPlugin"
        }
    }
}

pluginBundle {
    website = "https://github.com/beatlabs/gradle-localization-plugin"
    vcsUrl = "https://github.com/beatlabs/gradle-localization-plugin"
    tags = listOf("localization", "transifex", "android")
}


<|start_filename|>test-consumer/build.gradle.kts<|end_filename|>
plugins {
    id("co.thebeat.localization") version "0.4.1"
}

val transifexAPIToken: String? by project
val transifexResourceSlug: String? by project
val transifexProjectSlug: String? by project

configure<co.thebeat.localization.extensions.TransifexLocalizationExtension> {
    apiToken.set(transifexAPIToken ?: "")
    resourceSlug.set(transifexResourceSlug ?: "")
    projectSlug.set(transifexProjectSlug ?: "")
    localesMap.set(
            mapOf(
                "main/res/localization_en" to "en",
                "main/res/localization_gr" to "el_GR"
            )
    )
    srcDir.set("$projectDir/src")
}
