initial commit

This commit is contained in:
Gyu-Ho Lee 2016-04-17 19:30:06 -07:00
commit be6aa82c50
21 changed files with 2772 additions and 0 deletions

11
.travis.yml Normal file
View File

@ -0,0 +1,11 @@
language: go
sudo: false
go:
- 1.6.1
script:
- ./test

77
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,77 @@
# How to Contribute
CoreOS projects are [Apache 2.0 licensed](LICENSE) and accept contributions via
GitHub pull requests. This document outlines some of the conventions on
development workflow, commit message formatting, contact points and other
resources to make it easier to get your contribution accepted.
# Certificate of Origin
By contributing to this project you agree to the Developer Certificate of
Origin (DCO). This document was created by the Linux Kernel community and is a
simple statement that you, as a contributor, have the legal right to make the
contribution. See the [DCO](DCO) file for details.
# Email and Chat
The project currently uses the general CoreOS email list and IRC channel:
- Email: [coreos-dev](https://groups.google.com/forum/#!forum/coreos-dev)
- IRC: #[coreos](irc://irc.freenode.org:6667/#coreos) IRC channel on freenode.org
Please avoid emailing maintainers found in the MAINTAINERS file directly. They
are very busy and read the mailing lists.
## Getting Started
- Fork the repository on GitHub
- Read the [README](README.md) for build and test instructions
- Play with the project, submit bugs, submit patches!
## Contribution Flow
This is a rough outline of what a contributor's workflow looks like:
- Create a topic branch from where you want to base your work (usually master).
- Make commits of logical units.
- Make sure your commit messages are in the proper format (see below).
- Push your changes to a topic branch in your fork of the repository.
- Make sure the tests pass, and add any new tests as appropriate.
- Submit a pull request to the original repository.
Thanks for your contributions!
### Coding Style
CoreOS projects written in Go follow a set of style guidelines that we've documented
[here](https://github.com/coreos/docs/tree/master/golang). Please follow them when
working on your contributions.
### Format of the Commit Message
We follow a rough convention for commit messages that is designed to answer two
questions: what changed and why. The subject line should feature the what and
the body of the commit should describe the why.
```
scripts: add the test-cluster command
this uses tmux to setup a test cluster that you can easily kill and
start for debugging.
Fixes #38
```
The format can be described more formally as follows:
```
<subsystem>: <what changed>
<BLANK LINE>
<why this change was made>
<BLANK LINE>
<footer>
```
The first line is the subject and should be no longer than 70 characters, the
second line is always blank, and other lines should be wrapped at 80 characters.
This allows the message to be easier to read on GitHub as well as in various
git tools.

36
DCO Normal file
View File

@ -0,0 +1,36 @@
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.

202
LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

5
NOTICE Normal file
View File

@ -0,0 +1,5 @@
CoreOS Project
Copyright 2015 CoreOS, Inc
This product includes software developed at CoreOS, Inc.
(http://www.coreos.com/).

8
README.md Normal file
View File

@ -0,0 +1,8 @@
prodoc generates Protocol Buffer documentation.
Note that parser only understands the minimum syntax
of Protocol Buffer (just enough to generate documentation).
For full featured parser, please check out https://github.com/golang/protobuf.

19
main.go Normal file
View File

@ -0,0 +1,19 @@
// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
func main() {
}

16
parse/doc.go Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package parse parses Protocol Buffers.
package parse

108
parse/markdown.go Normal file
View File

@ -0,0 +1,108 @@
// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package parse
import (
"bytes"
"fmt"
"strings"
)
// Markdown saves 'Proto' to markdown documentation.
// lopts are a slice of language options (C++, Java, Python, Go, Ruby, C#).
func (p *Proto) Markdown(title, fpath string, lopts ...string) error {
p.Sort()
buf := new(bytes.Buffer)
buf.WriteString(fmt.Sprintf("### %s\n\n\n", title))
for _, msg := range p.Messages {
buf.WriteString(fmt.Sprintf("##### message `%s`\n\n", msg.Name))
if msg.Description != "" {
buf.WriteString(msg.Description)
buf.WriteString("\n\n")
}
hd1 := "| Field | Description | Type |"
hd2 := "| ----- | ----------- | ---- |"
for _, lopt := range lopts {
hd1 += fmt.Sprintf(" %s |", lopt)
ds := strings.Repeat("-", len(lopt))
if len(ds) < 3 {
ds = "---"
}
hd2 += fmt.Sprintf(" %s |", ds)
}
buf.WriteString(hd1 + "\n")
buf.WriteString(hd2 + "\n")
for _, elem := range msg.Fields {
ts := elem.ProtoType.String()
if elem.UserDefinedProtoType != "" {
ts = elem.UserDefinedProtoType
}
if elem.Repeated {
ts = "[]" + ts
}
line := fmt.Sprintf("| %s | %s | %s |", elem.Name, elem.Description, ts)
for _, lopt := range lopts {
if elem.UserDefinedProtoType != "" {
line += " |"
continue
}
formatSt := " %s |"
if elem.Repeated {
formatSt = " []%s |"
}
switch lopt {
case "C++":
line += fmt.Sprintf(formatSt, elem.ProtoType.Cpp())
case "Java":
line += fmt.Sprintf(formatSt, elem.ProtoType.Java())
case "Python":
line += fmt.Sprintf(formatSt, elem.ProtoType.Python())
case "Go":
line += fmt.Sprintf(formatSt, elem.ProtoType.Go())
case "Ruby":
line += fmt.Sprintf(formatSt, elem.ProtoType.Ruby())
case "C#":
line += fmt.Sprintf(formatSt, elem.ProtoType.Csharp())
default:
return fmt.Errorf("%q is unknown (must be C++, Java, Python, Go, Ruby, C#)", lopt)
}
}
buf.WriteString(line + "\n")
}
buf.WriteString("\n\n<br>\n\n")
}
for _, svs := range p.Services {
buf.WriteString(fmt.Sprintf("##### service `%s`\n\n", svs.Name))
if svs.Description != "" {
buf.WriteString(svs.Description)
buf.WriteString("\n\n")
}
hd1 := "| Method | Request Type | Response Type | Description |"
hd2 := "| ------ | ------------ | ------------- | ----------- |"
buf.WriteString(hd1 + "\n")
buf.WriteString(hd2 + "\n")
for _, elem := range svs.Methods {
line := fmt.Sprintf("| %s | `%s` | `%s` | %s |", elem.Name, elem.RequestType, elem.ResponseType, elem.Description)
buf.WriteString(line + "\n")
}
buf.WriteString("\n\n<br>\n\n")
}
return toFile(buf.String(), fpath)
}

27
parse/markdown_test.go Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package parse
import "testing"
func TestMarkdown(t *testing.T) {
proto, err := ReadDir("testdata")
if err != nil {
t.Fatal(err)
}
if err := proto.Markdown("etcdserverpb", "testdata/README.md", "Go", "Java", "Python", "C++"); err != nil {
t.Fatal(err)
}
}

212
parse/parse.go Normal file
View File

@ -0,0 +1,212 @@
// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package parse
import (
"bufio"
"io"
"os"
"strings"
)
func readLines(r io.Reader) ([]string, error) {
var (
lines []string
scanner = bufio.NewScanner(r)
)
for scanner.Scan() {
// remove indents
line := strings.TrimSpace(scanner.Text())
if len(line) > 0 {
if strings.HasPrefix(line, "//") {
lines = append(lines, line)
continue
}
// remove semi-colon line-separator
sl := strings.Split(line, ";")
for _, txt := range sl {
if len(txt) > 0 {
if strings.HasPrefix(txt, "optional ") { // proto2
txt = strings.Replace(txt, "optional ", "", 1)
}
lines = append(lines, txt)
}
}
}
}
if err := scanner.Err(); err != nil {
return nil, err
}
return lines, nil
}
type parseMode int
const (
reading parseMode = iota
parsingMessage
parsingService
parsingRPC
)
func ReadDir(targetDir string) (*Proto, error) {
rm, err := walkDirExt(targetDir, ".proto")
if err != nil {
return nil, err
}
var lines []string
for _, fpath := range rm {
f, err := os.OpenFile(fpath, os.O_RDONLY, 0444)
if err != nil {
return nil, err
}
ls, err := readLines(f)
if err != nil {
f.Close()
return nil, err
}
lines = append(lines, ls...)
f.Close()
}
var (
rp = Proto{
Messages: []ProtoMessage{},
Services: []ProtoService{},
}
mode = reading
comments []string
protoMessage = ProtoMessage{}
protoService = ProtoService{}
)
skippingEnum := false
for _, line := range lines {
if strings.HasPrefix(line, "//") {
ls := strings.Replace(line, "//", "", 1)
comments = append(comments, strings.TrimSpace(ls))
continue
}
if strings.HasPrefix(line, "enum ") {
skippingEnum = true
continue
}
if skippingEnum {
if strings.HasSuffix(line, "}") { // end of enum
skippingEnum = false
}
continue
}
switch mode {
case reading:
for j, elem := range strings.Fields(line) {
switch j {
case 0:
switch elem {
case "message":
mode = parsingMessage
case "service":
mode = parsingService
}
case 1: // proto message/service name
switch mode {
case parsingMessage: // message Name
protoMessage.Name = strings.Replace(elem, "{", "", -1)
protoMessage.Description = strings.Join(comments, " ")
comments = []string{} // reset
protoMessage.Fields = []ProtoField{} // reset
case parsingService: // service Name
protoService.Name = strings.Replace(elem, "{", "", -1)
protoService.Description = strings.Join(comments, " ")
comments = []string{} // reset
protoService.Methods = []ProtoMethod{} // reset
}
}
}
case parsingMessage:
if strings.HasSuffix(line, "}") { // closing of message
rp.Messages = append(rp.Messages, protoMessage)
protoMessage = ProtoMessage{}
comments = []string{}
mode = reading
continue
}
protoField := ProtoField{}
tl := line
if strings.HasPrefix(tl, "repeated") {
protoField.Repeated = true
tl = strings.Replace(tl, "repeated ", "", -1)
}
fds := strings.Fields(tl)
tp, err := ToProtoType(fds[0])
if err != nil {
protoField.ProtoType = 0
protoField.UserDefinedProtoType = fds[0]
} else {
protoField.ProtoType = tp
protoField.UserDefinedProtoType = ""
}
protoField.Name = fds[1]
protoField.Description = strings.Join(comments, " ")
protoMessage.Fields = append(protoMessage.Fields, protoField)
comments = []string{}
case parsingService:
// parse 'rpc Watch(stream WatchRequest) returns (stream WatchResponse) {}'
if strings.HasPrefix(line, "rpc ") {
lt := strings.Replace(line, "rpc ", "", 1)
lt = strings.Replace(lt, ")", "", -1)
lt = strings.Replace(lt, " {}", "", 1)
fsigs := strings.Split(lt, " returns ")
ft := strings.Split(fsigs[0], "(") // split 'Watch(stream WatchRequest'
f1 := ft[0]
ft = strings.Fields(ft[1])
f2 := ft[len(ft)-1]
ft = strings.Fields(strings.Replace(fsigs[1], "(", "", 1)) // split '(stream WatchResponse'
f3 := ft[len(ft)-1]
protoMethod := ProtoMethod{} // reset
protoMethod.Name = f1
protoMethod.RequestType = f2
protoMethod.ResponseType = f3
protoMethod.Description = strings.Join(comments, " ")
protoService.Methods = append(protoService.Methods, protoMethod)
comments = []string{}
} else if !strings.HasSuffix(line, "{}") && strings.HasSuffix(line, "}") { // closing of service
rp.Services = append(rp.Services, protoService)
protoService = ProtoService{}
comments = []string{}
mode = reading
}
}
}
return &rp, nil
}

80
parse/parse_test.go Normal file
View File

@ -0,0 +1,80 @@
// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package parse
import "testing"
func TestReadDir(t *testing.T) {
proto, err := ReadDir("testdata")
if err != nil {
t.Fatal(err)
}
proto.Sort()
if proto.Messages[51].Name != "MemberListRequest" {
t.Fatalf("expected 'MemberListRequest', got %+v", proto.Messages[51])
}
if proto.Messages[52].Name != "MemberListResponse" {
t.Fatalf("expected 'MemberListResponse', got %+v", proto.Messages[52])
}
if proto.Messages[52].Fields[0].Name != "header" {
t.Fatalf("expected 'header', got %+v", proto.Messages[52])
}
if proto.Messages[52].Fields[0].UserDefinedProtoType != "ResponseHeader" {
t.Fatalf("expected 'ResponseHeader', got %+v", proto.Messages[52])
}
if proto.Messages[75].Name != "WatchResponse" {
t.Fatalf("expected 'WatchResponse', got %+v", proto.Messages[75])
}
if proto.Messages[75].Fields[0].Name != "header" {
t.Fatalf("expected 'header', got %+v", proto.Messages[75])
}
if proto.Messages[75].Fields[1].ProtoType != Int64 {
t.Fatalf("expected 'Int64', got %+v", proto.Messages[75])
}
if proto.Messages[75].Fields[1].Name != "watch_id" {
t.Fatalf("expected 'watch_id', got %+v", proto.Messages[75])
}
if proto.Messages[75].Fields[0].UserDefinedProtoType != "ResponseHeader" {
t.Fatalf("expected 'ResponseHeader', got %+v", proto.Messages[75])
}
if len(proto.Services[3].Methods) != 3 {
t.Fatalf("expected 3 methods, got %+v", proto.Services[3].Methods)
}
if proto.Services[3].Methods[0].Name != "LeaseGrant" {
t.Fatalf("expected 'LeaseGrant', got %+v", proto.Services[3].Methods[0])
}
if proto.Services[3].Methods[1].Name != "LeaseRevoke" {
t.Fatalf("expected 'LeaseRevoke', got %+v", proto.Services[3].Methods[1])
}
if proto.Services[3].Methods[2].Name != "LeaseKeepAlive" {
t.Fatalf("expected 'LeaseKeepAlive', got %+v", proto.Services[3].Methods[2])
}
if proto.Services[5].Name != "Watch" {
t.Fatalf("expected 'Watch', got %+v", proto.Services[5])
}
if proto.Services[5].Methods[0].Name != "Watch" {
t.Fatalf("expected 'Watch', got %+v", proto.Services[5])
}
if proto.Services[5].Methods[0].RequestType != "WatchRequest" {
t.Fatalf("expected 'WatchRequest', got %+v", proto.Services[5])
}
if proto.Services[5].Methods[0].ResponseType != "WatchResponse" {
t.Fatalf("expected 'WatchRequest', got %+v", proto.Services[5])
}
}

73
parse/proto.go Normal file
View File

@ -0,0 +1,73 @@
// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package parse
import "sort"
// Proto represents sets of 'ProtoMessage' and 'ProtoService'.
type Proto struct {
Messages []ProtoMessage
Services []ProtoService
}
type messages []ProtoMessage
func (s messages) Len() int { return len(s) }
func (s messages) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s messages) Less(i, j int) bool { return s[i].Name < s[j].Name }
type services []ProtoService
func (s services) Len() int { return len(s) }
func (s services) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s services) Less(i, j int) bool { return s[i].Name < s[j].Name }
func (p *Proto) Sort() {
sort.Sort(messages(p.Messages))
sort.Sort(services(p.Services))
}
// ProtoMessage represents the 'message' type in Protocol Buffer.
// (https://developers.google.com/protocol-buffers/docs/proto3#simple)
type ProtoMessage struct {
Name string
Description string
Fields []ProtoField
}
// ProtoField represent member fields in ProtoMessage.
type ProtoField struct {
Name string
Description string
Repeated bool
ProtoType ProtoType
UserDefinedProtoType string
}
// ProtoService represents the 'service' type in Protocol Buffer.
// (https://developers.google.com/protocol-buffers/docs/proto3#services)
type ProtoService struct {
Name string
Description string
Methods []ProtoMethod
}
// ProtoMethod represents methods in ProtoService.
type ProtoMethod struct {
Name string
Description string
RequestType string
ResponseType string
}

863
parse/testdata/README.md vendored Normal file
View File

@ -0,0 +1,863 @@
### etcdserverpb
##### message `AlarmMember`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| memberID | | uint64 | uint64 | long | int/long | uint64 |
| alarm | | AlarmType | | | | |
<br>
##### message `AlarmRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| action | | AlarmAction | | | | |
| memberID | MemberID is the member raising the alarm request | uint64 | uint64 | long | int/long | uint64 |
| alarm | | AlarmType | | | | |
<br>
##### message `AlarmResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
| alarms | | []AlarmMember | | | | |
<br>
##### message `AuthDisableRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `AuthDisableResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthEnableRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `AuthEnableResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthRoleAddRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| name | | string | string | String | str/unicode | string |
<br>
##### message `AuthRoleAddResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthRoleDeleteRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `AuthRoleDeleteResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthRoleGetRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `AuthRoleGetResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthRoleGrantRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| name | | string | string | String | str/unicode | string |
| perm | | authpb.Permission | | | | |
<br>
##### message `AuthRoleGrantResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthRoleRevokeRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `AuthRoleRevokeResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthUserAddRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| name | | string | string | String | str/unicode | string |
| password | | string | string | String | str/unicode | string |
<br>
##### message `AuthUserAddResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthUserChangePasswordRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| name | | string | string | String | str/unicode | string |
| password | | string | string | String | str/unicode | string |
<br>
##### message `AuthUserChangePasswordResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthUserDeleteRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| name | | string | string | String | str/unicode | string |
<br>
##### message `AuthUserDeleteResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthUserGetRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `AuthUserGetResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthUserGrantRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| user | | string | string | String | str/unicode | string |
| role | | string | string | String | str/unicode | string |
<br>
##### message `AuthUserGrantResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthUserRevokeRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `AuthUserRevokeResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `AuthenticateRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `AuthenticateResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `CompactionRequest`
Compaction compacts the kv store upto a given revision. All superseded keys with a revision less than the compaction revision will be removed.
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| revision | | int64 | int64 | long | int/long | int64 |
| physical | physical is set so the RPC will wait until the compaction is physically applied to the local database such that compacted entries are totally removed from the backing store. | bool | bool | boolean | boolean | bool |
<br>
##### message `CompactionResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `Compare`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| result | | CompareResult | | | | |
| target | | CompareTarget | | | | |
| key | key path | bytes | []byte | ByteString | str | string |
| target_union | | oneof | | | | |
| version | version of the given key | int64 | int64 | long | int/long | int64 |
| create_revision | create revision of the given key | int64 | int64 | long | int/long | int64 |
| mod_revision | last modified revision of the given key | int64 | int64 | long | int/long | int64 |
| value | value of the given key | bytes | []byte | ByteString | str | string |
<br>
##### message `DefragmentRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `DefragmentResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `DeleteRangeRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| key | if the range_end is not given, the request deletes the key. | bytes | []byte | ByteString | str | string |
| range_end | if the range_end is given, it deletes the keys in range [key, range_end). | bytes | []byte | ByteString | str | string |
<br>
##### message `DeleteRangeResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
| deleted | Deleted is the number of keys that got deleted. | int64 | int64 | long | int/long | int64 |
<br>
##### message `EmptyResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `HashRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `HashResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
| hash | | uint32 | uint32 | int | int/long | uint32 |
<br>
##### message `InternalRaftRequest`
An InternalRaftRequest is the union of all requests which can be sent via raft.
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| ID | | uint64 | uint64 | long | int/long | uint64 |
| v2 | | Request | | | | |
| range | | RangeRequest | | | | |
| put | | PutRequest | | | | |
| delete_range | | DeleteRangeRequest | | | | |
| txn | | TxnRequest | | | | |
| compaction | | CompactionRequest | | | | |
| lease_grant | | LeaseGrantRequest | | | | |
| lease_revoke | | LeaseRevokeRequest | | | | |
| auth_enable | | AuthEnableRequest | | | | |
| auth_user_add | | AuthUserAddRequest | | | | |
| auth_user_delete | | AuthUserDeleteRequest | | | | |
| auth_user_change_password | | AuthUserChangePasswordRequest | | | | |
| auth_user_grant | | AuthUserGrantRequest | | | | |
| auth_role_add | | AuthRoleAddRequest | | | | |
| auth_role_grant | | AuthRoleGrantRequest | | | | |
| alarm | | AlarmRequest | | | | |
<br>
##### message `LeaseGrantRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| TTL | advisory ttl in seconds | int64 | int64 | long | int/long | int64 |
| ID | requested ID to create; 0 lets lessor choose | int64 | int64 | long | int/long | int64 |
<br>
##### message `LeaseGrantResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
| ID | | int64 | int64 | long | int/long | int64 |
| TTL | server decided ttl in second | int64 | int64 | long | int/long | int64 |
| error | | string | string | String | str/unicode | string |
<br>
##### message `LeaseKeepAliveRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| ID | | int64 | int64 | long | int/long | int64 |
<br>
##### message `LeaseKeepAliveResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
| ID | | int64 | int64 | long | int/long | int64 |
| TTL | | int64 | int64 | long | int/long | int64 |
<br>
##### message `LeaseRevokeRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| ID | | int64 | int64 | long | int/long | int64 |
<br>
##### message `LeaseRevokeResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `Member`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| ID | | uint64 | uint64 | long | int/long | uint64 |
| name | If the member is not started, name will be an empty string. | string | string | String | str/unicode | string |
| peerURLs | | []string | []string | []String | []str/unicode | []string |
| clientURLs | If the member is not started, client_URLs will be an zero length string array. | []string | []string | []String | []str/unicode | []string |
<br>
##### message `MemberAddRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| peerURLs | | []string | []string | []String | []str/unicode | []string |
<br>
##### message `MemberAddResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
| member | | Member | | | | |
<br>
##### message `MemberListRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `MemberListResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
| members | | []Member | | | | |
<br>
##### message `MemberRemoveRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| ID | | uint64 | uint64 | long | int/long | uint64 |
<br>
##### message `MemberRemoveResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `MemberUpdateRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| ID | | uint64 | uint64 | long | int/long | uint64 |
| peerURLs | | []string | []string | []String | []str/unicode | []string |
<br>
##### message `MemberUpdateResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `Metadata`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| NodeID | | uint64 | uint64 | long | int/long | uint64 |
| ClusterID | | uint64 | uint64 | long | int/long | uint64 |
<br>
##### message `PutRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| key | | bytes | []byte | ByteString | str | string |
| value | | bytes | []byte | ByteString | str | string |
| lease | | int64 | int64 | long | int/long | int64 |
<br>
##### message `PutResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
<br>
##### message `RangeRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| key | if the range_end is not given, the request returns the key. | bytes | []byte | ByteString | str | string |
| range_end | if the range_end is given, it gets the keys in range [key, range_end) if range_end is nonempty, otherwise it returns all keys >= key. | bytes | []byte | ByteString | str | string |
| limit | limit the number of keys returned. | int64 | int64 | long | int/long | int64 |
| revision | range over the store at the given revision. if revision is less or equal to zero, range over the newest store. if the revision has been compacted, ErrCompaction will be returned in response. | int64 | int64 | long | int/long | int64 |
| sort_order | sort_order is the requested order for returned the results | SortOrder | | | | |
| sort_target | sort_target is the kv field to use for sorting | SortTarget | | | | |
| serializable | range request is linearizable by default. Linearizable requests has a higher latency and lower throughput than serializable request. To reduce latency, serializable can be set. If serializable is set, range request will be serializable, but not linearizable with other requests. Serializable range can be served locally without waiting for other nodes in the cluster. | bool | bool | boolean | boolean | bool |
<br>
##### message `RangeResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
| kvs | | []storagepb.KeyValue | | | | |
| more | more indicates if there are more keys to return in the requested range. | bool | bool | boolean | boolean | bool |
<br>
##### message `Request`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| ID | | uint64 | uint64 | long | int/long | uint64 |
| Method | | string | string | String | str/unicode | string |
| Path | | string | string | String | str/unicode | string |
| Val | | string | string | String | str/unicode | string |
| Dir | | bool | bool | boolean | boolean | bool |
| PrevValue | | string | string | String | str/unicode | string |
| PrevIndex | | uint64 | uint64 | long | int/long | uint64 |
| PrevExist | | bool | bool | boolean | boolean | bool |
| Expiration | | int64 | int64 | long | int/long | int64 |
| Wait | | bool | bool | boolean | boolean | bool |
| Since | | uint64 | uint64 | long | int/long | uint64 |
| Recursive | | bool | bool | boolean | boolean | bool |
| Sorted | | bool | bool | boolean | boolean | bool |
| Quorum | | bool | bool | boolean | boolean | bool |
| Time | | int64 | int64 | long | int/long | int64 |
| Stream | | bool | bool | boolean | boolean | bool |
| Refresh | | bool | bool | boolean | boolean | bool |
<br>
##### message `RequestUnion`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| request | | oneof | | | | |
| request_range | | RangeRequest | | | | |
| request_put | | PutRequest | | | | |
| request_delete_range | | DeleteRangeRequest | | | | |
<br>
##### message `ResponseHeader`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| cluster_id | | uint64 | uint64 | long | int/long | uint64 |
| member_id | | uint64 | uint64 | long | int/long | uint64 |
| revision | revision of the store when the request was applied. | int64 | int64 | long | int/long | int64 |
| raft_term | term of raft when the request was applied. | uint64 | uint64 | long | int/long | uint64 |
<br>
##### message `ResponseUnion`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| response | | oneof | | | | |
| response_range | | RangeResponse | | | | |
| response_put | | PutResponse | | | | |
| response_delete_range | | DeleteRangeResponse | | | | |
<br>
##### message `SnapshotRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `SnapshotResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | header has the current store information. The first header in the snapshot stream indicates the point in time of the snapshot. | ResponseHeader | | | | |
| remaining_bytes | remaining_bytes is the number of blob bytes to be sent after this message | uint64 | uint64 | long | int/long | uint64 |
| blob | blob has the next chunk of the snapshot in the snapshot stream. | bytes | []byte | ByteString | str | string |
<br>
##### message `StatusRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
<br>
##### message `StatusResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
| version | | string | string | String | str/unicode | string |
| dbSize | | int64 | int64 | long | int/long | int64 |
| leader | | uint64 | uint64 | long | int/long | uint64 |
| raftIndex | | uint64 | uint64 | long | int/long | uint64 |
| raftTerm | | uint64 | uint64 | long | int/long | uint64 |
<br>
##### message `TxnRequest`
If the comparisons succeed, then the success requests will be processed in order, and the response will contain their respective responses in order. If the comparisons fail, then the failure requests will be processed in order, and the response will contain their respective responses in order. From google paxosdb paper: Our implementation hinges around a powerful primitive which we call MultiOp. All other database operations except for iteration are implemented as a single call to MultiOp. A MultiOp is applied atomically and consists of three components: 1. A list of tests called guard. Each test in guard checks a single entry in the database. It may check for the absence or presence of a value, or compare with a given value. Two different tests in the guard may apply to the same or different entries in the database. All tests in the guard are applied and MultiOp returns the results. If all tests are true, MultiOp executes t op (see item 2 below), otherwise it executes f op (see item 3 below). 2. A list of database operations called t op. Each operation in the list is either an insert, delete, or lookup operation, and applies to a single database entry. Two different operations in the list may apply to the same or different entries in the database. These operations are executed if guard evaluates to true. 3. A list of database operations called f op. Like t op, but executed if guard evaluates to false.
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| compare | | []Compare | | | | |
| success | | []RequestUnion | | | | |
| failure | | []RequestUnion | | | | |
<br>
##### message `TxnResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
| succeeded | | bool | bool | boolean | boolean | bool |
| responses | | []ResponseUnion | | | | |
<br>
##### message `WatchCancelRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| watch_id | | int64 | int64 | long | int/long | int64 |
<br>
##### message `WatchCreateRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| key | the key to be watched | bytes | []byte | ByteString | str | string |
| range_end | if the range_end is given, keys in [key, range_end) are watched NOTE: only range_end == prefixEnd(key) is accepted now | bytes | []byte | ByteString | str | string |
| start_revision | start_revision is an optional revision (including) to watch from. No start_revision is "now". | int64 | int64 | long | int/long | int64 |
| progress_notify | if progress_notify is set, etcd server sends WatchResponse with empty events to the created watcher when there are no recent events. It is useful when clients want always to be able to recover a disconnected watcher from a recent known revision. etcdsever can decide how long it should send a notification based on current load. | bool | bool | boolean | boolean | bool |
<br>
##### message `WatchRequest`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| request_union | | oneof | | | | |
| create_request | | WatchCreateRequest | | | | |
| cancel_request | | WatchCancelRequest | | | | |
<br>
##### message `WatchResponse`
| Field | Description | Type | Go | Java | Python | C++ |
| ----- | ----------- | ---- | --- | ---- | ------ | --- |
| header | | ResponseHeader | | | | |
| watch_id | watch_id is the ID of the watching the response sent to. | int64 | int64 | long | int/long | int64 |
| created | If the response is for a create watch request, created is set to true. Client should record the watch_id and prepare for receiving events for that watching from the same stream. All events sent to the created watching will attach with the same watch_id. | bool | bool | boolean | boolean | bool |
| canceled | If the response is for a cancel watch request, cancel is set to true. No further events will be sent to the canceled watching. | bool | bool | boolean | boolean | bool |
| compact_revision | CompactRevision is set to the minimum index if a watching tries to watch at a compacted index. This happens when creating a watching at a compacted revision or the watching cannot catch up with the progress of the KV. Client should treat the watching as canceled and should not try to create any watching with same start_revision again. | int64 | int64 | long | int/long | int64 |
| events | | []storagepb.Event | | | | |
<br>
##### service `Auth`
| Method | Request Type | Response Type | Description |
| ------ | ------------ | ------------- | ----------- |
| AuthEnable | `AuthEnableRequest` | `AuthEnableResponse` | AuthEnable enables authentication. |
| AuthDisable | `AuthDisableRequest` | `AuthDisableResponse` | AuthDisable disables authentication. |
| Authenticate | `AuthenticateRequest` | `AuthenticateResponse` | Authenticate processes authenticate request. |
| UserAdd | `AuthUserAddRequest` | `AuthUserAddResponse` | UserAdd adds a new user. |
| UserGet | `AuthUserGetRequest` | `AuthUserGetResponse` | UserGet gets a detailed information of a user or lists entire users. |
| UserDelete | `AuthUserDeleteRequest` | `AuthUserDeleteResponse` | UserDelete deletes a specified user. |
| UserChangePassword | `AuthUserChangePasswordRequest` | `AuthUserChangePasswordResponse` | UserChangePassword changes password of a specified user. |
| UserGrant | `AuthUserGrantRequest` | `AuthUserGrantResponse` | UserGrant grants a role to a specified user. |
| UserRevoke | `AuthUserRevokeRequest` | `AuthUserRevokeResponse` | UserRevoke revokes a role of specified user. |
| RoleAdd | `AuthRoleAddRequest` | `AuthRoleAddResponse` | RoleAdd adds a new role. |
| RoleGet | `AuthRoleGetRequest` | `AuthRoleGetResponse` | RoleGet gets a detailed information of a role or lists entire roles. |
| RoleDelete | `AuthRoleDeleteRequest` | `AuthRoleDeleteResponse` | RoleDelete deletes a specified role. |
| RoleGrant | `AuthRoleGrantRequest` | `AuthRoleGrantResponse` | RoleGrant grants a permission of a specified key or range to a specified role. |
| RoleRevoke | `AuthRoleRevokeRequest` | `AuthRoleRevokeResponse` | RoleRevoke revokes a key or range permission of a specified role. |
<br>
##### service `Cluster`
| Method | Request Type | Response Type | Description |
| ------ | ------------ | ------------- | ----------- |
| MemberAdd | `MemberAddRequest` | `MemberAddResponse` | MemberAdd adds a member into the cluster. |
| MemberRemove | `MemberRemoveRequest` | `MemberRemoveResponse` | MemberRemove removes an existing member from the cluster. |
| MemberUpdate | `MemberUpdateRequest` | `MemberUpdateResponse` | MemberUpdate updates the member configuration. |
| MemberList | `MemberListRequest` | `MemberListResponse` | MemberList lists all the members in the cluster. |
<br>
##### service `KV`
| Method | Request Type | Response Type | Description |
| ------ | ------------ | ------------- | ----------- |
| Range | `RangeRequest` | `RangeResponse` | Range gets the keys in the range from the store. |
| Put | `PutRequest` | `PutResponse` | Put puts the given key into the store. A put request increases the revision of the store, and generates one event in the event history. |
| DeleteRange | `DeleteRangeRequest` | `DeleteRangeResponse` | Delete deletes the given range from the store. A delete request increase the revision of the store, and generates one event in the event history. |
| Txn | `TxnRequest` | `TxnResponse` | Txn processes all the requests in one transaction. A txn request increases the revision of the store, and generates events with the same revision in the event history. It is not allowed to modify the same key several times within one txn. |
| Compact | `CompactionRequest` | `CompactionResponse` | Compact compacts the event history in etcd. User should compact the event history periodically, or it will grow infinitely. |
<br>
##### service `Lease`
| Method | Request Type | Response Type | Description |
| ------ | ------------ | ------------- | ----------- |
| LeaseGrant | `LeaseGrantRequest` | `LeaseGrantResponse` | LeaseGrant creates a lease. A lease has a TTL. The lease will expire if the server does not receive a keepAlive within TTL from the lease holder. All keys attached to the lease will be expired and deleted if the lease expires. The key expiration generates an event in event history. |
| LeaseRevoke | `LeaseRevokeRequest` | `LeaseRevokeResponse` | LeaseRevoke revokes a lease. All the key attached to the lease will be expired and deleted. |
| LeaseKeepAlive | `LeaseKeepAliveRequest` | `LeaseKeepAliveResponse` | KeepAlive keeps the lease alive. |
<br>
##### service `Maintenance`
| Method | Request Type | Response Type | Description |
| ------ | ------------ | ------------- | ----------- |
| Alarm | `AlarmRequest` | `AlarmResponse` | Alarm activates, deactivates, and queries alarms regarding cluster health. |
| Status | `StatusRequest` | `StatusResponse` | Status gets the status of the member. |
| Defragment | `DefragmentRequest` | `DefragmentResponse` | |
| Hash | `HashRequest` | `HashResponse` | Hash returns the hash of the local KV state for consistency checking purpose. This is designed for testing; do not use this in production when there are ongoing transactions. |
| Snapshot | `SnapshotRequest` | `SnapshotResponse` | Snapshot sends a snapshot of the entire backend |
<br>
##### service `Watch`
| Method | Request Type | Response Type | Description |
| ------ | ------------ | ------------- | ----------- |
| Watch | `WatchRequest` | `WatchResponse` | Watch watches the events happening or happened. Both input and output are stream. One watch rpc can watch for multiple keys or prefixs and get a stream of events. The whole events history can be watched unless compacted. |
<br>

34
parse/testdata/etcdserver.proto vendored Normal file
View File

@ -0,0 +1,34 @@
syntax = "proto2";
package etcdserverpb;
import "gogoproto/gogo.proto";
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.goproto_getters_all) = false;
message Request {
optional uint64 ID = 1 [(gogoproto.nullable) = false];
optional string Method = 2 [(gogoproto.nullable) = false];
optional string Path = 3 [(gogoproto.nullable) = false];
optional string Val = 4 [(gogoproto.nullable) = false];
optional bool Dir = 5 [(gogoproto.nullable) = false];
optional string PrevValue = 6 [(gogoproto.nullable) = false];
optional uint64 PrevIndex = 7 [(gogoproto.nullable) = false];
optional bool PrevExist = 8 [(gogoproto.nullable) = true];
optional int64 Expiration = 9 [(gogoproto.nullable) = false];
optional bool Wait = 10 [(gogoproto.nullable) = false];
optional uint64 Since = 11 [(gogoproto.nullable) = false];
optional bool Recursive = 12 [(gogoproto.nullable) = false];
optional bool Sorted = 13 [(gogoproto.nullable) = false];
optional bool Quorum = 14 [(gogoproto.nullable) = false];
optional int64 Time = 15 [(gogoproto.nullable) = false];
optional bool Stream = 16 [(gogoproto.nullable) = false];
optional bool Refresh = 17 [(gogoproto.nullable) = true];
}
message Metadata {
optional uint64 NodeID = 1 [(gogoproto.nullable) = false];
optional uint64 ClusterID = 2 [(gogoproto.nullable) = false];
}

