• Stars
    star
    136
  • Rank 267,670 (Top 6 %)
  • Language
    Go
  • License
    MIT License
  • Created over 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Yet another Go package which parses a Protocol Buffer file (proto2+proto3)

go-protoparser GoDocCircleCIGo Report CardReleaseLicense

go-protoparser is a yet another Go package which parses a Protocol Buffer file (proto2+proto3).

  • Conforms to the exactly official spec.
  • Undergone rigorous testing. The parser can parses all examples of the official spec well.
  • Easy to use the parser. You can just call the Parse function and receive the Proto struct.

Installation

GO111MODULE=on go get github.com/yoheimuta/go-protoparser/v4

Example

A Protocol Buffer file versioned 3 which is an example of the official reference.

syntax = "proto3";
// An example of the official reference
// See https://developers.google.com/protocol-buffers/docs/reference/proto3-spec#proto_file
package examplepb;
import public "other.proto";
option java_package = "com.example.foo";
enum EnumAllowingAlias {
    option allow_alias = true;
    UNKNOWN = 0;
    STARTED = 1;
    RUNNING = 2 [(custom_option) = "this is a "
                                   "string on two lines"
                ];
}
message outer {
    option (my_option).a = true;
    message inner {   // Level 2
      int64 ival = 1;
    }
    repeated inner inner_message = 2;
    EnumAllowingAlias enum_field =3;
    map<int32, string> my_map = 4;
}
service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse) {};
}

The Parsed result is a Go typed struct. The below output is encoded to JSON for simplicity.

