Skip to content

Commit

Permalink
Build native executable artifacts (#87)
Browse files Browse the repository at this point in the history
* build and publish native artifacts #6

* update tests to use native artifact

* bugfix for plugin working directory resolution

* update build to resolve plugin config relatively

* bump project version
  • Loading branch information
marcoferrer authored Nov 19, 2019
1 parent b978f5f commit 7fef300
Show file tree
Hide file tree
Showing 11 changed files with 163 additions and 60 deletions.
24 changes: 22 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ subprojects{ subproject ->
apply plugin: 'kotlin'

group = 'com.github.marcoferrer.krotoplus'
version = '0.5.0'
version = '0.6.0-SNAPSHOT'

compileKotlin {
kotlinOptions.jvmTarget = "1.8"
Expand All @@ -54,7 +54,6 @@ subprojects{ subproject ->
testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
}


tasks.withType(Test) {
testLogging {
// set options for log level LIFECYCLE
Expand Down Expand Up @@ -99,4 +98,25 @@ subprojects{ subproject ->
}
}
}

subproject.ext{
localPluginPath = [
"kroto": "${rootProject.projectDir}/protoc-gen-kroto-plus/build/libs/protoc-gen-kroto-plus-${project.version}-${osdetector.classifier}.exe",
"coroutines": "${rootProject.projectDir}/protoc-gen-grpc-coroutines/build/libs/protoc-gen-grpc-coroutines-${project.version}-${osdetector.classifier}.exe"
]

configProtoTaskWithKroto = { task, krotoConfig ->
task.inputs.files krotoConfig
task.dependsOn ':protoc-gen-kroto-plus:buildCanteenArtifacts'
task.plugins {
kroto {
outputSubDir = "java"
// We want to relativize the configuration path
// because absolute paths cause issues in windows
// environments
option "ConfigPath=${krotoConfig.absolutePath.replace(rootProject.projectDir.path, "").drop(1)}"
}
}
}
}
}
6 changes: 5 additions & 1 deletion buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ plugins {
repositories {
jcenter()
}


dependencies {
// Needed by the script 'canteen.gradle'
implementation("com.google.guava:guava:27.0.1-jre")
}
81 changes: 81 additions & 0 deletions canteen.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// The following dependency needs to exist on the 'buildscript' classpath
// 'com.google.guava:guava:27.0.1-jre'
// It is currently added via the buildSrc project
import com.google.common.io.ByteStreams

// Native artifact generation based off of
// https:/salesforce/grpc-java-contrib/tree/master/canteen

def platforms = ["osx-x86_64", "linux-x86_64", "windows-x86_64"]

Task bootJarTask = tasks.getByName("bootJar")
File bootJarFile = bootJarTask.archiveFile.get().asFile

platforms.each { platform ->

// Resolve the canteen bootstrap artifact
Configuration config = project.configurations.create("canteenBootstrapLocator_$platform") {
visible = false
transitive = false
extendsFrom = []
}
Map<String, String> notation = [
group: "com.salesforce.servicelibs",
name: "canteen-bootstrap",
version: "1.0.0",
classifier: platform,
ext: "exe",
]
Dependency dep = project.dependencies.add(config.name, notation)
File bootstrapFile = config.fileCollection(dep).singleFile
File destinationArtifactFile = new File(bootJarTask.destinationDirectory.get().asFile,
bootJarFile.name.replace("jvm8.jar", platform + ".exe"))

// Create task to copy the original jar and embed the
// canteen bootstrap executable for the target platform
Task canteenTask = task("canteenArtifact_$platform"){
group = "canteen"
dependsOn("bootJar")
// Add files for UP-TO-DATE checks
inputs.files(bootJarFile)
outputs.files(destinationArtifactFile)
doLast {
// Build the bootstrap file
OutputStream targetStream = new FileOutputStream(destinationArtifactFile)
InputStream bootstrapStream = new FileInputStream(bootstrapFile)
ByteStreams.copy(bootstrapStream, targetStream);
InputStream sourceStream = new FileInputStream(bootJarFile)
ByteStreams.copy(sourceStream, targetStream);
targetStream.flush()
targetStream.close()
sourceStream.close()
bootstrapStream.close()
destinationArtifactFile.setExecutable(true);
}
}

artifacts {
archives(destinationArtifactFile) {
builtBy canteenTask
classifier platform
}
}

publishing {
publications {
mavenPublication(MavenPublication) {
artifact(destinationArtifactFile.absolutePath) {
builtBy canteenTask
classifier platform
}
}
}
}
}

task buildCanteenArtifacts{
group = "canteen"
platforms.each { platform ->
dependsOn("canteenArtifact_$platform")
}
}
4 changes: 2 additions & 2 deletions example-project/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
"grpc": '1.23.0',
"kotlin": '1.3.50',
"coroutines": '1.3.0',
"krotoplus": '0.5.0'
"krotoplus": '0.6.0-SNAPSHOT'
]
}

Expand Down Expand Up @@ -89,7 +89,7 @@ protobuf {
plugins {
grpc { artifact = "io.grpc:protoc-gen-grpc-java:${versions.grpc}" }
kroto {
artifact = "com.github.marcoferrer.krotoplus:protoc-gen-kroto-plus:${versions.krotoplus}:jvm8@jar"
artifact = "com.github.marcoferrer.krotoplus:protoc-gen-kroto-plus:${versions.krotoplus}"
}
}

Expand Down
11 changes: 2 additions & 9 deletions kroto-plus-coroutines/benchmark/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,18 @@ protobuf {
//noinspection GroovyAssignabilityCheck
plugins {
kroto {
path = "${rootProject.projectDir}/protoc-gen-kroto-plus/build/libs/protoc-gen-kroto-plus-${project.version}-jvm8.jar"
path = localPluginPath.kroto
}
}

generateProtoTasks {
def krotoConfig = file("krotoPlusConfig.asciipb")

all().each{ task ->
task.inputs.files krotoConfig
task.dependsOn ':protoc-gen-kroto-plus:bootJar'

configProtoTaskWithKroto(task, krotoConfig)
task.builtins {
remove java
}
task.plugins {
kroto {
option "ConfigPath=$krotoConfig"
}
}
}
}
}
5 changes: 2 additions & 3 deletions kroto-plus-coroutines/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,13 @@ protobuf {
//noinspection GroovyAssignabilityCheck
plugins {
coroutines {
path = "${rootProject.projectDir}/protoc-gen-grpc-coroutines/build/libs/protoc-gen-grpc-coroutines-${project.version}-jvm8.jar"
path = localPluginPath.coroutines
}
}

generateProtoTasks {

all().each{ task ->
task.dependsOn ':protoc-gen-grpc-coroutines:bootJar'
task.dependsOn ':protoc-gen-grpc-coroutines:buildCanteenArtifacts'
task.builtins {
remove java
}
Expand Down
7 changes: 3 additions & 4 deletions kroto-plus-gradle-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,19 @@ protobuf {
//noinspection GroovyAssignabilityCheck
plugins {
kroto {
artifact = "com.github.marcoferrer.krotoplus:protoc-gen-kroto-plus:0.1.3:jvm8@jar"
path = localPluginPath.kroto
}
}

generateProtoTasks {
def krotoConfig = file("krotoPlusConfig.asciipb")

all().each{ task ->
all().each { task ->
task.inputs.files krotoConfig
task.dependsOn ':kroto-plus-gradle-plugin:gen-config-dsl:jar'
task.dependsOn ':protoc-gen-kroto-plus:buildCanteenArtifacts'
task.plugins {
kroto {
outputSubDir = "java"
option "ConfigPath=$krotoConfig"
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions protoc-gen-grpc-coroutines/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ bootJar {
}
}

apply from: "${rootProject.projectDir}/canteen.gradle"

jar.enabled = true

artifacts {
Expand Down
2 changes: 2 additions & 0 deletions protoc-gen-kroto-plus/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ bootJar {
}
}

apply from: "${rootProject.projectDir}/canteen.gradle"

jar.enabled = true

artifacts {
Expand Down
12 changes: 2 additions & 10 deletions protoc-gen-kroto-plus/generator-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,15 @@ protobuf {
//noinspection GroovyAssignabilityCheck
plugins {
kroto {
path = "${rootProject.projectDir}/protoc-gen-kroto-plus/build/libs/protoc-gen-kroto-plus-${project.version}-jvm8.jar"
path = localPluginPath.kroto
}
}

generateProtoTasks {
def krotoConfig = file("krotoPlusConfig.asciipb")

all().each{ task ->
task.inputs.files krotoConfig
task.dependsOn ':protoc-gen-kroto-plus:bootJar'

task.plugins {
kroto {
outputSubDir = "java"
option "ConfigPath=$krotoConfig"
}
}
configProtoTaskWithKroto(task, krotoConfig)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,36 +35,47 @@ data class GeneratorContext(
val args: CompilerArgs = request.parseArgs(),
val config: CompilerConfig = args.getCompilerConfig()
) {
val currentWorkingDir by lazy {
args.options[ARG_KEY_CONFIG_PATH]
?.firstOrNull()
?.let { path -> File(path).parentFile.takeIf { it.exists() } }
.sure {
"Unable to resolve current working directory. " +
"protoc option '$ARG_KEY_CONFIG_PATH' is not configured"
}
}
}
val currentWorkingDir: File by lazy {
if(args.configPath.isNullOrEmpty()) File(USER_DIR) else {
val workingDir = args.getConfigFile().parentFile

fun CompilerArgs.getCompilerConfig(): CompilerConfig =
options[ARG_KEY_CONFIG_PATH]
?.firstOrNull()
?.let { path ->
val configFile = File(path)
configFile
workingDir
.takeIf { it.exists() }
?: error("Config file does not exist. '${configFile.absolutePath}'")
.sure { "Unable to resolve current working directory. '$workingDir'" }
}
?.let { configFile ->
CompilerConfig.newBuilder().also { builder ->
when (configFile.extension.toLowerCase()) {
"json" -> JsonFormat.parser().merge(configFile.readText(), builder)
"asciipb" -> TextFormat.getParser().merge(configFile.readText(), builder)
"yaml", "yml" -> {
val jsonString = yamlToJson(configFile.readText())
JsonFormat.parser().merge(jsonString, builder)
}
}
}.build()
}
}

fun CompilerArgs.getCompilerConfig(): CompilerConfig {
if(configPath.isNullOrEmpty())
return CompilerConfig.getDefaultInstance()

val configFile = getConfigFile()

return CompilerConfig.newBuilder().also { builder ->
when (configFile.extension.toLowerCase()) {
"json" -> JsonFormat.parser().merge(configFile.readText(), builder)
"asciipb" -> TextFormat.getParser().merge(configFile.readText(), builder)
"yaml", "yml" -> {
val jsonString = yamlToJson(configFile.readText())
JsonFormat.parser().merge(jsonString, builder)
}
}
?: CompilerConfig.getDefaultInstance()
}.build()
}

private fun CompilerArgs.getConfigFile(): File {
val configPath = configPath ?: error("protoc option '$ARG_KEY_CONFIG_PATH' is not configured")

val configFile = File(USER_DIR).resolve(File(configPath))

return configFile
.takeIf { it.exists() }
?: error("Config file does not exist. '${configFile.absolutePath}'")
}

private val CompilerArgs.configPath: String?
get() = options[ARG_KEY_CONFIG_PATH]?.firstOrNull()

private val USER_DIR: String
get() = System.getProperty("user.dir")

0 comments on commit 7fef300

Please sign in to comment.