40
parse/testdata/raft_internal.proto vendored Normal file
View File

@ -0,0 +1,40 @@
syntax = "proto3";
package etcdserverpb;
import "gogoproto/gogo.proto";
import "etcdserver.proto";
import "rpc.proto";
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.goproto_getters_all) = false;
// An InternalRaftRequest is the union of all requests which can be
// sent via raft.
message InternalRaftRequest {
uint64 ID = 1;
Request v2 = 2;
RangeRequest range = 3;
PutRequest put = 4;
DeleteRangeRequest delete_range = 5;
TxnRequest txn = 6;
CompactionRequest compaction = 7;
LeaseGrantRequest lease_grant = 8;
LeaseRevokeRequest lease_revoke = 9;
AuthEnableRequest auth_enable = 10;
AuthUserAddRequest auth_user_add = 11;
AuthUserDeleteRequest auth_user_delete = 12;
AuthUserChangePasswordRequest auth_user_change_password = 13;
AuthUserGrantRequest auth_user_grant = 14;
AuthRoleAddRequest auth_role_add = 15;
AuthRoleGrantRequest auth_role_grant = 16;
AlarmRequest alarm = 17;
}
message EmptyResponse {
}

610
parse/testdata/rpc.proto vendored Normal file
View File

@ -0,0 +1,610 @@
syntax = "proto3";
package etcdserverpb;
import "gogoproto/gogo.proto";
import "etcd/storage/storagepb/kv.proto";
import "etcd/auth/authpb/auth.proto";
option (gogoproto.marshaler_all) = true;
option (gogoproto.unmarshaler_all) = true;
service KV {
// Range gets the keys in the range from the store.
rpc Range(RangeRequest) returns (RangeResponse) {}
// Put puts the given key into the store.
// A put request increases the revision of the store,
// and generates one event in the event history.
rpc Put(PutRequest) returns (PutResponse) {}
// Delete deletes the given range from the store.
// A delete request increase the revision of the store,
// and generates one event in the event history.
rpc DeleteRange(DeleteRangeRequest) returns (DeleteRangeResponse) {}
// Txn processes all the requests in one transaction.
// A txn request increases the revision of the store,
// and generates events with the same revision in the event history.
// It is not allowed to modify the same key several times within one txn.
rpc Txn(TxnRequest) returns (TxnResponse) {}
// Compact compacts the event history in etcd. User should compact the
// event history periodically, or it will grow infinitely.
rpc Compact(CompactionRequest) returns (CompactionResponse) {}
}
service Watch {
// Watch watches the events happening or happened. Both input and output
// are stream. One watch rpc can watch for multiple keys or prefixs and
// get a stream of events. The whole events history can be watched unless
// compacted.
rpc Watch(stream WatchRequest) returns (stream WatchResponse) {}
}
service Lease {
// LeaseGrant creates a lease. A lease has a TTL. The lease will expire if the
// server does not receive a keepAlive within TTL from the lease holder.
// All keys attached to the lease will be expired and deleted if the lease expires.
// The key expiration generates an event in event history.
rpc LeaseGrant(LeaseGrantRequest) returns (LeaseGrantResponse) {}
// LeaseRevoke revokes a lease. All the key attached to the lease will be expired and deleted.
rpc LeaseRevoke(LeaseRevokeRequest) returns (LeaseRevokeResponse) {}
// KeepAlive keeps the lease alive.
rpc LeaseKeepAlive(stream LeaseKeepAliveRequest) returns (stream LeaseKeepAliveResponse) {}
// TODO(xiangli) List all existing Leases?
// TODO(xiangli) Get details information (expirations, leased keys, etc.) of a lease?
}
service Cluster {
// MemberAdd adds a member into the cluster.
rpc MemberAdd(MemberAddRequest) returns (MemberAddResponse) {}
// MemberRemove removes an existing member from the cluster.
rpc MemberRemove(MemberRemoveRequest) returns (MemberRemoveResponse) {}
// MemberUpdate updates the member configuration.
rpc MemberUpdate(MemberUpdateRequest) returns (MemberUpdateResponse) {}
// MemberList lists all the members in the cluster.
rpc MemberList(MemberListRequest) returns (MemberListResponse) {}
}
service Maintenance {
// Alarm activates, deactivates, and queries alarms regarding cluster health.
rpc Alarm(AlarmRequest) returns (AlarmResponse) {}
// Status gets the status of the member.
rpc Status(StatusRequest) returns (StatusResponse) {}
rpc Defragment(DefragmentRequest) returns (DefragmentResponse) {}
// Hash returns the hash of the local KV state for consistency checking purpose.
// This is designed for testing; do not use this in production when there
// are ongoing transactions.
rpc Hash(HashRequest) returns (HashResponse) {}
// Snapshot sends a snapshot of the entire backend
rpc Snapshot(SnapshotRequest) returns (stream SnapshotResponse) {}
}
service Auth {
// AuthEnable enables authentication.
rpc AuthEnable(AuthEnableRequest) returns (AuthEnableResponse) {}
// AuthDisable disables authentication.
rpc AuthDisable(AuthDisableRequest) returns (AuthDisableResponse) {}
// Authenticate processes authenticate request.
rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse) {}
// UserAdd adds a new user.
rpc UserAdd(AuthUserAddRequest) returns (AuthUserAddResponse) {}
// UserGet gets a detailed information of a user or lists entire users.
rpc UserGet(AuthUserGetRequest) returns (AuthUserGetResponse) {}
// UserDelete deletes a specified user.
rpc UserDelete(AuthUserDeleteRequest) returns (AuthUserDeleteResponse) {}
// UserChangePassword changes password of a specified user.
rpc UserChangePassword(AuthUserChangePasswordRequest) returns (AuthUserChangePasswordResponse) {}
// UserGrant grants a role to a specified user.
rpc UserGrant(AuthUserGrantRequest) returns (AuthUserGrantResponse) {}
// UserRevoke revokes a role of specified user.
rpc UserRevoke(AuthUserRevokeRequest) returns (AuthUserRevokeResponse) {}
// RoleAdd adds a new role.
rpc RoleAdd(AuthRoleAddRequest) returns (AuthRoleAddResponse) {}
// RoleGet gets a detailed information of a role or lists entire roles.
rpc RoleGet(AuthRoleGetRequest) returns (AuthRoleGetResponse) {}
// RoleDelete deletes a specified role.
rpc RoleDelete(AuthRoleDeleteRequest) returns (AuthRoleDeleteResponse) {}
// RoleGrant grants a permission of a specified key or range to a specified role.
rpc RoleGrant(AuthRoleGrantRequest) returns (AuthRoleGrantResponse) {}
// RoleRevoke revokes a key or range permission of a specified role.
rpc RoleRevoke(AuthRoleRevokeRequest) returns (AuthRoleRevokeResponse) {}
}
message ResponseHeader {
uint64 cluster_id = 1;
uint64 member_id = 2;
// revision of the store when the request was applied.
int64 revision = 3;
// term of raft when the request was applied.
uint64 raft_term = 4;
}
message RangeRequest {
enum SortOrder {
NONE = 0; // default, no sorting
ASCEND = 1; // lowest target value first
DESCEND = 2; // highest target value first
}
enum SortTarget {
KEY = 0;
VERSION = 1;
CREATE = 2;
MOD = 3;
VALUE = 4;
}
// if the range_end is not given, the request returns the key.
bytes key = 1;
// if the range_end is given, it gets the keys in range [key, range_end)
// if range_end is nonempty, otherwise it returns all keys >= key.
bytes range_end = 2;
// limit the number of keys returned.
int64 limit = 3;
// range over the store at the given revision.
// if revision is less or equal to zero, range over the newest store.
// if the revision has been compacted, ErrCompaction will be returned in
// response.
int64 revision = 4;
// sort_order is the requested order for returned the results
SortOrder sort_order = 5;
// sort_target is the kv field to use for sorting
SortTarget sort_target = 6;
// range request is linearizable by default. Linearizable requests has a higher
// latency and lower throughput than serializable request.
// To reduce latency, serializable can be set. If serializable is set, range request
// will be serializable, but not linearizable with other requests.
// Serializable range can be served locally without waiting for other nodes in the cluster.
bool serializable = 7;
}
message RangeResponse {
ResponseHeader header = 1;
repeated storagepb.KeyValue kvs = 2;
// more indicates if there are more keys to return in the requested range.
bool more = 3;
}
message PutRequest {
bytes key = 1;
bytes value = 2;
int64 lease = 3;
}
message PutResponse {
ResponseHeader header = 1;
}
message DeleteRangeRequest {
// if the range_end is not given, the request deletes the key.
bytes key = 1;
// if the range_end is given, it deletes the keys in range [key, range_end).
bytes range_end = 2;
}
message DeleteRangeResponse {
ResponseHeader header = 1;
// Deleted is the number of keys that got deleted.
int64 deleted = 2;
}
message RequestUnion {
oneof request {
RangeRequest request_range = 1;
PutRequest request_put = 2;
DeleteRangeRequest request_delete_range = 3;
}
}
message ResponseUnion {
oneof response {
RangeResponse response_range = 1;
PutResponse response_put = 2;
DeleteRangeResponse response_delete_range = 3;
}
}
message Compare {
enum CompareResult {
EQUAL = 0;
GREATER = 1;
LESS = 2;
}
enum CompareTarget {
VERSION = 0;
CREATE = 1;
MOD = 2;
VALUE= 3;
}
CompareResult result = 1;
CompareTarget target = 2;
// key path
bytes key = 3;
oneof target_union {
// version of the given key
int64 version = 4;
// create revision of the given key
int64 create_revision = 5;
// last modified revision of the given key
int64 mod_revision = 6;
// value of the given key
bytes value = 7;
}
}
// If the comparisons succeed, then the success requests will be processed in order,
// and the response will contain their respective responses in order.
// If the comparisons fail, then the failure requests will be processed in order,
// and the response will contain their respective responses in order.
// From google paxosdb paper:
// Our implementation hinges around a powerful primitive which we call MultiOp. All other database
// operations except for iteration are implemented as a single call to MultiOp. A MultiOp is applied atomically
// and consists of three components:
// 1. A list of tests called guard. Each test in guard checks a single entry in the database. It may check
// for the absence or presence of a value, or compare with a given value. Two different tests in the guard
// may apply to the same or different entries in the database. All tests in the guard are applied and
// MultiOp returns the results. If all tests are true, MultiOp executes t op (see item 2 below), otherwise
// it executes f op (see item 3 below).
// 2. A list of database operations called t op. Each operation in the list is either an insert, delete, or
// lookup operation, and applies to a single database entry. Two different operations in the list may apply
// to the same or different entries in the database. These operations are executed
// if guard evaluates to
// true.
// 3. A list of database operations called f op. Like t op, but executed if guard evaluates to false.
message TxnRequest {
repeated Compare compare = 1;
repeated RequestUnion success = 2;
repeated RequestUnion failure = 3;
}
message TxnResponse {
ResponseHeader header = 1;
bool succeeded = 2;
repeated ResponseUnion responses = 3;
}
// Compaction compacts the kv store upto a given revision. All superseded keys
// with a revision less than the compaction revision will be removed.
message CompactionRequest {
int64 revision = 1;
// physical is set so the RPC will wait until the compaction is physically
// applied to the local database such that compacted entries are totally
// removed from the backing store.
bool physical = 2;
}
message CompactionResponse {
ResponseHeader header = 1;
}
message HashRequest {
}
message HashResponse {
ResponseHeader header = 1;
uint32 hash = 2;
}
message SnapshotRequest {
}
message SnapshotResponse {
// header has the current store information. The first header in the snapshot
// stream indicates the point in time of the snapshot.
ResponseHeader header = 1;
// remaining_bytes is the number of blob bytes to be sent after this message
uint64 remaining_bytes = 2;
// blob has the next chunk of the snapshot in the snapshot stream.
bytes blob = 3;
}
message WatchRequest {
oneof request_union {
WatchCreateRequest create_request = 1;
WatchCancelRequest cancel_request = 2;
}
}
message WatchCreateRequest {
// the key to be watched
bytes key = 1;
// if the range_end is given, keys in [key, range_end) are watched
// NOTE: only range_end == prefixEnd(key) is accepted now
bytes range_end = 2;
// start_revision is an optional revision (including) to watch from. No start_revision is "now".
int64 start_revision = 3;
// if progress_notify is set, etcd server sends WatchResponse with empty events to the
// created watcher when there are no recent events. It is useful when clients want always to be
// able to recover a disconnected watcher from a recent known revision.
// etcdsever can decide how long it should send a notification based on current load.
bool progress_notify = 4;
}
message WatchCancelRequest {
int64 watch_id = 1;
}
message WatchResponse {
ResponseHeader header = 1;
// watch_id is the ID of the watching the response sent to.
int64 watch_id = 2;
// If the response is for a create watch request, created is set to true.
// Client should record the watch_id and prepare for receiving events for
// that watching from the same stream.
// All events sent to the created watching will attach with the same watch_id.
bool created = 3;
// If the response is for a cancel watch request, cancel is set to true.
// No further events will be sent to the canceled watching.
bool canceled = 4;
// CompactRevision is set to the minimum index if a watching tries to watch
// at a compacted index.
//
// This happens when creating a watching at a compacted revision or the watching cannot
// catch up with the progress of the KV.
//
// Client should treat the watching as canceled and should not try to create any
// watching with same start_revision again.
int64 compact_revision = 5;
repeated storagepb.Event events = 11;
}
message LeaseGrantRequest {
// advisory ttl in seconds
int64 TTL = 1;
// requested ID to create; 0 lets lessor choose
int64 ID = 2;
}
message LeaseGrantResponse {
ResponseHeader header = 1;
int64 ID = 2;
// server decided ttl in second
int64 TTL = 3;
string error = 4;
}
message LeaseRevokeRequest {
int64 ID = 1;
}
message LeaseRevokeResponse {
ResponseHeader header = 1;
}
message LeaseKeepAliveRequest {
int64 ID = 1;
}
message LeaseKeepAliveResponse {
ResponseHeader header = 1;
int64 ID = 2;
int64 TTL = 3;
}
message Member {
uint64 ID = 1;
// If the member is not started, name will be an empty string.
string name = 2;
repeated string peerURLs = 3;
// If the member is not started, client_URLs will be an zero length
// string array.
repeated string clientURLs = 4;
}
message MemberAddRequest {
repeated string peerURLs = 1;
}
message MemberAddResponse {
ResponseHeader header = 1;
Member member = 2;
}
message MemberRemoveRequest {
uint64 ID = 1;
}
message MemberRemoveResponse {
ResponseHeader header = 1;
}
message MemberUpdateRequest {
uint64 ID = 1;
repeated string peerURLs = 2;
}
message MemberUpdateResponse{
ResponseHeader header = 1;
}
message MemberListRequest {
}
message MemberListResponse {
ResponseHeader header = 1;
repeated Member members = 2;
}
message DefragmentRequest {
}
message DefragmentResponse {
ResponseHeader header = 1;
}
enum AlarmType {
NONE = 0; // default, used to query if any alarm is active
NOSPACE = 1;
}
message AlarmRequest {
enum AlarmAction {
GET = 0;
ACTIVATE = 1;
DEACTIVATE = 2;
}
AlarmAction action = 1;
// MemberID is the member raising the alarm request
uint64 memberID = 2;
AlarmType alarm = 3;
}
message AlarmMember {
uint64 memberID = 1;
AlarmType alarm = 2;
}
message AlarmResponse {
ResponseHeader header = 1;
repeated AlarmMember alarms = 2;
}
message StatusRequest {
}
message StatusResponse {
ResponseHeader header = 1;
string version = 2;
int64 dbSize = 3;
uint64 leader = 4;
uint64 raftIndex = 5;
uint64 raftTerm = 6;
}
message AuthEnableRequest {
}
message AuthDisableRequest {
}
message AuthenticateRequest {
}
message AuthUserAddRequest {
string name = 1;
string password = 2;
}
message AuthUserGetRequest {
}
message AuthUserDeleteRequest {
string name = 1;
}
message AuthUserChangePasswordRequest {
string name = 1;
string password = 2;
}
message AuthUserGrantRequest {
string user = 1;
string role = 2;
}
message AuthUserRevokeRequest {
}
message AuthRoleAddRequest {
string name = 1;
}
message AuthRoleGetRequest {
}
message AuthRoleDeleteRequest {
}
message AuthRoleGrantRequest {
string name = 1;
authpb.Permission perm = 2;
}
message AuthRoleRevokeRequest {
}
message AuthEnableResponse {
ResponseHeader header = 1;
}
message AuthDisableResponse {
ResponseHeader header = 1;
}
message AuthenticateResponse {
ResponseHeader header = 1;
}
message AuthUserAddResponse {
ResponseHeader header = 1;
}
message AuthUserGetResponse {
ResponseHeader header = 1;
}
message AuthUserDeleteResponse {
ResponseHeader header = 1;
}
message AuthUserChangePasswordResponse {
ResponseHeader header = 1;
}
message AuthUserGrantResponse {
ResponseHeader header = 1;
}
message AuthUserRevokeResponse {
ResponseHeader header = 1;
}
message AuthRoleAddResponse {
ResponseHeader header = 1;
}
message AuthRoleGetResponse {
ResponseHeader header = 1;
}
message AuthRoleDeleteResponse {
ResponseHeader header = 1;
}
message AuthRoleGrantResponse {
ResponseHeader header = 1;
}
message AuthRoleRevokeResponse {
ResponseHeader header = 1;
}