{
  "Syntax": {
    "ProtobufVersion": "proto3",
    "ProtobufVersionQuote": "\"proto3\"",
    "Comments": null,
    "InlineComment": null,
    "Meta": {
      "Pos": {
        "Filename": "simple.proto",
        "Offset": 0,
        "Line": 1,
        "Column": 1
      },
      "LastPos": {
        "Filename": "",
        "Offset": 0,
        "Line": 0,
        "Column": 0
      }
    }
  },
  "ProtoBody": [
    {
      "Name": "examplepb",
      "Comments": [
        {
          "Raw": "// An example of the official reference",
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 19,
              "Line": 2,
              "Column": 1
            },
            "LastPos": {
              "Filename": "",
              "Offset": 0,
              "Line": 0,
              "Column": 0
            }
          }
        },
        {
          "Raw": "// See https://developers.google.com/protocol-buffers/docs/reference/proto3-spec#proto_file",
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 59,
              "Line": 3,
              "Column": 1
            },
            "LastPos": {
              "Filename": "",
              "Offset": 0,
              "Line": 0,
              "Column": 0
            }
          }
        }
      ],
      "InlineComment": null,
      "Meta": {
        "Pos": {
          "Filename": "simple.proto",
          "Offset": 151,
          "Line": 4,
          "Column": 1
        },
        "LastPos": {
          "Filename": "",
          "Offset": 0,
          "Line": 0,
          "Column": 0
        }
      }
    },
    {
      "Modifier": 1,
      "Location": "\"other.proto\"",
      "Comments": null,
      "InlineComment": null,
      "Meta": {
        "Pos": {
          "Filename": "simple.proto",
          "Offset": 170,
          "Line": 5,
          "Column": 1
        },
        "LastPos": {
          "Filename": "",
          "Offset": 0,
          "Line": 0,
          "Column": 0
        }
      }
    },
    {
      "OptionName": "java_package",
      "Constant": "\"com.example.foo\"",
      "Comments": null,
      "InlineComment": null,
      "Meta": {
        "Pos": {
          "Filename": "simple.proto",
          "Offset": 199,
          "Line": 6,
          "Column": 1
        },
        "LastPos": {
          "Filename": "",
          "Offset": 0,
          "Line": 0,
          "Column": 0
        }
      }
    },
    {
      "EnumName": "EnumAllowingAlias",
      "EnumBody": [
        {
          "OptionName": "allow_alias",
          "Constant": "true",
          "Comments": null,
          "InlineComment": null,
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 269,
              "Line": 8,
              "Column": 5
            },
            "LastPos": {
              "Filename": "",
              "Offset": 0,
              "Line": 0,
              "Column": 0
            }
          }
        },
        {
          "Ident": "UNKNOWN",
          "Number": "0",
          "EnumValueOptions": null,
          "Comments": null,
          "InlineComment": null,
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 300,
              "Line": 9,
              "Column": 5
            },
            "LastPos": {
              "Filename": "",
              "Offset": 0,
              "Line": 0,
              "Column": 0
            }
          }
        },
        {
          "Ident": "STARTED",
          "Number": "1",
          "EnumValueOptions": null,
          "Comments": null,
          "InlineComment": null,
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 317,
              "Line": 10,
              "Column": 5
            },
            "LastPos": {
              "Filename": "",
              "Offset": 0,
              "Line": 0,
              "Column": 0
            }
          }
        },
        {
          "Ident": "RUNNING",
          "Number": "2",
          "EnumValueOptions": [
            {
              "OptionName": "(custom_option)",
              "Constant": "\"this is a string on two lines\""
            }
          ],
          "Comments": null,
          "InlineComment": null,
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 334,
              "Line": 11,
              "Column": 5
            },
            "LastPos": {
              "Filename": "",
              "Offset": 0,
              "Line": 0,
              "Column": 0
            }
          }
        }
      ],
      "Comments": null,
      "InlineComment": null,
      "InlineCommentBehindLeftCurly": null,
      "Meta": {
        "Pos": {
          "Filename": "simple.proto",
          "Offset": 240,
          "Line": 7,
          "Column": 1
        },
        "LastPos": {
          "Filename": "simple.proto",
          "Offset": 454,
          "Line": 14,
          "Column": 1
        }
      }
    },
    {
      "MessageName": "outer",
      "MessageBody": [
        {
          "OptionName": "(my_option).a",
          "Constant": "true",
          "Comments": null,
          "InlineComment": null,
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 476,
              "Line": 16,
              "Column": 5
            },
            "LastPos": {
              "Filename": "",
              "Offset": 0,
              "Line": 0,
              "Column": 0
            }
          }
        },
        {
          "MessageName": "inner",
          "MessageBody": [
            {
              "IsRepeated": false,
              "IsRequired": false,
              "IsOptional": false,
              "Type": "int64",
              "FieldName": "ival",
              "FieldNumber": "1",
              "FieldOptions": null,
              "Comments": null,
              "InlineComment": null,
              "Meta": {
                "Pos": {
                  "Filename": "simple.proto",
                  "Offset": 544,
                  "Line": 18,
                  "Column": 7
                },
                "LastPos": {
                  "Filename": "",
                  "Offset": 0,
                  "Line": 0,
                  "Column": 0
                }
              }
            }
          ],
          "Comments": null,
          "InlineComment": null,
          "InlineCommentBehindLeftCurly": {
            "Raw": "// Level 2",
            "Meta": {
              "Pos": {
                "Filename": "simple.proto",
                "Offset": 527,
                "Line": 17,
                "Column": 23
              },
              "LastPos": {
                "Filename": "",
                "Offset": 0,
                "Line": 0,
                "Column": 0
              }
            }
          },
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 509,
              "Line": 17,
              "Column": 5
            },
            "LastPos": {
              "Filename": "simple.proto",
              "Offset": 564,
              "Line": 19,
              "Column": 5
            }
          }
        },
        {
          "IsRepeated": true,
          "IsRequired": false,
          "IsOptional": false,
          "Type": "inner",
          "FieldName": "inner_message",
          "FieldNumber": "2",
          "FieldOptions": null,
          "Comments": null,
          "InlineComment": null,
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 570,
              "Line": 20,
              "Column": 5
            },
            "LastPos": {
              "Filename": "",
              "Offset": 0,
              "Line": 0,
              "Column": 0
            }
          }
        },
        {
          "IsRepeated": false,
          "IsRequired": false,
          "IsOptional": false,
          "Type": "EnumAllowingAlias",
          "FieldName": "enum_field",
          "FieldNumber": "3",
          "FieldOptions": null,
          "Comments": null,
          "InlineComment": null,
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 608,
              "Line": 21,
              "Column": 5
            },
            "LastPos": {
              "Filename": "",
              "Offset": 0,
              "Line": 0,
              "Column": 0
            }
          }
        },
        {
          "KeyType": "int32",
          "Type": "string",
          "MapName": "my_map",
          "FieldNumber": "4",
          "FieldOptions": null,
          "Comments": null,
          "InlineComment": null,
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 645,
              "Line": 22,
              "Column": 5
            },
            "LastPos": {
              "Filename": "",
              "Offset": 0,
              "Line": 0,
              "Column": 0
            }
          }
        }
      ],
      "Comments": null,
      "InlineComment": null,
      "InlineCommentBehindLeftCurly": null,
      "Meta": {
        "Pos": {
          "Filename": "simple.proto",
          "Offset": 456,
          "Line": 15,
          "Column": 1
        },
        "LastPos": {
          "Filename": "simple.proto",
          "Offset": 676,
          "Line": 23,
          "Column": 1
        }
      }
    },
    {
      "ServiceName": "HelloService",
      "ServiceBody": [
        {
          "RPCName": "SayHello",
          "RPCRequest": {
            "IsStream": false,
            "MessageType": "HelloRequest",
            "Meta": {
              "Pos": {
                "Filename": "simple.proto",
                "Offset": 716,
                "Line": 25,
                "Column": 16
              },
              "LastPos": {
                "Filename": "",
                "Offset": 0,
                "Line": 0,
                "Column": 0
              }
            }
          },
          "RPCResponse": {
            "IsStream": false,
            "MessageType": "HelloResponse",
            "Meta": {
              "Pos": {
                "Filename": "simple.proto",
                "Offset": 739,
                "Line": 25,
                "Column": 39
              },
              "LastPos": {
                "Filename": "",
                "Offset": 0,
                "Line": 0,
                "Column": 0
              }
            }
          },
          "Options": null,
          "Comments": null,
          "InlineComment": null,
          "Meta": {
            "Pos": {
              "Filename": "simple.proto",
              "Offset": 703,
              "Line": 25,
              "Column": 3
            },
            "LastPos": {
              "Filename": "simple.proto",
              "Offset": 757,
              "Line": 25,
              "Column": 57
            }
          }
        }
      ],
      "Comments": null,
      "InlineComment": null,
      "InlineCommentBehindLeftCurly": null,
      "Meta": {
        "Pos": {
          "Filename": "simple.proto",
          "Offset": 678,
          "Line": 24,
          "Column": 1
        },
        "LastPos": {
          "Filename": "simple.proto",
          "Offset": 759,
          "Line": 26,
          "Column": 1
        }
      }
    }
  ],
  "Meta": {
    "Filename": "simple.proto"
  }
}

