@@ -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