229
parse/types.go Normal file
View File

@ -0,0 +1,229 @@
// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package parse
import "fmt"
// https://developers.google.com/protocol-buffers/docs/proto3#scalar
type (
ProtoType int
ProtoTypeCpp int
ProtoTypeJava int
ProtoTypePython int
ProtoTypeGo int
ProtoTypeRuby int
ProtoTypeCsharp int
)
const (
Double ProtoType = iota
Float
Int32
Int64
Uint32
Uint64
Sint32
Sint64
Fixed32
Fixed64
Sfixed32
Sfixed64
Bool
String
Bytes
)
var (
ProtoTypes = [...]string{
"double",
"float",
"int32",
"int64",
"uint32",
"uint64",
"sint32",
"sint64",
"fixed32",
"fixed64",
"sfixed32",
"sfixed64",
"bool",
"string",
"bytes",
}
protoTypesMap = map[string]ProtoType{
"double": Double,
"float": Float,
"int32": Int32,
"int64": Int64,
"uint32": Uint32,
"uint64": Uint64,
"sint32": Sint32,
"sint64": Sint64,
"fixed32": Fixed32,
"fixed64": Fixed64,
"sfixed32": Sfixed32,
"sfixed64": Sfixed64,
"bool": Bool,
"string": String,
"bytes": Bytes,
}
ToCpp = map[ProtoType]string{
Double: "double",
Float: "float",
Int32: "int32",
Int64: "int64",
Uint32: "uint32",
Uint64: "uint64",
Sint32: "int32",
Sint64: "int64",
Fixed32: "uint32",
Fixed64: "uint64",
Sfixed32: "int32",
Sfixed64: "int64",
Bool: "bool",
String: "string",
Bytes: "string",
}
ToJava = map[ProtoType]string{
Double: "double",
Float: "float",
Int32: "int",
Int64: "long",
Uint32: "int",
Uint64: "long",
Sint32: "int",
Sint64: "long",
Fixed32: "int",
Fixed64: "long",
Sfixed32: "int32",
Sfixed64: "int64",
Bool: "boolean",
String: "String",
Bytes: "ByteString",
}
ToPython = map[ProtoType]string{
Double: "float",
Float: "float",
Int32: "int",
Int64: "int/long",
Uint32: "int/long",
Uint64: "int/long",
Sint32: "int",
Sint64: "int/long",
Fixed32: "int",
Fixed64: "int/long",
Sfixed32: "int",
Sfixed64: "int/long",
Bool: "boolean",
String: "str/unicode",
Bytes: "str",
}
ToGo = map[ProtoType]string{
Double: "float64",
Float: "float32",
Int32: "int32",
Int64: "int64",
Uint32: "uint32",
Uint64: "uint64",
Sint32: "int32",
Sint64: "int64",
Fixed32: "uint32",
Fixed64: "uint64",
Sfixed32: "int32",
Sfixed64: "int64",
Bool: "bool",
String: "string",
Bytes: "[]byte",
}
ToRuby = map[ProtoType]string{
Double: "Float",
Float: "Float",
Int32: "Fixnum or Bignum (as required)",
Int64: "Bignum",
Uint32: "Fixnum or Bignum (as required)",
Uint64: "Bignum",
Sint32: "Fixnum or Bignum (as required)",
Sint64: "Bignum",
Fixed32: "Fixnum or Bignum (as required)",
Fixed64: "Bignum",
Sfixed32: "Fixnum or Bignum (as required)",
Sfixed64: "Bignum",
Bool: "TrueClass/FalseClass",
String: "String (UTF-8)",
Bytes: "String (ASCII-8BIT)",
}
ToCsharp = map[ProtoType]string{
Double: "double",
Float: "float",
Int32: "int",
Int64: "long",
Uint32: "uint",
Uint64: "ulong",
Sint32: "int",
Sint64: "long",
Fixed32: "uint",
Fixed64: "ulong",
Sfixed32: "int",
Sfixed64: "long",
Bool: "bool",
String: "string",
Bytes: "ByteString",
}
)
// ToProtoType parses string to return 'ProtoType'.
func ToProtoType(s string) (ProtoType, error) {
v, ok := protoTypesMap[s]
if !ok {
return 0, fmt.Errorf("%q is not defined", s)
}
return v, nil
}
func (t ProtoType) String() string {
return ProtoTypes[t]
}
func (t ProtoType) Cpp() string {
return ToCpp[t]
}
func (t ProtoType) Java() string {
return ToJava[t]
}
func (t ProtoType) Python() string {
return ToPython[t]
}
func (t ProtoType) Go() string {
return ToGo[t]
}
func (t ProtoType) Ruby() string {
return ToRuby[t]
}
func (t ProtoType) Csharp() string {
return ToCsharp[t]
}

