-
Notifications
You must be signed in to change notification settings - Fork 54
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
Draft: Selective api poc #3129
Draft: Selective api poc #3129
Changes from 11 commits
c20c974
cbcd5bc
cf87622
e877473
a89bb9f
7dcdf56
f47c93a
2496716
c29a319
7d8480a
395fa47
950069e
fa63021
e013458
5a89def
a99af2c
e8f5388
2012a82
7978c15
c2967e9
819bdd5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ | |
|
||
package com.google.api.generator.gapic.protoparser; | ||
|
||
import com.google.api.ClientLibrarySettings; | ||
import com.google.api.ClientProto; | ||
import com.google.api.DocumentationRule; | ||
import com.google.api.FieldBehavior; | ||
|
@@ -154,6 +155,14 @@ public static GapicContext parse(CodeGeneratorRequest request) { | |
// Keep message and resource name parsing separate for cleaner logic. | ||
// While this takes an extra pass through the protobufs, the extra time is relatively trivial | ||
// and is worth the larger reduced maintenance cost. | ||
|
||
// Note that if selective api generation is configured via service yaml, resource names | ||
// and messages corresponding to RPC's methods excluded for generation are not removed. | ||
// However, these resource names will not be composed. | ||
// refer to ComposerTest.testComposeSelectively_shouldComposeOnlyOneHelperResource for | ||
// verification. | ||
// TODO: remove messages and resource names that's only used by excluded RPCs configured | ||
// via selective api generation from parsed GapicContext. | ||
Map<String, Message> messages = parseMessages(request, outputResourceReferencesSeen); | ||
|
||
Map<String, ResourceName> resourceNames = parseResourceNames(request); | ||
|
@@ -425,6 +434,47 @@ public static List<Service> parseService( | |
Transport.GRPC); | ||
} | ||
|
||
private static Optional<List<String>> getInclusionMethodListFromServiceYaml( | ||
Optional<com.google.api.Service> serviceYamlProtoOpt, String protoPackage) { | ||
if (!serviceYamlProtoOpt.isPresent() | ||
|| serviceYamlProtoOpt.get().getPublishing().getLibrarySettingsCount() == 0) { | ||
return Optional.empty(); | ||
} | ||
List<ClientLibrarySettings> librarySettingsList = | ||
serviceYamlProtoOpt.get().getPublishing().getLibrarySettingsList(); | ||
// verify library_settings.version matches with proto package name | ||
// This should be validated in upstream. Give warnings if not match. | ||
if (!librarySettingsList.get(0).getVersion().isEmpty() | ||
zhumin8 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
&& !protoPackage.equals(librarySettingsList.get(0).getVersion())) { | ||
LOGGER.warning( | ||
"Service yaml config may be misconfigured. " | ||
zhumin8 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
+ "Version in publishing.library_settings does not match proto package." | ||
zhumin8 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
+ "Disregarding selective generation settings."); | ||
return Optional.empty(); | ||
} | ||
List<String> includeMethodsList = | ||
librarySettingsList | ||
.get(0) | ||
.getJavaSettings() | ||
.getCommon() | ||
.getSelectiveGapicGeneration() | ||
.getMethodsList(); | ||
return Optional.of(includeMethodsList); | ||
} | ||
|
||
private static boolean shouldIncludeMethodInGeneration( | ||
zhumin8 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
MethodDescriptor method, Optional<List<String>> optionalIncludeMethodsList) { | ||
// default to include all when no service yaml or no library setting section. | ||
if (!optionalIncludeMethodsList.isPresent()) { | ||
return true; | ||
} | ||
// default to include all when nothing specified. | ||
if (optionalIncludeMethodsList.get().isEmpty()) { | ||
return true; | ||
} | ||
zhumin8 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return optionalIncludeMethodsList.get().contains(method.getFullName()); | ||
} | ||
|
||
public static List<Service> parseService( | ||
FileDescriptor fileDescriptor, | ||
Map<String, Message> messageTypes, | ||
|
@@ -433,18 +483,27 @@ public static List<Service> parseService( | |
Optional<GapicServiceConfig> serviceConfigOpt, | ||
Set<ResourceName> outputArgResourceNames, | ||
Transport transport) { | ||
|
||
String protoPackage = fileDescriptor.getPackage(); | ||
Optional<List<String>> inclusionMethodListFromServiceYaml = | ||
getInclusionMethodListFromServiceYaml(serviceYamlProtoOpt, protoPackage); | ||
return fileDescriptor.getServices().stream() | ||
.filter( | ||
serviceDescriptor -> { | ||
List<MethodDescriptor> methodsList = serviceDescriptor.getMethods(); | ||
if (methodsList.isEmpty()) { | ||
List<MethodDescriptor> methodListSelected = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This scenario is in case that all methods from a service are excluded? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. And this is likely now e.g. in vertexai's requirement it only exposes methods from 2 services. |
||
methodsList.stream() | ||
.filter( | ||
method -> { | ||
return shouldIncludeMethodInGeneration(method, inclusionMethodListFromServiceYaml); | ||
}) | ||
.collect(Collectors.toList()); | ||
if (methodListSelected.isEmpty()) { | ||
LOGGER.warning( | ||
String.format( | ||
"Service %s has no RPC methods and will not be generated", | ||
serviceDescriptor.getName())); | ||
} | ||
return !methodsList.isEmpty(); | ||
return !methodListSelected.isEmpty(); | ||
}) | ||
.map( | ||
s -> { | ||
|
@@ -498,6 +557,8 @@ public static List<Service> parseService( | |
String pakkage = TypeParser.getPackage(fileDescriptor); | ||
String originalJavaPackage = pakkage; | ||
// Override Java package with that specified in gapic.yaml. | ||
// this override is deprecated and legacy support only | ||
// see go/client-user-guide#configure-long-running-operation-polling-timeouts-optional | ||
if (serviceConfigOpt.isPresent() | ||
&& serviceConfigOpt.get().getLanguageSettingsOpt().isPresent()) { | ||
GapicLanguageSettings languageSettings = | ||
|
@@ -518,6 +579,7 @@ public static List<Service> parseService( | |
.setMethods( | ||
parseMethods( | ||
s, | ||
inclusionMethodListFromServiceYaml, | ||
pakkage, | ||
messageTypes, | ||
resourceNames, | ||
|
@@ -709,6 +771,7 @@ public static Map<String, ResourceName> parseResourceNames( | |
@VisibleForTesting | ||
static List<Method> parseMethods( | ||
ServiceDescriptor serviceDescriptor, | ||
Optional<List<String>> inclusionMethodListFromServiceYaml, | ||
String servicePackage, | ||
Map<String, Message> messageTypes, | ||
Map<String, ResourceName> resourceNames, | ||
|
@@ -721,8 +784,10 @@ static List<Method> parseMethods( | |
// Parse the serviceYaml for autopopulated methods and fields once and put into a map | ||
Map<String, List<String>> autoPopulatedMethodsWithFields = | ||
parseAutoPopulatedMethodsAndFields(serviceYamlProtoOpt); | ||
|
||
for (MethodDescriptor protoMethod : serviceDescriptor.getMethods()) { | ||
if (!shouldIncludeMethodInGeneration(protoMethod, inclusionMethodListFromServiceYaml)) { | ||
continue; | ||
} | ||
// Parse the method. | ||
TypeNode inputType = TypeParser.parseType(protoMethod.getInputType()); | ||
Method.Builder methodBuilder = Method.builder(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is usually preferred to not passing around
Optional
if we can check it before calling the method.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to follow-up on this from our discussion earlier and get @blakeli0 your opinion on this. (FYI, I've combined this method into
shouldIncludeMethodInGeneration()
)For now, I am slightly inclined to keep this
Optional<com.google.api.Service> serviceYamlProtoOpt
as input for 2 reasons:Optional
is repeated in thisParser
class, a larger scale refactor is needed to remove these.shouldIncludeMethodInGeneration()
has all the information to decide if this method should or not be included. I could checkserviceYamlProtoOpt
before calling the method, but the 2 occurrences would repeat the logic in a reverse way, and it might be less readable for debugging in the future.Does this makes sense to you? WDYT?