Skip to content

Fix filtering #173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open

Fix filtering #173

wants to merge 31 commits into from

Conversation

dmdashenkov
Copy link
Contributor

@dmdashenkov dmdashenkov commented Sep 8, 2023

In this PR we introduce a better way for plugin developers to control the sources they are working with.

For this, a new term is introduced — source file set label (a.k.a. label). A label consists of the programming language used by the files in the file set and the name of the code generator that created the files. The label is declarative, i.e. the user who configures ProtoData is responsible for providing accurate info.

Typically, a label corresponds to one protoc plugin/builtin. However, protoc treats all the outputs of all plugins/builtins equally, disregarding their relations (e.g. using the same language, etc.). Thus, we require the extra details to be configured by the ProtoData user.

Now, a Renderer may choose which source file sets it wants to process. For this, the implementations should override the supports(SourceFileSetLabel) method. Only the supported source file sets will be passed to render(..). For example, if a renderer only needs to process Java gRPC stubs, it would run the following check:

public class MyRenderer extends JavaRenderer {

    @Override
    public boolean supports(SourceFileSetLabel label) {
        return label.getLanguage().equals(Java.lang()) && 
               label.getGenerator().getName().equals("grpc"); 
    }

    // ...
}

New CLI and Gradle APIs are added for specifying the labels.

In CLI, the source file sets are now supplied by a single parameter --paths. The parameter consists of the label (including the language and the code generator name), the source path, and the target path. Legacy --source-root and --target-root params are no longer supported. See PathsParam help message for more info.

In Gradle DSL, the source file sets are supplied via the SourcePaths objects. The preferred way of creating them is as follows:

protodata {

    launchFor(sourceSets.main) {
         sourceFileSet {
            source = "$buildDir/generated-proto/main/java"
            target = "$buildDir/footest-java"
            language = "java"
        }
        sourceFileSet {
            source = "$buildDir/generated-proto/main/grpc"
            target = "$buildDir/footest-java-grpc"
            language = "java"
            generatorName = "grpc"
        }
    }

    launchFor(sourceSets.test) {
         sourceFileSet {
            source = "$buildDir/generated-proto/test/java"
            target = "$buildDir/footest-test-java"
            language = "java"
        }
    }
}

The protodata.paths property provides a more file-grained control over the registered source file sets.

Fixes SpineEventEngine/compiler#23, fixes SpineEventEngine/compiler#17.

@dmdashenkov dmdashenkov self-assigned this Sep 8, 2023
@codecov
Copy link

codecov bot commented Sep 20, 2023

Codecov Report

Merging #173 (9a3158e) into master (2bc2b03) will decrease coverage by 2.17%.
The diff coverage is 38.50%.

Additional details and impacted files
@@             Coverage Diff              @@
##             master     SpineEventEngine/ProtoData#173      +/-   ##
============================================
- Coverage     82.11%   79.94%   -2.17%     
+ Complexity      364      363       -1     
============================================
  Files           104      114      +10     
  Lines          2600     2688      +88     
  Branches        188      192       +4     
============================================
+ Hits           2135     2149      +14     
- Misses          385      462      +77     
+ Partials         80       77       -3     

@dmdashenkov dmdashenkov marked this pull request as ready for review September 20, 2023 14:54
@dmdashenkov
Copy link
Contributor Author

@alexander-yevsyukov, PTAL. @armiol, PTAL.

Copy link
Collaborator

@armiol armiol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmdashenkov please see my comments.

