/*
* Copyright (C) 2020 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
plugins {
id 'org.jetbrains.kotlin.jvm'
id 'java-gradle-plugin'
id 'maven-publish'
id 'com.github.johnrengelman.shadow'
}
configurations {
// Config for dependencies that will be shadowed / jarjared
shadowed
// Make all shadowed dependencies be compileOnly dependencies to not affect
// main compilation / configuration
compileOnly.extendsFrom(shadowed)
// Make all shadowed dependencies be included in the plugin test classpath
// since they are compileOnly in the main configuration
testPluginCompile.extendsFrom(shadowed)
// Config for plugin classpath to be used during tests
testPluginCompile {
canBeConsumed = false
canBeResolved = true
}
}
// Renames default jar to avoid using it in publications.
jar {
archiveClassifier = "before-jarjar"
}
shadowJar {
archiveClassifier = ""
configurations = [project.configurations.shadowed]
dependencies {
// Don't jarjar stdlib deps that are automatically added by Kotlin plugin
exclude(dependency("org.jetbrains.kotlin::"))
exclude(dependency("org.jetbrains:annotations:"))
}
doLast {
outputs.files.each { jarFile ->
checkJarFile(jarFile, 'dagger', 'META-INF')
}
}
}
dependencies {
shadowed project(':agp-wrapper-impl')
shadowed fileTree(dir: 'libs', include: '*.jar')
implementation gradleApi()
compileOnly "com.android.tools.build:gradle:$agp_version"
compileOnly "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
compileOnly "com.google.devtools.ksp:symbol-processing-gradle-plugin:$ksp_version"
implementation 'org.ow2.asm:asm:9.6'
implementation "com.squareup:javapoet:1.13.0"
testImplementation gradleTestKit()
testImplementation 'junit:junit:4.12'
testImplementation 'com.google.truth:truth:1.0.1'
testImplementation 'org.javassist:javassist:3.26.0-GA'
testPluginCompile "com.android.tools.build:gradle:$agp_version"
testPluginCompile "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
testPluginCompile "com.google.devtools.ksp:symbol-processing-gradle-plugin:$ksp_version"
}
// Configure the generating task of plugin-under-test-metadata.properties to
// include additional dependencies for the injected plugin classpath that
// are not present in the main runtime dependencies. This allows us to test
// the desired AGP version while keeping a compileOnly dep on the main source.
tasks.withType(PluginUnderTestMetadata.class).named("pluginUnderTestMetadata").configure {
it.pluginClasspath.from(configurations.testPluginCompile)
}
compileKotlin {
kotlinOptions {
allWarningsAsErrors = true
freeCompilerArgs += [ "-opt-in=kotlin.ExperimentalStdlibApi" ]
jvmTarget = 11
}
}
// Imports a shared library from the main project. The library and its classes
// will be shadowed in the plugin's artifact.
tasks.register("importSharedLib").configure {
def outputDir = file("${project.projectDir}/libs")
outputs.dir(outputDir)
doLast {
def buildCmd = 'bazel'
def buildDir = 'bazel-bin'
def findGenFilesParent
findGenFilesParent = { File dir ->
if (dir == null || !dir.isDirectory()) {
return null
}
if (new File(dir, buildDir).exists()) {
return dir
} else {
return findGenFilesParent(dir.parentFile)
}
}
// Build shared lib
def bazelOutput = new ByteArrayOutputStream()
def buildResult = exec {
commandLine buildCmd, 'build', 'import-shared-lib'
standardOutput = bazelOutput
errorOutput = bazelOutput
}
buildResult.assertNormalExitValue()
// Find shared lib Jar in build directory.
def genFilesDir = findGenFilesParent(project.buildFile.parentFile)
if (genFilesDir == null) {
throw new GradleException("Couldn't find build folder '$buildDir'")
}
def libPath = bazelOutput.toString().split('\n')
.find { line -> line.contains("$buildDir/") }.trim()
def inputFile = file("$genFilesDir/$libPath")
def outputFile = file("$outputDir/${inputFile.name}")
outputFile << inputFile.newInputStream()
}
}
tasks.getByName('compileKotlin').dependsOn('importSharedLib')
// Task that generates a top-level property containing the version of the
// project so that it can be used in code and at runtime.
def pluginVersionOutDir = file("$buildDir/generated/source/plugin-version/")
tasks.register("generatePluginVersionSource").configure {
def version = getPublishVersion()
inputs.property('version', version)
outputs.dir(pluginVersionOutDir)
doLast {
def versionFile =
file("$pluginVersionOutDir/dagger/hilt/android/plugin/Version.kt")
versionFile.parentFile.mkdirs()
versionFile.text = """
// Generated file. Do not edit!
package dagger.hilt.android.plugin
val HILT_VERSION = "${version}"
""".stripIndent()
}
}
sourceSets.main.java.srcDir pluginVersionOutDir
tasks.getByName('compileKotlin').dependsOn('generatePluginVersionSource')
// Create sources Jar from main kotlin sources
tasks.register("sourcesJar", Jar).configure {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Assembles sources JAR"
archiveClassifier.set("sources")
from(sourceSets["main"].allSource)
dependsOn('generatePluginVersionSource')
}
// Create javadoc Jar. The jar is empty since we don't really have docs
// for this plugin but this is required to upload to Sonatype.
// https://central.sonatype.org/pages/requirements.html#supply-javadoc-and-sources
tasks.register("javadocJar", Jar).configure {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Assembles javadoc JAR"
archiveClassifier.set("javadoc")
}
// Disable Gradle metadata publication.
tasks.withType(GenerateModuleMetadata) {
enabled = false
}
// TODO(danysantiago): Use POM template in tools/ to avoid duplicating lines.
publishing {
publications {
plugin(MavenPublication) {
artifactId = pluginArtifactId
version = getPublishVersion()
from components.kotlin
artifact(shadowJar)
artifact(sourcesJar)
artifact(javadocJar)
pom {
addPomTemplate(owner)
}
}
// https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_markers
pluginMarker(MavenPublication) {
groupId = pluginId
artifactId = "${pluginId}.gradle.plugin"
version = getPublishVersion()
pom {
addPomTemplate(owner)
withXml {
def dependencyNode =
asNode().appendNode("dependencies").appendNode("dependency")
dependencyNode.appendNode("groupId", group)
dependencyNode.appendNode("artifactId", pluginArtifactId)
dependencyNode.appendNode("version", getPublishVersion())
}
}
}
}
// Publish to build output repository.
repositories {
maven {
url = uri("$buildDir/repo")
}
}
}
group = 'com.google.dagger'
// TODO(danysantiago): Use POM template in tools/ to avoid duplicating lines.
def addPomTemplate(pom) {
pom.name = 'Hilt Android Gradle Plugin'
pom.description = 'A fast dependency injector for Android and Java.'
pom.url = 'https://github.com/google/dagger'
pom.scm {
url = 'https://github.com/google/dagger/'
connection = 'scm:git:git://github.com/google/dagger.git'
developerConnection = 'scm:git:ssh://git@github.com/google/dagger.git'
tag = 'HEAD'
}
pom.issueManagement {
system = 'GitHub Issues'
url = 'https://github.com/google/dagger/issues'
}
pom.licenses {
license {
name = 'Apache 2.0'
url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
pom.organization {
name = 'Google, Inc.'
url = 'https://www.google.com'
}
pom.withXml {
def projectNode = asNode()
// Adds:
//
// org.sonatype.oss
// oss-parent
// 7
//
def parentNode = projectNode.appendNode('parent')
parentNode.appendNode('groupId', 'org.sonatype.oss')
parentNode.appendNode('artifactId', 'oss-parent')
parentNode.appendNode('version', '7')
// Adds scm->tag because for some reason the DSL API does not.
//
// HEAD
//
projectNode.get('scm').first().appendNode('tag', 'HEAD')
}
}
def getPublishVersion() {
def publishVersion = findProperty("PublishVersion")
return (publishVersion != null) ? publishVersion : "LOCAL-SNAPSHOT"
}
def checkJarFile(File jarFile, String... allowedPrefixes) {
def zip = new ZipFile(jarFile)
try {
Enumeration list = zip.entries()
while (list.hasMoreElements()) {
String entry = list.nextElement().name
if (!allowedPrefixes.any { entry.startsWith(it) }) {
throw new GradleException(
"Found a file that is not in " +
"${ allowedPrefixes.collect { "'$it'" }.join('/') }: $entry")
}
}
} finally {
zip.close()
}
}