def FormatHeaderFromFile(source_code_info, file_proto): """Format proto header. Args: source_code_info: SourceCodeInfo object. file_proto: FileDescriptorProto for file. Returns: Formatted proto header as a string. """ # Load the type database. typedb = utils.LoadTypeDb() # Figure out type dependencies in this .proto. types = Types() text_format.Merge( traverse.TraverseFile(file_proto, type_whisperer.TypeWhispererVisitor()), types) type_dependencies = sum( [list(t.type_dependencies) for t in types.types.values()], []) for service in file_proto.service: for m in service.method: type_dependencies.extend([m.input_type[1:], m.output_type[1:]]) # Determine the envoy/ import paths from type deps. envoy_proto_paths = set(typedb.types[t].proto_path for t in type_dependencies if t.startswith('envoy.') and typedb.types[t].proto_path != file_proto.name) def CamelCase(s): return ''.join(t.capitalize() for t in re.split('[\._]', s)) package_line = 'package %s;\n' % file_proto.package file_block = '\n'.join(['syntax = "proto3";\n', package_line]) options = [ 'option java_outer_classname = "%s";' % CamelCase(os.path.basename(file_proto.name)), 'option java_multiple_files = true;', 'option java_package = "io.envoyproxy.%s";' % file_proto.package, ] # This is a workaround for C#/Ruby namespace conflicts between packages and # objects, see https://github.com/envoyproxy/envoy/pull/3854. # TODO(htuch): remove once v3 fixes this naming issue in # https://github.com/envoyproxy/envoy/issues/8120. if file_proto.package in ['envoy.api.v2.listener', 'envoy.api.v2.cluster']: qualified_package = '.'.join( s.capitalize() for s in file_proto.package.split('.')) + 'NS' options += [ 'option csharp_namespace = "%s";' % qualified_package, 'option ruby_package = "%s";' % qualified_package, ] if file_proto.service: options += ['option java_generic_services = true;'] options_block = FormatBlock('\n'.join(options)) envoy_imports = list(envoy_proto_paths) google_imports = [] infra_imports = [] misc_imports = [] for d in file_proto.dependency: if d.startswith('envoy/'): # We ignore existing envoy/ imports, since these are computed explicitly # from type_dependencies. pass elif d.startswith('google/'): google_imports.append(d) elif d.startswith('validate/'): infra_imports.append(d) else: misc_imports.append(d) def FormatImportBlock(xs): if not xs: return '' return FormatBlock('\n'.join(sorted('import "%s";' % x for x in xs))) import_block = '\n'.join( map(FormatImportBlock, [envoy_imports, google_imports, misc_imports, infra_imports])) comment_block = FormatComments(source_code_info.file_level_comments) return ''.join( map(FormatBlock, [file_block, options_block, import_block, comment_block]))
def FormatHeaderFromFile(source_code_info, file_proto, empty_file): """Format proto header. Args: source_code_info: SourceCodeInfo object. file_proto: FileDescriptorProto for file. empty_file: are there no message/enum/service defs in file? Returns: Formatted proto header as a string. """ # Load the type database. typedb = utils.GetTypeDb() # Figure out type dependencies in this .proto. types = Types() text_format.Merge(traverse.TraverseFile(file_proto, type_whisperer.TypeWhispererVisitor()), types) type_dependencies = sum([list(t.type_dependencies) for t in types.types.values()], []) for service in file_proto.service: for m in service.method: type_dependencies.extend([m.input_type[1:], m.output_type[1:]]) # Determine the envoy/ import paths from type deps. envoy_proto_paths = set( typedb.types[t].proto_path for t in type_dependencies if t.startswith('envoy.') and typedb.types[t].proto_path != file_proto.name) def CamelCase(s): return ''.join(t.capitalize() for t in re.split('[\._]', s)) package_line = 'package %s;\n' % file_proto.package file_block = '\n'.join(['syntax = "proto3";\n', package_line]) options = descriptor_pb2.FileOptions() options.java_outer_classname = CamelCase(os.path.basename(file_proto.name)) options.java_multiple_files = True options.java_package = 'io.envoyproxy.' + file_proto.package # This is a workaround for C#/Ruby namespace conflicts between packages and # objects, see https://github.com/envoyproxy/envoy/pull/3854. # TODO(htuch): remove once v3 fixes this naming issue in # https://github.com/envoyproxy/envoy/issues/8120. if file_proto.package in ['envoy.api.v2.listener', 'envoy.api.v2.cluster']: qualified_package = '.'.join(s.capitalize() for s in file_proto.package.split('.')) + 'NS' options.csharp_namespace = qualified_package options.ruby_package = qualified_package if file_proto.service: options.java_generic_services = True if file_proto.options.HasExtension(migrate_pb2.file_migrate): options.Extensions[migrate_pb2.file_migrate].CopyFrom( file_proto.options.Extensions[migrate_pb2.file_migrate]) if file_proto.options.HasExtension( status_pb2.file_status) and file_proto.package.endswith('alpha'): options.Extensions[status_pb2.file_status].CopyFrom( file_proto.options.Extensions[status_pb2.file_status]) if not empty_file: options.Extensions[ status_pb2.file_status].package_version_status = file_proto.options.Extensions[ status_pb2.file_status].package_version_status options_block = FormatOptions(options) requires_versioning_import = any( protoxform_options.GetVersioningAnnotation(m.options) for m in file_proto.message_type) envoy_imports = list(envoy_proto_paths) google_imports = [] infra_imports = [] misc_imports = [] public_imports = [] for idx, d in enumerate(file_proto.dependency): if idx in file_proto.public_dependency: public_imports.append(d) continue elif d.startswith('envoy/annotations') or d.startswith('udpa/annotations'): infra_imports.append(d) elif d.startswith('envoy/'): # We ignore existing envoy/ imports, since these are computed explicitly # from type_dependencies. pass elif d.startswith('google/'): google_imports.append(d) elif d.startswith('validate/'): infra_imports.append(d) elif d in ['udpa/annotations/versioning.proto', 'udpa/annotations/status.proto']: # Skip, we decide to add this based on requires_versioning_import and options. pass else: misc_imports.append(d) if options.HasExtension(status_pb2.file_status): infra_imports.append('udpa/annotations/status.proto') if requires_versioning_import: infra_imports.append('udpa/annotations/versioning.proto') def FormatImportBlock(xs): if not xs: return '' return FormatBlock('\n'.join(sorted('import "%s";' % x for x in set(xs) if x))) def FormatPublicImportBlock(xs): if not xs: return '' return FormatBlock('\n'.join(sorted('import public "%s";' % x for x in xs))) import_block = '\n'.join( map(FormatImportBlock, [envoy_imports, google_imports, misc_imports, infra_imports])) import_block += '\n' + FormatPublicImportBlock(public_imports) comment_block = FormatComments(source_code_info.file_level_comments) return ''.join(map(FormatBlock, [file_block, import_block, options_block, comment_block]))
def format_header_from_file(source_code_info, file_proto, empty_file, requires_deprecation_annotation): """Format proto header. Args: source_code_info: SourceCodeInfo object. file_proto: FileDescriptorProto for file. empty_file: are there no message/enum/service defs in file? requires_deprecation_annotation: does the proto have the deprecated version annotation or disallowed annotation. Returns: Formatted proto header as a string. """ # Load the type database. typedb = utils.get_type_db() # Figure out type dependencies in this .proto. types = types_pb2.Types() text_format.Merge( traverse.traverse_file(file_proto, type_whisperer.TypeWhispererVisitor()), types) type_dependencies = sum( [list(t.type_dependencies) for t in types.types.values()], []) for service in file_proto.service: for m in service.method: type_dependencies.extend([m.input_type[1:], m.output_type[1:]]) # Determine the envoy/ import paths from type deps. envoy_proto_paths = set(typedb.types[t].proto_path for t in type_dependencies if t.startswith('envoy.') and typedb.types[t].proto_path != file_proto.name) def camel_case(s): return ''.join(t.capitalize() for t in re.split('[\._]', s)) package_line = 'package %s;\n' % file_proto.package file_block = '\n'.join(['syntax = "proto3";\n', package_line]) options = descriptor_pb2.FileOptions() options.java_outer_classname = camel_case(os.path.basename( file_proto.name)) for msg in file_proto.message_type: if msg.name == options.java_outer_classname: # This is a workaround for Java outer class names that would otherwise # conflict with types defined within the same proto file, see # https://github.com/envoyproxy/envoy/pull/13378. # TODO: in next major version, make this consistent. options.java_outer_classname += "OuterClass" options.java_multiple_files = True options.java_package = 'io.envoyproxy.' + file_proto.package # Workaround packages in generated go code conflicting by transforming: # foo/bar/v2 to use barv2 as the package in the generated code golang_package_name = "" if file_proto.package.split(".")[-1] in ("v2", "v3"): name = "".join(file_proto.package.split(".")[-2:]) golang_package_name = ";" + name options.go_package = "".join([ "github.com/envoyproxy/go-control-plane/", file_proto.package.replace(".", "/"), golang_package_name ]) # This is a workaround for C#/Ruby namespace conflicts between packages and # objects, see https://github.com/envoyproxy/envoy/pull/3854. # TODO(htuch): remove once v3 fixes this naming issue in # https://github.com/envoyproxy/envoy/issues/8120. if file_proto.package in ['envoy.api.v2.listener', 'envoy.api.v2.cluster']: names = [s.capitalize() for s in file_proto.package.split('.')] options.csharp_namespace = '.'.join(names) + 'NS' options.ruby_package = '::'.join(names) + 'NS' if file_proto.service: options.java_generic_services = True if file_proto.options.HasExtension(migrate_pb2.file_migrate): options.Extensions[migrate_pb2.file_migrate].CopyFrom( file_proto.options.Extensions[migrate_pb2.file_migrate]) if file_proto.options.HasExtension(xds_status_pb2.file_status): options.Extensions[xds_status_pb2.file_status].CopyFrom( file_proto.options.Extensions[xds_status_pb2.file_status]) if file_proto.options.HasExtension( status_pb2.file_status) and file_proto.package.endswith('alpha'): options.Extensions[status_pb2.file_status].CopyFrom( file_proto.options.Extensions[status_pb2.file_status]) frozen_proto = file_proto.options.HasExtension( status_pb2.file_status) and file_proto.options.Extensions[ status_pb2.file_status].package_version_status == status_pb2.FROZEN if not empty_file: options.Extensions[ status_pb2. file_status].package_version_status = file_proto.options.Extensions[ status_pb2.file_status].package_version_status options_block = format_options(options) requires_versioning_import = any( protoxform_options.get_versioning_annotation(m.options) for m in file_proto.message_type) envoy_imports = list(envoy_proto_paths) google_imports = [] infra_imports = [] misc_imports = [] public_imports = [] for idx, d in enumerate(file_proto.dependency): if idx in file_proto.public_dependency: public_imports.append(d) continue elif d.startswith('envoy/annotations') or d.startswith( 'udpa/annotations'): if d == 'envoy/annotations/deprecation.proto' and not frozen_proto: # Skip adding, as deprecation proto should be added if # import_deprecation_proto is True or the proto is frozen. continue infra_imports.append(d) elif d.startswith('envoy/') or d.startswith('contrib/'): # We ignore existing envoy/ imports, since these are computed explicitly # from type_dependencies. pass elif d.startswith('google/'): google_imports.append(d) elif d.startswith('validate/'): infra_imports.append(d) elif d in [ 'udpa/annotations/versioning.proto', 'udpa/annotations/status.proto' ]: # Skip, we decide to add this based on requires_versioning_import and options. pass else: misc_imports.append(d) if requires_deprecation_annotation: infra_imports.append('envoy/annotations/deprecation.proto') if options.HasExtension(status_pb2.file_status): infra_imports.append('udpa/annotations/status.proto') if requires_versioning_import: infra_imports.append('udpa/annotations/versioning.proto') def format_import_block(xs): if not xs: return '' return format_block('\n'.join( sorted('import "%s";' % x for x in set(xs) if x))) def format_public_import_block(xs): if not xs: return '' return format_block('\n'.join( sorted('import public "%s";' % x for x in xs))) import_block = '\n'.join( map(format_import_block, [envoy_imports, google_imports, misc_imports, infra_imports])) import_block += '\n' + format_public_import_block(public_imports) comment_block = format_comments(source_code_info.file_level_comments) return ''.join( map(format_block, [file_block, import_block, options_block, comment_block]))