/**
* A label for a source file set.
*
* The label marks the programming language that the files use and the name of the generator that
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the usage example (the one from the PR description) it is not clear how labels relate to language and generatorName. More than that, with this description, it is now more confusing.

I would use the same terms both in CLI, Gradle DSL, and in the code.

/**
* A name of a custom source code generator.
*
* May represent a Protobuf compiler plugin, or any other code generator.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something strange.

"Generator" in all cases is the thing producing the code. Why would we need a "default" and "custom" generators? They both generate something, and why would we care about their origin?

And again, in this piece of documentation, you mention "labels". Which still does not add up: "generator"s, source set labels and "language" all dance around :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Default" simply references the case most users will likely face most of the time. And it is the default way in which Protoc generated code, as opposed to custom generators/Protoc plugins.

I've cleared up the doc's wording a bit so that there is no confusion with the labels.

2. The source path. Must be an absolute path where the code files are located. If there
are no code files, i.e. ProtoData should generate all the code from scratch, this part
may be left blank.
2. The target path. Must be an absolute path where the code files should be placed after
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"3."

Java,
Kotlin,
JavaScript,
AnyLanguage
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is weird in terms of allowing to use this value in CLI.

/**
* `SourcePaths` to run ProtoData on.
*
* The keys to the multimap are the scopes, i.e. Gradle's source set names,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This String-typed "scope" sounds like a "label" to me. Or like a "generator". I.e., more confusing than not.

If this is a source set name, let's say so.

Same below.

require(!language.isNullOrBlank()) { missingMessage("language") }
}

private fun missingMessage(propName: String) = "Source file set requires the $propName."
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's separate $propName with some symbols, such as ticks or back-ticks.

* from the present data for backward compatibility. However, in this compatibility mode,
* only Java and Kotlin source file sets can be constructed.
*/
internal fun pathsOrCompat(sourceSet: SourceSet): Set<SourcePaths> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem here is that we need to remember which version (this one or paths) to use. And there is no clear sign on when to stop using one and start using another.

Maybe, we could have a "compatibility" mode turned on always. And for testing (or whatever we need "strictly new API" mode for) have another method, which would ignore the deprecated properties?

Copy link
Contributor Author

@dmdashenkov dmdashenkov Sep 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a note on this in doc. Essentially, this method needs to exist until mc-java is updated. Potentially, until the very next PR. Then, only paths need to be used.

return srcRoots.zip(targetRoots)
.map { (src, target) ->
val pathSuffix = src.asFile.toPath().name
val lang = if (pathSuffix == "kotlin") Kotlin else Java
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using a literal, maybe we could use knownLanguages, which we have previously created exactly to associate Kotlin with "kotlin"?

* @see subDirs
*/
public val defaultSubdirectories: List<String> = listOf(
"java",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With all these words constantly repeating, it again strikes me on why we don't re-use the definitions, say, from either languages, or generators (or labels), that we know exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some here. This list will die off once the old subdirs API is removed.

"grpc",
"js",
"dart",
"spine",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't generate anything into "spine" for a while already.

@dmdashenkov dmdashenkov requested a review from armiol September 21, 2023 15:35
@dmdashenkov
Copy link
Contributor Author

@armiol, PTAL again.

Copy link
Collaborator

@alexander-yevsyukov alexander-yevsyukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why we need extra settings for ProtoData while we know what Protobuf and its Gradle Plugin have for languages and generators, like gRPC.

It's either a plugin or built-in in Protobuf codegen terms. The set of supported builtins is known. There are also known plugins like gRPC.

We can get this information from there and transform into Language and Generator terms.

@alexander-yevsyukov
Copy link
Collaborator

We can get this information from there and transform into Language and Generator terms.

When I wrote this I meant we don't need yet another term "label".

Copy link
Collaborator

@armiol armiol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmdashenkov basically, the gist of this PR is as follows.

We could have discussed the approach beforehand, or deal with a number of newly introduced language terms in scope of PR. The latter is longer, but here we are, and there is not much time left to make things conclude with a resolution leaving all parties happy.

I suggest we gather tomorrow on a call with @alexander-yevsyukov and discuss these changes again, instead of bouncing thing back and forth in a PR.

@dmdashenkov dmdashenkov removed their assignment Sep 22, 2023
@dmdashenkov
Copy link
Contributor Author

@armiol, @alexander-yevsyukov, PTAL at the current state of this changeset. I've reflected the main points of our discussion in the PR header and changed some of the naming accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

JavaRenderer should receive SourceFileSet only with .java files Empty Kotlin SourceFileSet is passed to JavaPrinter
3 participants