Skip to content

Commit

Permalink
Prepared resourcemanager to be distributed as gradle plugin.
Browse files Browse the repository at this point in the history
  • Loading branch information
vsnappy1 committed Nov 11, 2024
1 parent f72dedc commit 3bb1b95
Show file tree
Hide file tree
Showing 14 changed files with 831 additions and 0 deletions.
1 change: 1 addition & 0 deletions resourcemanager/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
42 changes: 42 additions & 0 deletions resourcemanager/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
plugins {
`kotlin-dsl`
java
id("com.gradle.plugin-publish") version "1.3.0"
}

dependencies {
implementation(gradleApi())
implementation(localGroovy())
}

group = "dev.randos"
version = "0.0.1"

gradlePlugin {
website.set("https://github.com/vsnappy1/ResourceManager")
vcsUrl.set("https://github.com/vsnappy1/ResourceManager")
plugins {
create("resourcemanager") {
id = "dev.randos.resourcemanager"
implementationClass = "ResourceManagerPlugin"
displayName = "Resource Manager"
description = "ResourceManager is an Android plugin that simplifies accessing Android resources (strings, colors, drawables, etc.) in both Android and non-Android components (e.g., ViewModel) using generated code."
tags.set(listOf("android", "androidResources", "codeGeneration"))
}
}
}

java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

kotlin {
jvmToolchain(8)
}

publishing {
repositories {
mavenLocal()
}
}
24 changes: 24 additions & 0 deletions resourcemanager/src/main/kotlin/ResourceManagerPlugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import dev.randos.resourcemanager.ResourceManagerGenerator
import org.gradle.api.Plugin
import org.gradle.api.Project
import java.io.File

class ResourceManagerPlugin : Plugin<Project> {
override fun apply(project: Project) {
val generatedFile = File(project.projectDir, "build/generated/resourcemanager/main/ResourceManager.kt")
val resourceManager = ResourceManagerGenerator(project.projectDir, generatedFile)

val generateResourceManagerTask = project.tasks.register("generateResourceManager") {
inputs.files(resourceManager.getFilesUnderObservation())
outputs.files(generatedFile)
doLast {
resourceManager.generate()
}
}

project.tasks.matching { it.name.startsWith("compile") }
.configureEach {
dependsOn(generateResourceManagerTask)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package dev.randos.resourcemanager

import java.io.File

import dev.randos.resourcemanager.model.Resource
import dev.randos.resourcemanager.model.ResourceType
import dev.randos.resourcemanager.model.ModuleDetails
import dev.randos.resourcemanager.manager.ModuleManager
import dev.randos.resourcemanager.file.generation.ClassFileGenerator

internal class ResourceManagerGenerator(
private val moduleFile: File,
private val generatedFile: File
) {

fun generate() {

val moduleManager = ModuleManager(moduleFile)
val resources = getResources(moduleFile, moduleManager.getModuleDependencies())

try {
// Create the new file with a dependency on all source files
generatedFile.parentFile.mkdirs()

// Write the generated class content to the file
generatedFile.bufferedWriter().use { out ->

val classFile = ClassFileGenerator.generateClassFile(
namespace = moduleManager.getNamespace()
?: throw IllegalStateException("Namespace could not be found in either build.gradle, build.gradle.kts or AndroidManifest.xml. Please ensure the module is properly configured."),
files = resources
)

out.write(classFile)
out.close()
}
} catch (e: Exception) {
println("Error: ${e.localizedMessage}")
e.printStackTrace()
}
}

fun getFilesUnderObservation(): List<File> {
val moduleManager = ModuleManager(moduleFile)
val resources = getResources(moduleFile, moduleManager.getModuleDependencies())
return resources.getFilesUnderObservation() + listOf(moduleManager.getBuildGradleFile()) // Also observe the module build.gradle file.
}

/**
* Scans the directory structure starting from the given file path to locate default resource file
* within an Android project's res/values directories.
*
* @return A list of [Resource].
*/
private fun getResources(
moduleFile: File,
moduleDependencies: List<String>
): List<Resource> {
val list = mutableListOf<Resource>()

var resFile = File(moduleFile, "src/main/res")

// Locate the "values" directory within the "res" directory.
list.add(
Resource(
type = ResourceType.VALUES,
moduleDetails = ModuleDetails(resDirectory = File(resFile, "values"))
)
)

// Locate the "drawable" directory within the "res" directory.
list.add(
Resource(
type = ResourceType.DRAWABLES,
moduleDetails = ModuleDetails(resDirectory = File(resFile, "drawable"))
)
)

/*
Also add resources for project dependencies. (i.e. implementation(project(":my_library")))
*/
val projectFile = moduleFile.parentFile
moduleDependencies.forEach { module ->
val dependencyModuleFile = File(projectFile, module)
resFile = File(dependencyModuleFile, "src/main/res")

ModuleManager(dependencyModuleFile).getNamespace()?.let { namespace ->
// Locate the "values" directory within the "res" directory.
list.add(
Resource(
type = ResourceType.VALUES,
moduleDetails = ModuleDetails(module, namespace, File(resFile, "values"))
)
)

// Locate the "drawable" directory within the "res" directory.
list.add(
Resource(
type = ResourceType.DRAWABLES,
moduleDetails = ModuleDetails(module, namespace, File(resFile, "drawable"))
)
)
}
}
return list
}

/**
* Generates a list of all files within the directories specified by each `Resource` object.
*
* @receiver List of `Resource` objects, each containing a directory path.
* @return A list of all files under each directory in the `Resource` list.
*/
private fun List<Resource>.getFilesUnderObservation(): List<File> {
val files = mutableListOf<File>()
this.map { it.moduleDetails.resDirectory }.forEach { directory ->
directory.walkTopDown().forEach { file ->
if (file.isFile) {
files.add(file)
}
}
}
return files
}
}
Loading

0 comments on commit 3bb1b95

Please sign in to comment.