All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.objectbox.gradle.transform.ObjectBoxAndroidTransform.kt Maven / Gradle / Ivy

/*
 * Copyright (C) 2017-2018 ObjectBox Ltd.
 *
 * This file is part of ObjectBox Build Tools.
 *
 * ObjectBox Build Tools is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * ObjectBox Build Tools is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ObjectBox Build Tools.  If not, see .
 */

package io.objectbox.gradle.transform

import com.android.build.api.transform.Format
import com.android.build.api.transform.QualifiedContent
import com.android.build.api.transform.Transform
import com.android.build.api.transform.TransformInvocation
import io.objectbox.logging.log
import io.objectbox.reporting.BasicBuildTracker
import org.gradle.api.provider.Property
import java.io.File

/**
 * A byte-code [Transform] to be registered with the Android plugin to run before dexing (regular builds or instrumented
 * unit test builds). The transform results are stored in a directory assigned to this Transform.
 * To also support transformation for local unit test builds the registration code injects custom transform tasks
 * for each build variant with unit tests. They run an [ObjectBoxJavaTransform] before unit test code is compiled.
 *
 * @see ClassTransformer
 */
class ObjectBoxAndroidTransform(private val debug: Property) : Transform() {

    override fun getName(): String {
        return "ObjectBoxAndroidTransform"
    }

    override fun getInputTypes(): MutableSet {
        return mutableSetOf(QualifiedContent.DefaultContentType.CLASSES)
    }

    override fun getScopes(): MutableSet {
        return mutableSetOf(QualifiedContent.Scope.PROJECT)
    }

    override fun isIncremental(): Boolean {
        return false
    }

    override fun transform(info: TransformInvocation) {
        super.transform(info)
        val debug = debug.get()
        try {
            val probedClasses = mutableListOf()

            val classProber = ClassProber()
            info.inputs.forEach { transformInput ->
                // Look through directory inputs to transform or just copy.
                transformInput.directoryInputs.forEach { directoryInput ->
                    if (debug) log("Input directory: ${directoryInput.name} ${directoryInput.file}")
                    // Output files to directory unique for this input directory.
                    val outDir = info.outputProvider.getContentLocation(
                        directoryInput.name,
                        outputTypes,
                        scopes,
                        Format.DIRECTORY
                    )
                    if (debug) log("Output directory: $outDir")

                    // TODO incremental: directoryInput.changedFiles

                    var classes = 0
                    var copied = 0
                    directoryInput.file.walk().filter { it.isFile }.forEach { file ->
                        if (file.name.endsWith(".class")) {
                            probedClasses += classProber.probeClass(file, outDir)
                            classes += 1
                        } else {
                            val relativePath = file.toRelativeString(directoryInput.file)
                            val destFile = File(outDir, relativePath)
                            file.copyTo(destFile, overwrite = true)
                            copied += 1
                        }
                    }
                    if (debug) log("Copied $copied files, will check $classes classes if transform required.")
                }

                // Not looking at class files in JARs, just copy them.
                // It appears only Android Gradle Plugin 3.6.0 uses this to pass the R classes in a JAR.
                // https://github.com/objectbox/objectbox-java/issues/817
                transformInput.jarInputs.forEach { jarInput ->
                    if (debug) log("Input JAR: ${jarInput.name} ${jarInput.file}")
                    // Note: TransformOutputProvider.getContentLocation(name, ...) returns the same file if all params
                    // match. Make sure name differs for each JAR to avoid overwriting an already copied JAR.
                    val outFileJar =
                        info.outputProvider.getContentLocation(jarInput.name, outputTypes, scopes, Format.JAR)
                    jarInput.file.copyTo(outFileJar, overwrite = true)
                    if (debug) log("Output JAR: $outFileJar")
                }
            }

            ClassTransformer(debug).transformOrCopyClasses(probedClasses)

        } catch (e: Throwable) {
            val buildTracker = BasicBuildTracker("Transformer")
            if (e is TransformException) buildTracker.trackError("Transform failed", e)
            else buildTracker.trackFatal("Transform failed", e)
            throw e
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy