From cf5aeb0996df552c038b04333ffc52df6a1bd84a Mon Sep 17 00:00:00 2001 From: Aleksey Mikhailov Date: Mon, 4 May 2020 09:44:49 +0700 Subject: [PATCH] #44 add FilesGenerator --- .../gradle/MultiplatformResourcesPlugin.kt | 4 +- .../gradle/generator/FilesGenerator.kt | 96 +++++++++++++++++++ .../android/AndroidFilesGenerator.kt | 49 ++++++++++ .../generator/common/CommonFilesGenerator.kt | 23 +++++ .../gradle/generator/ios/IosFilesGenerator.kt | 40 ++++++++ .../icerock/moko/resources/FileResource.kt | 20 ++-- .../icerock/moko/resources/FileResource.kt | 4 +- .../icerock/moko/resources/FileResource.kt | 4 +- .../moko/resources/ReadFileTextException.kt | 14 +++ 9 files changed, 241 insertions(+), 13 deletions(-) create mode 100644 gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/FilesGenerator.kt create mode 100644 gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/android/AndroidFilesGenerator.kt create mode 100644 gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/common/CommonFilesGenerator.kt create mode 100644 gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/ios/IosFilesGenerator.kt create mode 100644 resources/src/iosMain/kotlin/dev/icerock/moko/resources/ReadFileTextException.kt diff --git a/gradle-plugin/src/main/kotlin/dev/icerock/gradle/MultiplatformResourcesPlugin.kt b/gradle-plugin/src/main/kotlin/dev/icerock/gradle/MultiplatformResourcesPlugin.kt index e3df7b59..e11d80b5 100644 --- a/gradle-plugin/src/main/kotlin/dev/icerock/gradle/MultiplatformResourcesPlugin.kt +++ b/gradle-plugin/src/main/kotlin/dev/icerock/gradle/MultiplatformResourcesPlugin.kt @@ -7,6 +7,7 @@ package dev.icerock.gradle import com.android.build.gradle.LibraryExtension import com.android.build.gradle.LibraryPlugin import com.android.build.gradle.api.AndroidSourceSet +import dev.icerock.gradle.generator.FilesGenerator import dev.icerock.gradle.generator.FontsGenerator import dev.icerock.gradle.generator.GenerateMultiplatformResourcesTask import dev.icerock.gradle.generator.ImagesGenerator @@ -85,7 +86,8 @@ class MultiplatformResourcesPlugin : Plugin { StringsGenerator.Feature(sourceInfo, iosLocalizationRegion), PluralsGenerator.Feature(sourceInfo, iosLocalizationRegion), ImagesGenerator.Feature(sourceInfo), - FontsGenerator.Feature(sourceInfo) + FontsGenerator.Feature(sourceInfo), + FilesGenerator.Feature(sourceInfo) ) val targets: List = multiplatformExtension.targets.toList() diff --git a/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/FilesGenerator.kt b/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/FilesGenerator.kt new file mode 100644 index 00000000..ebb66f80 --- /dev/null +++ b/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/FilesGenerator.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +package dev.icerock.gradle.generator + +import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.KModifier +import com.squareup.kotlinpoet.PropertySpec +import com.squareup.kotlinpoet.TypeSpec +import dev.icerock.gradle.generator.android.AndroidFilesGenerator +import dev.icerock.gradle.generator.common.CommonFilesGenerator +import dev.icerock.gradle.generator.ios.IosFilesGenerator +import org.gradle.api.file.FileTree +import java.io.File + +abstract class FilesGenerator( + private val inputFileTree: FileTree +) : MRGenerator.Generator { + + private val resourceClass = ClassName("dev.icerock.moko.resources", "FileResource") + + override fun generate(resourcesGenerationDir: File): TypeSpec { + val fileSpecs = inputFileTree.map { file -> + FileSpec( + key = file.nameWithoutExtension, + file = file + ) + }.sortedBy { it.key } + val typeSpec = createTypeSpec(fileSpecs.map { it.key }) + generateResources(resourcesGenerationDir, fileSpecs) + return typeSpec + } + + private fun createTypeSpec(keys: List): TypeSpec { + val classBuilder = TypeSpec.objectBuilder("files") + @Suppress("SpreadOperator") + classBuilder.addModifiers(*getClassModifiers()) + + keys.forEach { classBuilder.addProperty(generateFileProperty(fileName = it)) } + return classBuilder.build() + } + + override fun getImports(): List = emptyList() + + private fun generateFileProperty( + fileName: String + ): PropertySpec { + @Suppress("SpreadOperator") + return PropertySpec.builder(fileName, resourceClass) + .addModifiers(*getPropertyModifiers()) + .apply { + getPropertyInitializer(fileName)?.let { initializer(it) } + } + .build() + } + + protected open fun generateResources( + resourcesGenerationDir: File, + files: List + ) { + } + + abstract fun getClassModifiers(): Array + + abstract fun getPropertyModifiers(): Array + + abstract fun getPropertyInitializer(fileName: String): CodeBlock? + + data class FileSpec( + val key: String, + val file: File + ) + + class Feature(private val info: SourceInfo) : ResourceGeneratorFeature { + private val fileTree = info.commonResources.matching { + include("MR/files/**") + } + + override fun createCommonGenerator(): FilesGenerator { + return CommonFilesGenerator(fileTree) + } + + override fun createIosGenerator(): FilesGenerator { + return IosFilesGenerator(fileTree) + } + + override fun createAndroidGenerator(): FilesGenerator { + return AndroidFilesGenerator( + fileTree, + info.androidRClassPackage + ) + } + } +} diff --git a/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/android/AndroidFilesGenerator.kt b/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/android/AndroidFilesGenerator.kt new file mode 100644 index 00000000..bbff1984 --- /dev/null +++ b/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/android/AndroidFilesGenerator.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +package dev.icerock.gradle.generator.android + +import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.KModifier +import dev.icerock.gradle.generator.FilesGenerator +import org.gradle.api.file.FileTree +import java.io.File +import java.util.Locale + +class AndroidFilesGenerator( + inputFileTree: FileTree, + private val androidRClassPackage: String +) : FilesGenerator( + inputFileTree = inputFileTree +) { + override fun getClassModifiers(): Array = arrayOf(KModifier.ACTUAL) + + override fun getPropertyModifiers(): Array = arrayOf(KModifier.ACTUAL) + + override fun getPropertyInitializer(fileName: String): CodeBlock? { + return CodeBlock.of("FileResource(rawResId = R.raw.%L)", keyToResourceId(fileName)) + } + + override fun getImports(): List = listOf( + ClassName(androidRClassPackage, "R") + ) + + override fun generateResources( + resourcesGenerationDir: File, + files: List + ) { + val targetDir = File(resourcesGenerationDir, "raw") + targetDir.mkdirs() + + files.forEach { (key, file) -> + val fileName = keyToResourceId(key) + "." + file.extension + file.copyTo(File(targetDir, fileName)) + } + } + + private fun keyToResourceId(key: String): String { + return key.replace("-", "_").toLowerCase(Locale.ROOT) + } +} diff --git a/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/common/CommonFilesGenerator.kt b/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/common/CommonFilesGenerator.kt new file mode 100644 index 00000000..1b72e365 --- /dev/null +++ b/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/common/CommonFilesGenerator.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +package dev.icerock.gradle.generator.common + +import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.KModifier +import dev.icerock.gradle.generator.FilesGenerator +import dev.icerock.gradle.generator.FontsGenerator +import org.gradle.api.file.FileTree + +class CommonFilesGenerator( + inputFileTree: FileTree +) : FilesGenerator( + inputFileTree = inputFileTree +) { + override fun getClassModifiers(): Array = emptyArray() + + override fun getPropertyModifiers(): Array = emptyArray() + + override fun getPropertyInitializer(fileName: String): CodeBlock? = null +} diff --git a/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/ios/IosFilesGenerator.kt b/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/ios/IosFilesGenerator.kt new file mode 100644 index 00000000..2b32aecb --- /dev/null +++ b/gradle-plugin/src/main/kotlin/dev/icerock/gradle/generator/ios/IosFilesGenerator.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +package dev.icerock.gradle.generator.ios + +import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.KModifier +import dev.icerock.gradle.generator.FilesGenerator +import org.gradle.api.file.FileTree +import java.io.File + +class IosFilesGenerator( + inputFileTree: FileTree +) : FilesGenerator( + inputFileTree = inputFileTree +) { + override fun getClassModifiers(): Array = arrayOf(KModifier.ACTUAL) + + override fun getPropertyModifiers(): Array = arrayOf(KModifier.ACTUAL) + + override fun getPropertyInitializer(fileName: String): CodeBlock? { + return CodeBlock.of( + "FileResource(fileName = %S, bundle = ${IosMRGenerator.BUNDLE_PROPERTY_NAME})", + fileName + ) + } + + override fun generateResources( + resourcesGenerationDir: File, + files: List + ) { + val targetDir = File(resourcesGenerationDir, "files") + targetDir.mkdirs() + + files.forEach { (_, file) -> + file.copyTo(File(targetDir, file.name)) + } + } +} diff --git a/resources/src/androidMain/kotlin/dev/icerock/moko/resources/FileResource.kt b/resources/src/androidMain/kotlin/dev/icerock/moko/resources/FileResource.kt index edb50117..8c473bc2 100644 --- a/resources/src/androidMain/kotlin/dev/icerock/moko/resources/FileResource.kt +++ b/resources/src/androidMain/kotlin/dev/icerock/moko/resources/FileResource.kt @@ -4,15 +4,21 @@ package dev.icerock.moko.resources -import java.io.File -import java.net.URI +import android.content.Context +import android.content.res.Resources +import androidx.annotation.RawRes +import java.io.BufferedReader +import java.io.InputStream +import java.io.InputStreamReader actual class FileResource( - val assetsPath: String + @RawRes + val rawResId: Int ) { - actual fun readText(): String { - val assetUri: URI = URI.create("file:///android_asset/$assetsPath") - val file: File = File(assetUri) - return file.readText() + fun readText(context: Context): String { + val resources: Resources = context.resources + val inputStream: InputStream = resources.openRawResource(rawResId) + val bufferedReader = BufferedReader(InputStreamReader(inputStream)) + return bufferedReader.readText() } } diff --git a/resources/src/commonMain/kotlin/dev/icerock/moko/resources/FileResource.kt b/resources/src/commonMain/kotlin/dev/icerock/moko/resources/FileResource.kt index 66714df2..709b3653 100644 --- a/resources/src/commonMain/kotlin/dev/icerock/moko/resources/FileResource.kt +++ b/resources/src/commonMain/kotlin/dev/icerock/moko/resources/FileResource.kt @@ -4,6 +4,4 @@ package dev.icerock.moko.resources -expect class FileResource { - fun readText(): String -} +expect class FileResource diff --git a/resources/src/iosMain/kotlin/dev/icerock/moko/resources/FileResource.kt b/resources/src/iosMain/kotlin/dev/icerock/moko/resources/FileResource.kt index f4e3895f..36b57dc3 100644 --- a/resources/src/iosMain/kotlin/dev/icerock/moko/resources/FileResource.kt +++ b/resources/src/iosMain/kotlin/dev/icerock/moko/resources/FileResource.kt @@ -23,7 +23,7 @@ actual class FileResource( val path: String get() = bundle.pathForResource(name = fileName, ofType = null, inDirectory = "files")!! val url: NSURL get() = bundle.URLForResource(name = fileName, withExtension = null, subdirectory = "files")!! - actual fun readText(): String { + fun readText(): String { val (result: String?, error: NSError?) = memScoped { val p = alloc>() val result: String? = runCatching { @@ -36,7 +36,7 @@ actual class FileResource( result to p.value } - if (error != null) throw RuntimeException(error.localizedDescription) + if (error != null) throw ReadFileTextException(fileResource = this, error = error) else return result!! } } diff --git a/resources/src/iosMain/kotlin/dev/icerock/moko/resources/ReadFileTextException.kt b/resources/src/iosMain/kotlin/dev/icerock/moko/resources/ReadFileTextException.kt new file mode 100644 index 00000000..6c31e66b --- /dev/null +++ b/resources/src/iosMain/kotlin/dev/icerock/moko/resources/ReadFileTextException.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +package dev.icerock.moko.resources + +import platform.Foundation.NSError + +class ReadFileTextException( + val fileResource: FileResource, + val info: String +) : Exception("can't read file $fileResource text ($info)") { + constructor(fileResource: FileResource, error: NSError) : this(fileResource, error.localizedDescription) +}