goimport for protobuf

This commit is contained in:
Jeff Carr 2025-02-01 06:54:55 -06:00
parent e678606ea2
commit cfedee740c
5 changed files with 241 additions and 3 deletions

View File

@ -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

View File

@ -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;
}

77
example/fruit.proto.new Normal file
View File

@ -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;
}

View File

@ -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))

161
protoReformat.go Normal file
View File

@ -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
}