30
parse/types_test.go Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package parse
import "testing"
func TestTypes(t *testing.T) {
tt, err := ToProtoType("sint32")
if err != nil {
t.Fatal(err)
}
if tt != Sint32 {
t.Fatalf("unexpected %v", tt)
}
if tt.Go() != "int32" {
t.Fatalf("unexpected %s", tt.Go())
}
}

67
parse/util.go Normal file
View File

@ -0,0 +1,67 @@
// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package parse
import (
"os"
"path/filepath"
"strings"
)
// walkDirExt returns all FileInfos with specific extension.
// Make sure to prefix the extension name with dot.
// For example, to find all go files, pass ".go".
func walkDirExt(targetDir, ext string) (map[os.FileInfo]string, error) {
rmap := make(map[os.FileInfo]string)
visit := func(path string, f os.FileInfo, err error) error {
if f != nil {
if !f.IsDir() {
if filepath.Ext(path) == ext {
if !filepath.HasPrefix(path, ".") && !strings.Contains(path, "/.") {
if _, ok := rmap[f]; !ok {
wd, err := os.Getwd()
if err != nil {
return err
}
thepath := filepath.Join(wd, strings.Replace(path, wd, "", -1))
rmap[f] = thepath
}
}
}
}
}
return nil
}
err := filepath.Walk(targetDir, visit)
if err != nil {
return nil, err
}
return rmap, nil
}
func toFile(txt, fpath string) error {
f, err := os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0777)
if err != nil {
f, err = os.Create(fpath)
if err != nil {
return err
}
}
defer f.Close()
if _, err := f.WriteString(txt); err != nil {
return err
}
return nil
}

25
test Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
TEST=./...;
FMT="*.go"
echo "Running tests...";
go test -v -cover -cpu 1,2,4 $TEST;
go test -v -cover -cpu 1,2,4 -race $TEST;
echo "Checking gofmt..."
fmtRes=$(gofmt -l -s $FMT)
if [ -n "${fmtRes}" ]; then
echo -e "gofmt checking failed:\n${fmtRes}"
exit 255
fi
echo "Checking govet..."
vetRes=$(go vet $TEST)
if [ -n "${vetRes}" ]; then
echo -e "govet checking failed:\n${vetRes}"
exit 255
fi
echo "Success";