diff options
| -rw-r--r-- | example/fruit.proto | 78 | ||||
| -rw-r--r-- | example/fruit.proto.new | 14 | ||||
| -rw-r--r-- | file.proto.new | 103 | ||||
| -rw-r--r-- | protoReformat.go | 44 |
4 files changed, 182 insertions, 57 deletions
diff --git a/example/fruit.proto b/example/fruit.proto index 6df0b89..c546fd4 100644 --- a/example/fruit.proto +++ b/example/fruit.proto @@ -16,61 +16,63 @@ 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 + 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; + 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 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 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 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; +message Basket { // `autogenpb:nomutex` + repeated string name = 1; // `autogenpb:sort` `autogenpb:unique` + string favorite = 2; // `autogenpb:sort` `autogenpb:unique` + int64 price = 3; // `autogenpb:sort` + // here for testing padding + + 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; + 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; +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/example/fruit.proto.new b/example/fruit.proto.new index f9f39a0..78f9c22 100644 --- a/example/fruit.proto.new +++ b/example/fruit.proto.new @@ -45,12 +45,14 @@ message Banana { // `autogenpb:nomutex` } 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; + 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 diff --git a/file.proto.new b/file.proto.new new file mode 100644 index 0000000..1bba651 --- /dev/null +++ b/file.proto.new @@ -0,0 +1,103 @@ +syntax = "proto3"; + +// Look at "example/fruit.proto" not this file + +// this file is actually used by autogenpb + +// here are some docs, but probably it's just easier to run +// autogenpb on this file and see what gets autogenerated +// in this directory. All autogenerated files are named *.pb.go + +// the 'uuid' standard at the end is an experiment +// establish a way to identify arbitrary .pb files + +// You can generate Marshal & Unmarshal for any struct (message) you want +// You can generate SortBy and Append functions ONLY FOR 'repeated <message>' +// Also, those structs must be defined in the same file +// Additionally, you must use `autogenpb:mutex` on the parent struct. +// The autogenerated code requires a RW mutex and autogenpb will insert it into the struct + +package main; + +// +// below are the actual structs autogen uses +// autogen parses the .proto file and then store the information +// it needs in these protobuf files, then it processes the +// protobuf files to write out *.sort.pb.go and *.marshal.pb.go files +// +message MsgVar { + string varName = 1; // the variable name + string varType = 2; // the variable type + bool isRepeated = 3; // does the variable repeate + bool hasSort = 4; // marked with sort + bool hasUnique = 5; // marked with unique +} + +message MsgName { + string name = 1; // the name of the message aka struct. for this example: "Shelf" + string lockname = 2; // name of the lockfile. ends in Mu + bool doMarshal = 3; // if msg struct should have Marshal & Unmarshal functions + bool doMutex = 4; // true if a mutex is needed for the message struct + bool doProtocMutex = 5; // an experiment to insert a mutex into the protoc generated msg struct (bad idea?) + bool mutexFound = 6; // true if the mutex was added to the protoc pb.go file + repeated string sort = 7; // keys to sort on + repeated string unique = 8; // if the fields should have AppendUnique() functions + repeated MsgVar vars = 9; // store all the vars in the message + bool needIter = 10; // true if the sort iterator has not been generated yet + bool needAll = 11; // true if the sort iterator has not been generated yet + bool noMutex = 12; // only use the global mutex +} + +message Sort { + string msgName = 1; // `autogenpb:unique` File + string varType = 2; // `autogenpb:unique` MsgName + string varName = 3; // `autogenpb:unique` msgNames, sortNames + string lockname = 4; // + bool needAll = 5; // +} + +message Find { + string parent = 1; // `autogenpb:unique` File + string varType = 2; // `autogenpb:unique` MsgName + string varName = 3; // `autogenpb:unique` msgNames, sortNames + bool needAll = 4; // +} + +message File { + // `autogenpb:var:w io.Writer` + string Package = 1; // whatever the package name is at the top of the .go file + string filename = 2; // yellow.proto + string pbfilename = 3; // yellow.pb.go + string filebase = 4; // yellow + string uuid = 5; // the uuid to use in a func NewMsgName() + string version = 6; // the version to use in a func NewMsgName() + MsgName bases = 7; // the message in "plural" form + MsgName base = 8; // the primary repeated message for the master struct + + // every struct in this proto file, this file has: "Apple", "Apples", ... "File", etc... + repeated MsgName msgNames = 9; + repeated MsgName sortNames = 10; // variables that are repeated can have the standard functions generated (Sort(), etc) + map<string, string> iterMap = 11; + repeated Sort toSort = 12; // variables that are repeated can have the standard functions generated (Sort(), etc) + string goPath = 13; // the version to use in a func NewMsgName() +} + +// I know, I know, the whole point of using protobuf +// is so you don't need a uuid or versions because it's +// inherently forward compatable. nonetheless, a simple stubbed out +// trivial and empty protobuf message can marshal and identify all the files +// also, this could be used to modify /usr/bin/file /usr/share/magic to identify the files +// maybe this is already been done and is pointless, but it seems like a good idea +message Files { // `autogenpb:marshal` + string uuid = 1; // `autogenpb:uuid:6c9ae4dd-648d-4b51-9738-bd59fb8fafd5` + string version = 2; // `autogenpb:version:v0.0.38` + repeated File Files = 3; // an array of each .proto file in the working directory +} + +// this generic message is used by autogen to identify and +// then dump the uuid and version from any arbitrary .pb file +message Identify { // `autogenpb:marshal` + string uuid = 1; // + string version = 2; // +} + diff --git a/protoReformat.go b/protoReformat.go index 26fae1f..580d920 100644 --- a/protoReformat.go +++ b/protoReformat.go @@ -21,15 +21,9 @@ func protoReformat(filename string) error { 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 + var newfile string // gets the max vartype and varname for _, line := range strings.Split(string(data), "\n") { @@ -59,6 +53,7 @@ func protoReformat(filename string) error { inMessage = true parts := strings.Fields(line) if len(parts) > 3 { + // hack to actually indent comments on the message line itself. you're welcome start := parts[0] + " " + parts[1] + " " + parts[2] end := strings.Join(parts[3:], " ") offset := maxVarname + maxVartype + 16 - len(start) @@ -66,29 +61,39 @@ func protoReformat(filename string) error { hmm := "%s %" + pad + "s %s" line = fmt.Sprintf(hmm, start, " ", end) } - fmt.Fprintln(pf, line) + newfile += fmt.Sprintln(line) continue } // find the end of the message if strings.HasPrefix(line, "}") { inMessage = false + // format and write the last message to the file for _, newline := range formatMessage(curmsg) { - fmt.Fprintln(pf, newline) + newfile += fmt.Sprintln(newline) } - fmt.Fprintln(pf, line) + newfile += fmt.Sprintln(line) curmsg = nil continue } // don't format or change anything when not in a "message {" section if !inMessage { - fmt.Fprintln(pf, line) + newfile += fmt.Sprintln(line) continue } curmsg = append(curmsg, line) } + pf, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + log.Info("file open error. permissions?", filename, err) + return err + } + newfile = strings.TrimSpace(newfile) + fmt.Fprintln(pf, newfile) + pf.Close() + // for i, s := range slices.Backward(pf.ToSort) { return nil } @@ -100,8 +105,8 @@ func formatMessage(curmsg []string) []string { for _, line := range curmsg { parts := strings.Split(line, ";") if len(parts) < 2 { - log.Info("parse error", line) - return curmsg + // line is blank or just a comment + continue } vartype, varname, _, _ := tokenMsgVar(line) @@ -114,6 +119,18 @@ func formatMessage(curmsg []string) []string { } for _, line := range curmsg { + line = strings.TrimSpace(line) + if line == "" { + newmsg = append(newmsg, line) + continue + } + if strings.HasPrefix(line, "//") { + pad := fmt.Sprintf("%d", maxVartype+maxVarname+21) + hmm := "%" + pad + "s %s" + line = fmt.Sprintf(hmm, " ", line) // todo: compute 50 + newmsg = append(newmsg, line) + continue + } mt := fmt.Sprintf("%d", maxVartype) mv := fmt.Sprintf("%d", maxVarname) @@ -124,6 +141,7 @@ func formatMessage(curmsg []string) []string { id = id + ";" newline := fmt.Sprintf(hmm, vartype, varname, id, end) + newline = strings.TrimRight(newline, " ") newmsg = append(newmsg, newline) } return newmsg |