Usage

See also _example/dump.

func run() int {
	flag.Parse()

	reader, err := os.Open(*proto)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to open %s, err %v\n", *proto, err)
		return 1
	}
	defer reader.Close()

	got, err := protoparser.Parse(reader)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to parse, err %v\n", err)
		return 1
	}

	gotJSON, err := json.MarshalIndent(got, "", "  ")
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to marshal, err %v\n", err)
	}
	fmt.Print(string(gotJSON))
	return 0
}

func main() {
	os.Exit(run())
}

Users

Motivation

There exists the similar protobuf parser packages in Go.

But I could not find the parser which just return a parsing result well-typed value. A parser which supports a visitor pattern is useful to implement like linter, but it may be difficult to use. It can be sufficient for most parsing situations to just return a parsing result well-typed value. This is easier to use.

Contributing

  • Fork it
  • Create your feature branch: git checkout -b your-new-feature
  • Commit changes: git commit -m 'Add your feature'
  • Pass all tests
  • Push to the branch: git push origin your-new-feature
  • Submit a pull request

License

The MIT License (MIT)

Acknowledgement

Thank you to the proto package: https://github.com/emicklei/proto

I referred to the package for the good proven design, interface and some source code.

More Repositories

1

protolint

A pluggable linter and fixer to enforce Protocol Buffer style and conventions.
Go
429
star
2

hubot-aws

Hubot masters aws commands
CoffeeScript
63
star
3

RxMusicPlayer

A reactive library to make it easy for audio playbacks using RxSwift.
Swift
55
star
4

mobile-videoplayer.js

Web video player for mobile browser, especially for ios safari which is disabled to autoplay mp4
JavaScript
22
star
5

ExoPlayerMusic

This sample shows how to implement a music player app backed by the ExoPlayer.
Kotlin
19
star
6

dbq

CLI tool to easily Decorate BigQuery table name
Go
14
star
7

AMMusicPlayerController

AMMusicPlayerController is an UI Controller with Apple Music-ish Player.
Swift
12
star
8

chromedp-example

chromedp Example Go App Scraping Sneaker Price List in StockX
Go
12
star
9

intellij-protolint

A protobuf linter for JetBrains IDEs
Java
12
star
10

github-pre-utility

Chrome extension to easily read github issues and gists with long comments without horizontal and vertical scrolling.
JavaScript
10
star
11

hubot-env

Hubot manages environment variables in process.env and redis via commands
CoffeeScript
9
star
12

Linux-GetPidstat

Monitor each process metrics avg using each pidfile
Perl
5
star
13

hubot-brain-inspect

Hubot inspect their own brain in detail
CoffeeScript
5
star
14

BufferedLogger

Tiny but thread-safe logger with a buffering and retrying mechanism for iOS
Swift
4
star
15

action-protolint

Run protolint with reviewdog
Shell
3
star
16

go-warmcache

go-warmcache is a thin go package which manages an in-memory warm cache. It provides thread safety
Go
3
star
17

homebrew-protolint

Homebrew tap for protolint. https://github.com/yoheimuta/protolint
Ruby
3
star
18

vim-protolint

Vim integration for protolint. https://github.com/yoheimuta/protolint
Vim Script
2
star
19

hubot-hint

Hubot tells you how to use other commands
CoffeeScript
2
star
20

go-rewrite

go-rewrite is a thin go package which helps replacing files.
Go
2
star
21

gcache

Golang package to run a http server that manages groupcache for the Redis database
Go
1
star
22

gii

CLI tool to bulk import each gist to github issue with gist url list
Go
1
star
23

talks

Go
1
star