summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--example/fruit.proto3
-rw-r--r--example/fruit.proto.new77
-rw-r--r--main.go1
-rw-r--r--protoReformat.go161
5 files changed, 241 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 1380f9a..3ac295e 100644
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,7 @@ install: test
GO111MODULE=off go install \
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
-auto:
+proto:
# rm -f auto.pb.go
autogenpb --proto file.proto --package main
# rm -f auto.sort.pb.go auto.newsort.pb.go # auto.marshal.pb.go
diff --git a/example/fruit.proto b/example/fruit.proto
index b119652..6df0b89 100644
--- a/example/fruit.proto
+++ b/example/fruit.proto
@@ -71,7 +71,6 @@ message Fruits { // `autogenpb:marshal` `autogenpb:mutex`
string uuid = 1; // `autogenpb:uuid:be926ad9-f07f-484c-adf2-d96eeabf3079`
string version = 2; // `autogenpb:version:v0.0.1`
repeated Fruit Fruits = 3; // THIS MUST BE "Fruit" and then "Fruit" + "s"
- // you can add additional things here but the three lines above must conform to the standard above
- int64 cost = 4;
+ int64 cost = 4; // you can add additional things here but the three lines above must conform to the standard above
map<string, string> junk = 5;
}
diff --git a/example/fruit.proto.new b/example/fruit.proto.new
new file mode 100644
index 0000000..f9f39a0
--- /dev/null
+++ b/example/fruit.proto.new
@@ -0,0 +1,77 @@
+syntax = "proto3";
+
+// this file is called "fruit.proto"
+//
+// for autogenpb to work, you must have:
+//
+// "Fruit" must exist. you can put anything in it
+//
+// and
+//
+// "Fruits" MUST EXIST and start exactly this way
+// It must be "Fruit" + 's' and must match the name of this file: "fruit.proto"
+
+package main;
+
+import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
+
+message Apple {
+ string name = 1; // `autogenpb:unique` // generates SortByxxx() and AppendUnique() functions
+ string genus = 2; // `autogenpb:unique` // generates same thing here but SortByGenus()
+ google.protobuf.Timestamp ctime = 3; // when the apple was born
+}
+
+message Apples {
+ string name = 1; // `autogenpb:unique` // generates SortByxxx() and AppendUnique() functions
+ string genus = 2; // `autogenpb:unique` // generates same thing here but SortByGenus()
+ repeated Apple apples = 3;
+}
+
+message Pear { // `autogenpb:nomutex`
+ string name = 1; // `autogenpb:sort`
+ string favorite = 2; // `autogenpb:sort` `autogenpb:unique`
+}
+
+message Pears { // `autogenpb:nomutex`
+ string name = 1; // `autogenpb:sort`
+ string favorite = 2; // `autogenpb:sort` `autogenpb:unique`
+ repeated Pear pears = 3;
+}
+
+message Banana { // `autogenpb:nomutex`
+ repeated string name = 1; // `autogenpb:sort`
+ string favorite = 2; // `autogenpb:sort` `autogenpb:unique`
+ string country = 3; // `autogenpb:sort`
+}
+
+message Basket { // `autogenpb:nomutex`
+ repeated string name = 1; // `autogenpb:sort` `autogenpb:unique`
+ string favorite = 2; // `autogenpb:sort` `autogenpb:unique`
+ int64 price = 3; // `autogenpb:sort`
+ repeated Banana banna = 4;
+ repeated Pear pears = 5;
+ repeated Apple stacks = 6;
+}
+
+// "Fruit" must exist. you can put anything in it
+message Fruit {
+ string brand = 1; // `autogenpb:unique` `autogenpb:sort`
+ Apple apples = 2;
+ repeated Pear pears = 3;
+ string UPC = 4; // `autogenpb:sort` `autogenpb:unique`
+ string city = 5; // `autogenpb:sort`
+ Pears notpears = 6;
+ Pears fakepears = 7;
+ repeated Basket gifts = 8;
+}
+
+// "Fruits" MUST EXIST and start exactly this way
+// It must be "Fruit" + 's' and must match the name of this file: "fruit.proto"
+message Fruits { // `autogenpb:marshal` `autogenpb:mutex`
+ string uuid = 1; // `autogenpb:uuid:be926ad9-f07f-484c-adf2-d96eeabf3079`
+ string version = 2; // `autogenpb:version:v0.0.1`
+ repeated Fruit Fruits = 3; // THIS MUST BE "Fruit" and then "Fruit" + "s"
+ int64 cost = 4; // you can add additional things here but the three lines above must conform to the standard above
+ map<string, string> junk = 5;
+}
+
diff --git a/main.go b/main.go
index 78e58a2..cbf8eea 100644
--- a/main.go
+++ b/main.go
@@ -77,6 +77,7 @@ func main() {
log.Info("autogenpb parse error:", err)
badExit(err)
}
+ protoReformat(argv.Proto)
if pf.Bases == nil {
badExit(fmt.Errorf("Base was nil. 'message %s {` did not exist", pf.Filebase))
diff --git a/protoReformat.go b/protoReformat.go
new file mode 100644
index 0000000..26fae1f
--- /dev/null
+++ b/protoReformat.go
@@ -0,0 +1,161 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "strings"
+
+ "go.wit.com/log"
+)
+
+// like 'goimport' but for .proto files
+
+var maxVarname int
+var maxVartype int
+
+func protoReformat(filename string) error {
+ // read in the .proto file
+ data, err := os.ReadFile(filename)
+ if err != nil {
+ log.Info("file read failed", filename, err)
+ return err
+ }
+
+ pf, err := os.OpenFile(filename+".new", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ log.Info("file open error. permissions?", filename, err)
+ return err
+ }
+ defer pf.Close()
+
+ var inMessage bool
+ var curmsg []string
+
+ // gets the max vartype and varname
+ for _, line := range strings.Split(string(data), "\n") {
+ if strings.HasPrefix(line, "message ") {
+ inMessage = true
+ continue
+ }
+
+ // find the end of the message
+ if strings.HasPrefix(line, "}") {
+ inMessage = false
+ formatMessage(curmsg)
+ curmsg = nil
+ continue
+ }
+
+ // don't format or change anything when not in a "message {" section
+ if !inMessage {
+ continue
+ }
+ curmsg = append(curmsg, line)
+ }
+
+ // parse the proto file for message struct names
+ for _, line := range strings.Split(string(data), "\n") {
+ if strings.HasPrefix(line, "message ") {
+ inMessage = true
+ parts := strings.Fields(line)
+ if len(parts) > 3 {
+ start := parts[0] + " " + parts[1] + " " + parts[2]
+ end := strings.Join(parts[3:], " ")
+ offset := maxVarname + maxVartype + 16 - len(start)
+ pad := fmt.Sprintf("%d", offset)
+ hmm := "%s %" + pad + "s %s"
+ line = fmt.Sprintf(hmm, start, " ", end)
+ }
+ fmt.Fprintln(pf, line)
+ continue
+ }
+
+ // find the end of the message
+ if strings.HasPrefix(line, "}") {
+ inMessage = false
+ for _, newline := range formatMessage(curmsg) {
+ fmt.Fprintln(pf, newline)
+ }
+ fmt.Fprintln(pf, line)
+ curmsg = nil
+ continue
+ }
+
+ // don't format or change anything when not in a "message {" section
+ if !inMessage {
+ fmt.Fprintln(pf, line)
+ continue
+ }
+ curmsg = append(curmsg, line)
+ }
+
+ // for i, s := range slices.Backward(pf.ToSort) {
+ return nil
+}
+
+func formatMessage(curmsg []string) []string {
+ var newmsg []string
+
+ // find the max length of varname and vartype
+ for _, line := range curmsg {
+ parts := strings.Split(line, ";")
+ if len(parts) < 2 {
+ log.Info("parse error", line)
+ return curmsg
+ }
+
+ vartype, varname, _, _ := tokenMsgVar(line)
+ if len(vartype) > maxVartype {
+ maxVartype = len(vartype)
+ }
+ if len(varname) > maxVarname {
+ maxVarname = len(varname)
+ }
+ }
+
+ for _, line := range curmsg {
+ mt := fmt.Sprintf("%d", maxVartype)
+ mv := fmt.Sprintf("%d", maxVarname)
+
+ hmm := " %-" + mt + "s %-" + mv + "s = %-3s %s"
+
+ vartype, varname, id, end := tokenMsgVar(line)
+ end = strings.TrimSpace(end)
+ id = id + ";"
+
+ newline := fmt.Sprintf(hmm, vartype, varname, id, end)
+ newmsg = append(newmsg, newline)
+ }
+ return newmsg
+}
+
+// returns vartype, varname, id, end
+func tokenMsgVar(line string) (string, string, string, string) {
+ parts := strings.Split(line, ";")
+ front := parts[0]
+ end := strings.Join(parts[1:], ";")
+
+ var id string
+ var varname string
+ var vartype string
+
+ parts = strings.Fields(front)
+ parts, id = slicesPop(parts)
+ parts, _ = slicesPop(parts) // this is the "=" sign
+ parts, varname = slicesPop(parts)
+ vartype = strings.Join(parts, " ")
+
+ return vartype, varname, id, end
+}
+
+func slicesPop(parts []string) ([]string, string) {
+ if len(parts) == 0 {
+ return nil, ""
+ }
+ if len(parts) == 1 {
+ return nil, parts[0]
+ }
+ x := len(parts)
+ end := parts[x-1]
+ return parts[0 : x-1], end
+}