Skip to content

Commit

Permalink
Merge pull request #53 from SpineEventEngine/filter-option-files-bein…
Browse files Browse the repository at this point in the history
…g-built

Filter files with custom options being built
  • Loading branch information
alexander-yevsyukov authored Jan 21, 2022
2 parents 6c639c7 + 870a811 commit da07b8d
Show file tree
Hide file tree
Showing 24 changed files with 203 additions and 103 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-on-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ jobs:
- name: Upload code coverage report
uses: codecov/codecov-action@v2
with:
fail_ci_if_error: true
fail_ci_if_error: false
verbose: true
8 changes: 8 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ allprojects {

repositories.applyStandard()
repositories.applyGitHubPackages("base-types", rootProject)

configurations.all {
resolutionStrategy {
force(
io.spine.internal.dependency.Grpc.protobufPlugin
)
}
}
}

subprojects {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ package io.spine.internal.dependency
@Suppress("MemberVisibilityCanBePrivate") // used directly from outside
object Protobuf {
private const val group = "com.google.protobuf"
const val version = "3.19.2"
const val version = "3.19.3"
val libs = listOf(
"${group}:protobuf-java:${version}",
"${group}:protobuf-java-util:${version}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import org.gradle.process.CommandLineArgumentProvider
* }
*```
*/
@Suppress("unused")
fun JavaCompile.configureErrorProne() {
options.errorprone
.errorproneArgumentProviders
Expand All @@ -67,7 +68,8 @@ private object ErrorProneConfig {
listOf(

// Exclude generated sources from being analyzed by ErrorProne.
"-XepExcludedPaths:.*/generated/.*",
// Include all directories started from `generated`, such as `generated-proto`.
"-XepExcludedPaths:.*/generated.*/.*",

// Turn the check off until ErrorProne can handle `@Nested` JUnit classes.
// See issue: https://github.com/google/error-prone/issues/956
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package io.spine.internal.gradle
package io.spine.internal.gradle.publish

import com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
import com.fasterxml.jackson.dataformat.xml.XmlMapper
import io.spine.internal.gradle.Repository
import java.io.FileNotFoundException
import java.net.URL
import org.gradle.api.DefaultTask
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@

@file:Suppress("unused")

package io.spine.internal.gradle
package io.spine.internal.gradle.publish

import io.spine.internal.gradle.publish.PublishingRepos
import org.gradle.api.Plugin
import org.gradle.api.Project

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ abstract class PublishExtension @Inject constructor() {
abstract val projectsToPublish: SetProperty<String>
abstract val targetRepositories: SetProperty<Repository>
abstract val spinePrefix: Property<Boolean>
abstract val customPrefix: Property<String>

/**
* The project to be published _instead_ of [projectsToPublish].
Expand All @@ -54,30 +55,40 @@ abstract class PublishExtension @Inject constructor() {
const val name = "spinePublishing"

/** The prefix to be used before the project name if [spinePrefix] is set to `true`. */
const val artifactPrefix = "spine-"
const val standardPrefix = "spine-"

/**
* Creates a new instance of the extension and adds it to the given project.
*/
fun createIn(project: Project): PublishExtension {
val extension = project.extensions.create(name, PublishExtension::class.java)
extension.spinePrefix.convention(true)
extension.customPrefix.convention("")
return extension
}
}

/**
* Obtains an artifact ID of the given project, taking into account the value of
* the [spinePrefix] property. If the property is set to `true`, [artifactPrefix] will
* the [spinePrefix] and [customPrefix] properties.
*
* If the `customPrefix` property is set to a non-empty string, it will be used before
* the published project name. Otherwise, the [spinePrefix] property is taken into account.
*
* If the `spinePrefix` property is set to `true`, [standardPrefix] will
* be used before the project name. Otherwise, just the name of the project will be
* used as the artifact ID.
*/
fun artifactId(project: Project): String =
if (spinePrefix.get()) {
"$artifactPrefix${project.name}"
fun artifactId(project: Project): String {
val customPrefix = customPrefix.get()
return if (customPrefix.isNotEmpty()) {
"$customPrefix${project.name}"
} else if (spinePrefix.get()) {
"$standardPrefix${project.name}"
} else {
project.name
}
}

/**
* Instructs to publish the passed project _instead_ of [projectsToPublish].
Expand Down
8 changes: 3 additions & 5 deletions buildSrc/src/main/kotlin/pmd-settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,9 @@ pmd {
// Disable the default rule set to use the custom rules (see below).
ruleSets = listOf()

// Load PMD settings from a file in `buildSrc/resources/`.
val classLoader = Pmd.javaClass.classLoader
val settingsResource = classLoader.getResource("pmd.xml")!!
val pmdSettings: String = settingsResource.readText()
val textResource: TextResource = resources.text.fromString(pmdSettings)
// Load PMD settings.
val pmdSettings = file("$rootDir/config/quality/pmd.xml")
val textResource: TextResource = resources.text.fromFile(pmdSettings)
ruleSetConfig = textResource

reportsDir = file("build/reports/pmd")
Expand Down
75 changes: 75 additions & 0 deletions cli/src/main/kotlin/io/spine/protodata/cli/DescriptorExtensions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2022, TeamDev. All rights reserved.
*
* 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
*
* Redistribution and use in source and/or binary forms, with or without
* modification, must retain the above copyright notice and the following
* disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package io.spine.protodata.cli

import com.google.protobuf.Descriptors.FileDescriptor
import com.google.protobuf.ExtensionRegistry
import io.spine.code.java.ClassName

/**
* Obtains a name of the outer Java class associated with this file.
*/
internal val FileDescriptor.outerClassName: String
get() {
val outerClass = ClassName.outerClass(this)
return outerClass.binaryName()
}

/**
* Obtains an outer Java class associated with this proto file, if such a class already exists.
* Otherwise, returns `null`.
*/
internal val FileDescriptor.outerClass: Class<*>?
get() {
val outerClass: Class<*>?
try {
val classLoader = javaClass.classLoader
outerClass = classLoader.loadClass(outerClassName)
} catch (e: ClassNotFoundException) {
return null
}
return outerClass
}

/**
* Reflectively calls the static `registerAllExtensions(..)` method, such as
* [io.spine.option.OptionsProto.registerAllExtensions], on the [outerClass] generated for
* this Protobuf file with the custom options declared.
*
* @throws IllegalStateException if the outer class for this proto file does not exist
*/
internal fun FileDescriptor.registerAllExtensions(registry: ExtensionRegistry) {
if (outerClass == null) {
throw IllegalStateException(
"The outer class `$outerClassName` for the file `$name` does not exist."
)
}
val method = outerClass!!.getDeclaredMethod(
"registerAllExtensions", ExtensionRegistry::class.java
)
method.invoke(null, registry)
}
25 changes: 5 additions & 20 deletions cli/src/main/kotlin/io/spine/protodata/cli/FileOptionsProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,35 +28,20 @@ package io.spine.protodata.cli

import com.google.protobuf.Descriptors.FileDescriptor
import com.google.protobuf.ExtensionRegistry
import io.spine.code.java.ClassName
import io.spine.protodata.option.OptionsProvider

/**
* An [OptionsProvider] which provides all the options defined in a single Protobuf file.
*/
internal class FileOptionsProvider(
private val descriptor: FileDescriptor
) : OptionsProvider {
internal class FileOptionsProvider(private val descriptor: FileDescriptor) : OptionsProvider {

/**
* Supplies the given [registry] with the options from the associated file descriptor.
* Supplies the given [registry] with the options from the associated descriptor
* of the proto file. The outer class for the file must exist.
*
* Reflectively calls the static `registerAllExtensions(..)` method, such
* as [io.spine.option.OptionsProto.registerAllExtensions], on the outer class generated for
* the Protobuf file where the custom options are declared.
* @throws IllegalStateException if the outer class for the proto file does not exist.
*/
override fun registerIn(registry: ExtensionRegistry) {
val outerClassName = outerClassName()
val classLoader = this.javaClass.classLoader
val optionsClass = classLoader.loadClass(outerClassName)
val method = optionsClass.getDeclaredMethod(
"registerAllExtensions", ExtensionRegistry::class.java
)
method.invoke(null, registry)
}

private fun outerClassName(): String {
val outerClass = ClassName.outerClass(descriptor)
return outerClass.binaryName()
descriptor.registerAllExtensions(registry)
}
}
12 changes: 10 additions & 2 deletions cli/src/main/kotlin/io/spine/protodata/cli/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,12 @@ internal class Run(version: String) : CliktCommand(
private fun filterOptionFiles(files: FileSet): Sequence<FileOptionsProvider> {
val fileProviders = files.files()
.filter { it.extensions.isNotEmpty() }
// Filter out files that do not have outer classes yet.
// These are `.proto` files being processed by ProtoData that contain
// option definitions. We cannot use these files because there is no binary Java
// code generated for them at this stage. Because of this they cannot be added to
// an `ExtensionRegistry` later.
.filter { it.outerClass != null }
.map(::FileOptionsProvider)
.asSequence()
return fileProviders
Expand All @@ -315,8 +321,10 @@ internal class Run(version: String) : CliktCommand(
return classNames.map { builder.tryCreate(it, classLoader) }
}

private fun <T: Any> ReflectiveBuilder<T>.tryCreate(className: String,
classLoader: ClassLoader): T {
private fun <T : Any> ReflectiveBuilder<T>.tryCreate(
className: String,
classLoader: ClassLoader
): T {
try {
return createByName(className, classLoader)
} catch (e: ClassNotFoundException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ internal open class ReflectiveBuilder<T: Any> {
* It is necessary that the class defined by the [className] parameter is a subtype of `T`.
* Otherwise, a casting error occurs.
*
* @param className name of the concrete class to instantiate
* @param classLoader the [ClassLoader] to load the class by its name
* @param className
* name of the concrete class to instantiate
* @param classLoader
* the [ClassLoader] to load the class by its name
*/
fun createByName(className: String, classLoader: ClassLoader): T {
val cls = classLoader.loadClass(className).kotlin
Expand Down
4 changes: 2 additions & 2 deletions compiler/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@

import io.spine.internal.dependency.JUnit
import io.spine.internal.dependency.Jackson
import io.spine.internal.gradle.CheckVersionIncrement
import io.spine.internal.gradle.IncrementGuard
import io.spine.internal.gradle.publish.CheckVersionIncrement
import io.spine.internal.gradle.publish.IncrementGuard
import io.spine.internal.gradle.publish.PublishingRepos

plugins {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,6 @@ dependencies {

protobuf {
protoc {
artifact = "com.google.protobuf:protoc:+"
artifact = io.spine.internal.dependency.Protobuf.compiler
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,6 @@ dependencies {

protobuf {
protoc {
artifact = "com.google.protobuf:protoc:+"
artifact = io.spine.internal.dependency.Protobuf.compiler
}
}
Loading

0 comments on commit da07b8d

Please sign in to comment.