示例#1
0
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]))
示例#2
0
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]))
示例#3
0
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]))