Skip to content

Commit 26f491b

Browse files
authored
Merge pull request quarkusio#36153 from cescoffier/fix-include-in-grpc-proto-compilation
Fix missing include clause in the gRPC proto compilation
2 parents ff64a75 + e4c0502 commit 26f491b

File tree

6 files changed

+101
-17
lines changed

6 files changed

+101
-17
lines changed

docs/src/main/asciidoc/grpc-getting-started.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,8 @@ For instance, having the following properties in your `application.properties`:
203203

204204
[source,properties]
205205
----
206-
quarkus.generate-code.grpc.scan-for-proto-includes."<groupId>\:<artifactId>"=foo/**,bar/**,banana/a-proto.proto
207-
quarkus.generate-code.grpc.scan-for-proto-excludes."<groupId>\:<artifactId>"=foo/private/**,bar/another-proto.proto
206+
quarkus.generate-code.grpc.scan-for-proto-include."<groupId>\:<artifactId>"=foo/**,bar/**,banana/a-proto.proto
207+
quarkus.generate-code.grpc.scan-for-proto-exclude."<groupId>\:<artifactId>"=foo/private/**,bar/another-proto.proto
208208
----
209209

210210
will include:

extensions/grpc/codegen/src/main/java/io/quarkus/grpc/deployment/GrpcCodeGen.java

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.util.List;
1818
import java.util.Locale;
1919
import java.util.Set;
20+
import java.util.stream.Collectors;
2021
import java.util.stream.Stream;
2122

2223
import org.eclipse.microprofile.config.Config;
@@ -100,11 +101,14 @@ public boolean trigger(CodeGenContext context) throws CodeGenException {
100101
Collection<Path> protoFilesFromDependencies = gatherProtosFromDependencies(dirWithProtosFromDependencies, protoDirs,
101102
context);
102103
if (!protoFilesFromDependencies.isEmpty()) {
103-
protoFilesFromDependencies.stream()
104-
.map(Path::normalize)
105-
.map(Path::toAbsolutePath)
106-
.map(Path::toString)
107-
.forEach(protoFiles::add);
104+
for (Path files : protoFilesFromDependencies) {
105+
var pathToProtoFile = files.normalize().toAbsolutePath();
106+
var pathToParentDir = files.getParent();
107+
// Add the proto file to the list of proto to compile, but also add the directory containing the
108+
// proto file to the list of directories to include (it's a set, so no duplicate).
109+
protoFiles.add(pathToProtoFile.toString());
110+
protoDirs.add(pathToParentDir.toString());
111+
}
108112
}
109113

110114
if (!protoFiles.isEmpty()) {
@@ -115,12 +119,12 @@ public boolean trigger(CodeGenContext context) throws CodeGenException {
115119

116120
List<String> command = new ArrayList<>();
117121
command.add(executables.protoc.toString());
118-
for (String protoImportDir : protosToImport) {
119-
command.add(String.format("-I=%s", escapeWhitespace(protoImportDir)));
120-
}
121122
for (String protoDir : protoDirs) {
122123
command.add(String.format("-I=%s", escapeWhitespace(protoDir)));
123124
}
125+
for (String protoImportDir : protosToImport) {
126+
command.add(String.format("-I=%s", escapeWhitespace(protoImportDir)));
127+
}
124128

125129
command.addAll(asList("--plugin=protoc-gen-grpc=" + executables.grpc,
126130
"--plugin=protoc-gen-q-grpc=" + executables.quarkusGrpc,
@@ -203,17 +207,21 @@ private Collection<Path> gatherProtosFromDependencies(Path workDir, Set<String>
203207
}
204208
boolean scanAll = "all".equalsIgnoreCase(scanDependencies);
205209

206-
List<String> dependenciesToScan = asList(scanDependencies.split(","));
210+
List<String> dependenciesToScan = Arrays.stream(scanDependencies.split(",")).map(String::trim)
211+
.collect(Collectors.toList());
207212

208213
ApplicationModel appModel = context.applicationModel();
209214
List<Path> protoFilesFromDependencies = new ArrayList<>();
210215
for (ResolvedDependency artifact : appModel.getRuntimeDependencies()) {
211216
String packageId = String.format("%s:%s", artifact.getGroupId(), artifact.getArtifactId());
212217
Collection<String> includes = properties
213-
.getOptionalValues(String.format(SCAN_DEPENDENCIES_FOR_PROTO_INCLUDE_PATTERN, packageId), String.class)
218+
.getOptionalValue(String.format(SCAN_DEPENDENCIES_FOR_PROTO_INCLUDE_PATTERN, packageId), String.class)
219+
.map(s -> Arrays.stream(s.split(",")).map(String::trim).collect(Collectors.toList()))
214220
.orElse(List.of());
221+
215222
Collection<String> excludes = properties
216-
.getOptionalValues(String.format(SCAN_DEPENDENCIES_FOR_PROTO_EXCLUDE_PATTERN, packageId), String.class)
223+
.getOptionalValue(String.format(SCAN_DEPENDENCIES_FOR_PROTO_EXCLUDE_PATTERN, packageId), String.class)
224+
.map(s -> Arrays.stream(s.split(",")).map(String::trim).collect(Collectors.toList()))
217225
.orElse(List.of());
218226

219227
if (scanAll
@@ -247,7 +255,8 @@ private Collection<String> gatherDirectoriesWithImports(Path workDir, CodeGenCon
247255
}
248256

249257
boolean scanAll = "all".equals(scanForImports.toLowerCase(Locale.getDefault()));
250-
List<String> dependenciesToScan = Arrays.asList(scanForImports.split(","));
258+
List<String> dependenciesToScan = Arrays.stream(scanForImports.split(",")).map(String::trim)
259+
.collect(Collectors.toList());
251260

252261
Set<String> importDirectories = new HashSet<>();
253262
ApplicationModel appModel = context.applicationModel();
@@ -277,8 +286,15 @@ private void extractProtosFromArtifact(Path workDir, Collection<Path> protoFiles
277286
protoDirectories.add(path.getParent().normalize().toAbsolutePath().toString());
278287
} else { // archive
279288
Path relativePath = path.getRoot().relativize(path);
289+
String uniqueName = artifact.getGroupId() + ":" + artifact.getArtifactId();
290+
if (artifact.getVersion() != null) {
291+
uniqueName += ":" + artifact.getVersion();
292+
}
293+
if (artifact.getClassifier() != null) {
294+
uniqueName += "-" + artifact.getClassifier();
295+
}
280296
Path protoUnzipDir = workDir
281-
.resolve(HashUtil.sha1(root.normalize().toAbsolutePath().toString()))
297+
.resolve(HashUtil.sha1(uniqueName))
282298
.normalize().toAbsolutePath();
283299
try {
284300
Files.createDirectories(protoUnzipDir);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
syntax = "proto3";
2+
3+
option java_package = "org.acme.protos.extended";
4+
option java_outer_classname = "ExtendedProtos";
5+
6+
option optimize_for = CODE_SIZE;
7+
8+
package org.acme.proto.extended;
9+
10+
// Import the base proto file
11+
import "base.proto";
12+
13+
// A message representing detailed user information
14+
message DetailedUser {
15+
org.acme.protos.base.User user = 1; // Use the User message from base.proto
16+
org.acme.protos.base.Address address = 2; // Use the Address message from base.proto
17+
string phone_number = 3;
18+
}
19+
20+
// Another message using the base Address message
21+
message Company {
22+
string name = 1;
23+
org.acme.protos.base.Address company_address = 2;
24+
}
25+

integration-tests/grpc-external-proto-test/src/main/resources/application.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
quarkus.generate-code.grpc.scan-for-proto=io.quarkus:quarkus-integration-test-external-proto
2-
quarkus.generate-code.grpc.scan-for-proto-include."io.quarkus\:quarkus-integration-test-external-proto"=dir/**,invalids/invalid2.proto
3-
quarkus.generate-code.grpc.scan-for-proto-exclude."io.quarkus\:quarkus-integration-test-external-proto"=dir/invalid.proto,invalids/invalid2.proto
2+
quarkus.generate-code.grpc.scan-for-proto-include."io.quarkus\:quarkus-integration-test-external-proto"=dir/**, invalids/invalid2.proto, protobuf/**
3+
quarkus.generate-code.grpc.scan-for-proto-exclude."io.quarkus\:quarkus-integration-test-external-proto"=dir/invalid.proto, invalids/invalid2.proto
44

55
%vertx.quarkus.grpc.clients.hello.host=localhost
66
%vertx.quarkus.grpc.clients.hello.port=8081
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
syntax = "proto3";
2+
3+
option java_package = "org.acme.protos.base";
4+
option java_outer_classname = "BASEProtos";
5+
6+
option optimize_for = CODE_SIZE;
7+
8+
// Import the extra proto file
9+
import "role.proto";
10+
11+
package org.acme.protos.base;
12+
13+
// A basic message representing user information
14+
message User {
15+
int32 id = 1;
16+
string name = 2;
17+
string email = 3;
18+
org.acme.protos.role.Role role = 4; // Use the Role message from extra.proto
19+
}
20+
21+
// A basic message representing an address
22+
message Address {
23+
string street = 1;
24+
string city = 2;
25+
string state = 3;
26+
string zip = 4;
27+
}
28+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
syntax = "proto3";
2+
3+
option java_package = "org.acme.protos.role";
4+
option java_outer_classname = "RoleProtos";
5+
6+
option optimize_for = CODE_SIZE;
7+
8+
package org.acme.protos.role;
9+
10+
// A basic message representing a role
11+
message Role {
12+
int32 role_id = 1;
13+
string role_name = 2;
14+
}
15+

0 commit comments

Comments
 (0)