fhelp/protoc.go

144 lines
4.5 KiB
Go

package fhelp
// auto run protoc with the correct args
import (
"bufio"
"fmt"
"os"
"strings"
"github.com/google/uuid"
"go.wit.com/log"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
/*
This verifies a .proto file conforms to the autogenpb standard
That means, for "toy.proto", there MUST exist:
message toy {
}
message toys {
}
this parses the .proto file and handles anything with `autogenpb: `
does the fruit.proto file have "message Fruits"
does it have a Uuid & valid version ?
This returns (UUID, Version, error on failure)
*/
func ValidProtobuf(filename string) (string, string, error) {
filebase := strings.TrimSuffix(filename, ".proto")
base := cases.Title(language.English, cases.NoLower).String(filebase)
pluralBase := base + "s" // to conform to autogenpb, it must have an added 's'
file, err := os.Open(filename)
if err != nil {
return "", "", err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
prefix := "message " + pluralBase + " {"
if !strings.HasPrefix(line, prefix) {
// log.Info("nope", prefix, "line", line)
// nope, not this line
continue
}
scanner.Scan()
line = scanner.Text()
fields := strings.Fields(line)
if len(fields) < 2 {
noUuidExit(filename)
return "", "", fmt.Errorf("proto file does not have a UUID")
}
// log.Info("GOT LINE", line)
if fields[0] == "string" && fields[1] != "uuid" {
noUuidExit(filename)
return "", "", fmt.Errorf("proto file does not have a UUID")
}
// ok, uuid is here
UUID := line
log.Info("found UUID:", line)
scanner.Scan()
line = scanner.Text()
fields = strings.Fields(line)
// log.Info("GOT LINE", line)
if fields[0] == "string" && fields[1] != "version" {
noUuidExit(filename)
return "", "", fmt.Errorf("proto file does not have a version")
}
// found "version", the .proto file conforms
version := line
log.Info("found Version:", line)
return UUID, version, nil
}
// right now, noPluralMessage does os.Exit(-1)
noPluralMessageExit(filename)
return "", "", fmt.Errorf("proto file does not have message %s", pluralBase)
}
func noPluralMessageExit(filename string) {
filebase := strings.TrimSuffix(filename, ".proto")
base := cases.Title(language.English, cases.NoLower).String(filebase)
log.Info("")
log.Info("###########################################################################")
log.Info("Your proto file", filename, "does not contain the correct 'message' definitions")
log.Info("")
log.Info("For autogenpb to work on your file", filename, ", you must have both names exactly:")
log.Info("")
log.Printf("message %s {\n", base)
log.Info("}")
log.Printf("message %s {\n", base+"s")
log.Info("}")
log.Info("")
log.Info("###########################################################################")
badExit(fmt.Errorf("proto file error %s", filename))
}
// 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"
// }
func noUuidExit(filename string) {
filebase := strings.TrimSuffix(filename, ".proto")
base := cases.Title(language.English, cases.NoLower).String(filebase)
id := uuid.New()
log.Info("")
log.Info("###########################################################################")
log.Info("Your proto file", filename, "is incorrect for 'message' ", base+"s")
log.Info("")
log.Info("For autogenpb to work on your file", filename, ",", base+"s must be exactly:")
log.Info("")
log.Info("message", base+"s", "{ // `autogenpb:marshal` `autogenpb:mutex`")
log.Info(" string uuid = 1; // `autogenpb:uuid:" + id.String() + "`")
log.Info(" string version = 2; // `autogenpb:version:v0.0.1`")
log.Info(" repeated", base, base+"s", " = 3; // THIS MUST BE ", base, " and then ", base+"s")
log.Info("}")
log.Info("")
log.Info("If you don't have a UUID, you can use the randomly generated one here")
log.Info("")
log.Info("###########################################################################")
badExit(fmt.Errorf("proto file error %s", filename))
}
func userInstructions() {
log.Info("This is likely because you don't have protoc and protoc-gen-go installed")
log.Info("")
log.Info("On debian, you can:")
log.Info(" apt install protobuf-compiler # for protoc")
log.Info(" apt install protoc-gen-go # for protoc-gen-go")
log.Info("")
}