Skip to content

Commit 22ddb97

Browse files
committed
Prune top level request/response messages
1 parent 5cdf67e commit 22ddb97

3 files changed

Lines changed: 474 additions & 22 deletions

File tree

packages/gapic-generator/gapic/schema/api.py

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,17 +263,40 @@ def with_selective_generation(
263263
*,
264264
generate_omitted_as_internal: bool,
265265
public_methods: Set[str],
266+
excluded_addresses: Set["metadata.Address"],
266267
) -> "Proto":
267268

268269
services = {}
269270
for k, v in self.services.items():
270271
new_v = v.with_selective_generation(
271272
generate_omitted_as_internal=generate_omitted_as_internal,
272-
public_methods=public_methods)
273+
public_methods=public_methods,
274+
excluded_addresses=excluded_addresses)
273275
if new_v:
274276
services[k] = new_v
275277

276-
return dataclasses.replace(self, services=services)
278+
# We only prune messages/enums from protos that are not dependencies.
279+
# Messages and enums are excluded only if they are reachable from some RPC
280+
# but NOT from any of the publicly allowed RPCs.
281+
all_messages = {
282+
k: v for k, v in self.all_messages.items() if v.ident not in excluded_addresses
283+
}
284+
285+
all_enums = {
286+
k: v for k, v in self.all_enums.items() if v.ident not in excluded_addresses
287+
}
288+
289+
# If the proto becomes empty after pruning, we return None to signal
290+
# that it should be excluded from generation.
291+
if not services and not all_messages and not all_enums:
292+
return None
293+
294+
return dataclasses.replace(
295+
self,
296+
services=services,
297+
all_messages=all_messages,
298+
all_enums=all_enums,
299+
)
277300

278301

279302
@dataclasses.dataclass(frozen=True)
@@ -438,10 +461,64 @@ def disambiguate_keyword_sanitize_fname(
438461
k: v for k, v in api.all_protos.items() if k not in api.protos
439462
}
440463

464+
all_resource_messages = collections.ChainMap(
465+
*(proto.resource_messages for proto in api.all_protos.values())
466+
)
467+
468+
# Create a global map of services to support cross-proto lookup
469+
# for extended LROs.
470+
all_services: Dict[str, wrappers.Service] = {}
471+
for p in api.all_protos.values():
472+
for s in p.services.values():
473+
all_services[s.meta.address.proto] = s
474+
all_services[s.name] = s
475+
476+
# Calculate addresses of omitted RPCs and their top-level request/response messages.
477+
# These are the ONLY things that can be excluded.
478+
# Other messages reachable from these (but not from public RPCs) will be KEPT.
479+
candidate_excluded_addresses: Set["metadata.Address"] = set([])
480+
for proto in api.all_protos.values():
481+
for service in proto.services.values():
482+
for method in service.methods.values():
483+
if method.ident.proto not in selective_gapic_methods:
484+
candidate_excluded_addresses.add(method.meta.address)
485+
candidate_excluded_addresses.add(method.input.ident)
486+
candidate_excluded_addresses.add(method.output.ident)
487+
488+
# If this is an LRO, add its response and metadata types to candidates.
489+
if method.lro:
490+
candidate_excluded_addresses.add(method.lro.response_type.ident)
491+
candidate_excluded_addresses.add(method.lro.metadata_type.ident)
492+
493+
# If this is an extended LRO, add its request and operation types to candidates.
494+
if method.extended_lro:
495+
candidate_excluded_addresses.add(method.extended_lro.request_type.ident)
496+
candidate_excluded_addresses.add(method.extended_lro.operation_type.ident)
497+
498+
# Calculate publicly reachable addresses (API-wide).
499+
# This includes only types reachable from the allowlisted methods.
500+
public_rpc_addresses: Set["metadata.Address"] = set([])
501+
for proto in api.all_protos.values():
502+
for service in proto.services.values():
503+
service.add_to_address_allowlist(
504+
address_allowlist=public_rpc_addresses,
505+
method_allowlist=selective_gapic_methods,
506+
resource_messages=all_resource_messages,
507+
services_in_proto=all_services,
508+
)
509+
510+
# Addresses to exclude: those that are candidates but NOT reachable from any PUBLIC RPC.
511+
excluded_addresses = (
512+
candidate_excluded_addresses - public_rpc_addresses
513+
if not selective_gapic_settings.generate_omitted_as_internal
514+
else set([])
515+
)
516+
441517
for name, proto in api.protos.items():
442518
proto_to_generate = proto.with_selective_generation(
443519
generate_omitted_as_internal=selective_gapic_settings.generate_omitted_as_internal,
444520
public_methods=selective_gapic_methods,
521+
excluded_addresses=excluded_addresses,
445522
)
446523
if proto_to_generate:
447524
new_all_protos[name] = proto_to_generate

0 commit comments

Comments
 (0)