make a protofile for the app itself

that turns out to be a lot of fun!
This commit is contained in:
Jeff Carr 2025-01-08 19:45:48 -06:00
parent 0a1eb821e9
commit 3fe2fde185
8 changed files with 89 additions and 72 deletions

View File

@ -1,20 +1,37 @@
VERSION = $(shell git describe --tags) VERSION = $(shell git describe --tags)
BUILDTIME = $(shell date +%Y.%m.%d) BUILDTIME = $(shell date +%Y.%m.%d_%H%M)
run: goimports vet install test: goimports build auto
full: clean goimports auto vet install
vet: vet:
@GO111MODULE=off go vet @GO111MODULE=off go vet
@echo this go binary package should build okay @echo this go binary package should build okay
cleanbuild:
rm -f auto.marshal.pb.go auto.sort.pb.go autogenpb
build: build:
GO111MODULE=off go build \ GO111MODULE=off go build \
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}" -ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
bak:
mv -f autogenpb autogenpb.last
install: install:
GO111MODULE=off go install \ GO111MODULE=off go install \
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}" -ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
auto.pb.go: auto.proto
./autogenpb --proto auto.proto --package testfiles
rm -f auto.sort.pb.go auto.marshal.pb.go
auto:
cd testfiles; rm -f go.* *.pb.go
cd testfiles; ../autogenpb --proto auto.proto --package yellow
cd testfiles; GO111MODULE=off go vet
goimports: goimports:
goimports -w *.go goimports -w *.go
@ -25,8 +42,7 @@ redomod:
go mod edit -go=1.20 go mod edit -go=1.20
reset: reset:
# clear your terminal -rm -f auto.sort.pb.go
reset
clean: clean:
-rm -f go.* -rm -f go.*

View File

@ -13,8 +13,8 @@ import (
"go.wit.com/log" "go.wit.com/log"
) )
func addMutex(names map[string]string) error { func (pb *Files) addMutex(f *File) error {
fullname := names["protobase"] + ".pb.go" fullname := f.Filebase + ".pb.go"
log.Info("fullname:", fullname) log.Info("fullname:", fullname)
data, err := os.ReadFile(fullname) data, err := os.ReadFile(fullname)
if err != nil { if err != nil {
@ -22,14 +22,21 @@ func addMutex(names map[string]string) error {
return err return err
} }
w, _ := os.OpenFile(names["protobase"]+".pb.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) w, _ := os.OpenFile(f.Filebase+".pb.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
var found bool var found bool
lines := strings.Split(string(data), "\n") lines := strings.Split(string(data), "\n")
for _, line := range lines { for _, line := range lines {
if strings.HasPrefix(line, "package ") {
log.Info("CHANGING package:", line, "to package:", f.Package)
fmt.Fprintln(w, "package "+f.Package)
// log.Info("CHANGING package:", line, "to package:main")
// fmt.Fprintln(w, "package "+"main")
continue
}
// log.Info("line:", line) // log.Info("line:", line)
start := "type " + names["Bases"] + " struct {" start := "type " + "sunshine" + " struct {"
if strings.HasSuffix(line, start) { if strings.HasSuffix(line, start) {
found = true found = true
log.Info("FOUND line:", line) log.Info("FOUND line:", line)

View File

@ -1,21 +0,0 @@
syntax = "proto3";
// experiment to identify .pb files incase things go sideways
package autogenpb;
message Apple { // `autogenpb:marshal`
string name = 1; // `autogenpb:unique` // generates SortByName() functions
string genus = 2; // `autogenpb:unique` // generates SortByGenus() functions
}
// autogenpb:no-sort // means don't generate sort functions
message Apples { // `autogenpb:marshal`
string uuid = 1; // could be useful for /usr/share/file/magic someday?
string version = 2; // could be used for protobuf schema change violations?
}
// `autogenpb:no-sort autogenpb:no-marshal` // means don't generate sort functions
message Pears {
string uuid = 1; // could be useful for /usr/share/file/magic someday?
string version = 2; // could be used for protobuf schema change violations?
}

View File

@ -9,6 +9,7 @@ package main
var argv args var argv args
type args struct { type args struct {
Package string `arg:"--package" help:"the package name"`
LoBase string `arg:"--lobase" help:"lowercase basename"` LoBase string `arg:"--lobase" help:"lowercase basename"`
UpBase string `arg:"--upbase" help:"uppercase basename"` UpBase string `arg:"--upbase" help:"uppercase basename"`
Proto string `arg:"--proto" help:"the .proto filename"` Proto string `arg:"--proto" help:"the .proto filename"`

View File

@ -6,7 +6,8 @@ import (
) )
func headerComment(w io.Writer) { func headerComment(w io.Writer) {
fmt.Fprintln(w, "") // technically this should be the first line and in this exact format:
fmt.Fprintln(w, "// Code generated by go.wit.com/apps/autogenpb. DO NOT EDIT.")
fmt.Fprintln(w, "// This file was autogenerated with autogenpb", VERSION, "DO NOT EDIT") fmt.Fprintln(w, "// This file was autogenerated with autogenpb", VERSION, "DO NOT EDIT")
fmt.Fprintln(w, "// go install go.wit.com/apps/autogenpb@latest") fmt.Fprintln(w, "// go install go.wit.com/apps/autogenpb@latest")
fmt.Fprintln(w, "//") fmt.Fprintln(w, "//")
@ -23,8 +24,9 @@ func headerComment(w io.Writer) {
} }
func header(w io.Writer, names map[string]string) { func header(w io.Writer, names map[string]string) {
fmt.Fprintln(w, "package "+names["package"]) // header must come first
headerComment(w) headerComment(w)
fmt.Fprintln(w, "package "+names["package"])
fmt.Fprintln(w, "import (") fmt.Fprintln(w, "import (")
fmt.Fprintln(w, " \"fmt\"") fmt.Fprintln(w, " \"fmt\"")
fmt.Fprintln(w, " \"sort\"") fmt.Fprintln(w, " \"sort\"")

55
main.go
View File

@ -28,6 +28,9 @@ var uniqueKeys []string
func main() { func main() {
pp := arg.MustParse(&argv) pp := arg.MustParse(&argv)
var pb *Files
pb = new(Files)
// you need a proto file // you need a proto file
if argv.Proto == "" { if argv.Proto == "" {
log.Info("you must provide --proto <filename>") log.Info("you must provide --proto <filename>")
@ -47,10 +50,9 @@ func main() {
os.Exit(-1) os.Exit(-1)
} }
if err := findGlobalAutogenpb(argv.Proto); err != nil { f := new(File)
log.Info("autogenpb parse error:", err) pb.Files = append(pb.Files, f)
os.Exit(-1) f.Filename = argv.Proto
}
// todo, look for go.work files // todo, look for go.work files
if argv.GoSrc == "" { if argv.GoSrc == "" {
@ -65,45 +67,42 @@ func main() {
} }
log.Info(argv.GoSrc, argv.GoPath) log.Info(argv.GoSrc, argv.GoPath)
pwd, _ := os.Getwd()
log.Info("pwd = ", pwd)
if !shell.Exists("go.sum") { if !shell.Exists("go.sum") {
shell.RunQuiet([]string{"go", "mod", "init"}) shell.RunQuiet([]string{"go", "mod", "init"})
shell.RunQuiet([]string{"go", "mod", "tidy"}) shell.RunQuiet([]string{"go", "mod", "tidy"})
shell.RunQuiet([]string{"go", "mod", "edit", "-go=1.18"}) // TODO: make this a global shell.RunQuiet([]string{"go", "mod", "edit", "-go=1.18"}) // TODO: pass this as ENV. verify protobuf version needed
} }
var packageName string
var result cmd.Status var result cmd.Status
var cmd []string var cmd []string
// if forge.IsGoWork() { if argv.Package == "" {
if false {
cmd = []string{"go", "work", "use"}
result = shell.Run(cmd)
log.Info(strings.Join(result.Stdout, "\n"))
log.Info(strings.Join(result.Stderr, "\n"))
if !shell.Exists("go.mod") {
cmd = []string{"go", "mod", "init"}
result = shell.Run(cmd)
log.Info(strings.Join(result.Stdout, "\n"))
log.Info(strings.Join(result.Stderr, "\n"))
}
cmd = []string{"go", "list", "-f", "'{{.Name}}'"}
result = shell.Run(cmd)
log.Info(strings.Join(result.Stdout, "\n"))
log.Info(strings.Join(result.Stderr, "\n"))
} else {
// TODO: switch to using forgepb // TODO: switch to using forgepb
// switch to forgepb // switch to forgepb
os.Setenv("GO111MODULE", "off") // keeps go list working if go version is back versioned for compatability os.Setenv("GO111MODULE", "off") // keeps go list working if go version is back versioned for compatability
cmd = []string{"go", "list", "-f", "'{{.Name}}'"} cmd = []string{"go", "list", "-f", "'{{.Name}}'"}
result = shell.RunQuiet(cmd) result = shell.RunQuiet(cmd)
os.Unsetenv("GO111MODULE") os.Unsetenv("GO111MODULE")
}
packageName := strings.Join(result.Stdout, "\n") packageName = strings.Join(result.Stdout, "\n")
packageName = strings.TrimSpace(packageName) packageName = strings.TrimSpace(packageName)
packageName = strings.Trim(packageName, "'") packageName = strings.Trim(packageName, "'")
// log.Info("packageName == ", packageName) // log.Info("packageName == ", packageName)
} else {
packageName = argv.Package
}
f.Package = packageName
protobase := strings.TrimSuffix(argv.Proto, ".proto") protobase := strings.TrimSuffix(argv.Proto, ".proto")
f.Filebase = protobase
if err := pb.findGlobalAutogenpb(f); err != nil {
log.Info("autogenpb parse error:", err)
os.Exit(-1)
}
sortmap = make(map[string]string) sortmap = make(map[string]string)
sortmap["package"] = packageName sortmap["package"] = packageName
@ -132,19 +131,26 @@ func main() {
} }
// parse sort & marshal options from the .proto file // parse sort & marshal options from the .proto file
// this goes through the .proto files and looks
// for `autogenpb: ` lines
if err := findAutogenpb(sortmap); err != nil { if err := findAutogenpb(sortmap); err != nil {
log.Info("autogenpb parse error:", err) log.Info("autogenpb parse error:", err)
os.Exit(-1) os.Exit(-1)
} }
// try to make foo.pb.go with protoc if it's not here // try to make foo.pb.go with protoc if it's not here
// this is helpful because the protoc-gen-go lines
// are also annoying to code by hand
sortmap["protoc"] = protobase + ".pb.go" sortmap["protoc"] = protobase + ".pb.go"
if !shell.Exists(sortmap["protoc"]) { if !shell.Exists(sortmap["protoc"]) {
if err := protocBuild(sortmap); err != nil { if err := protocBuild(sortmap); err != nil {
log.Info("protoc build error:", err) log.Info("protoc build error:", err)
os.Exit(-1) os.Exit(-1)
} }
pb.addMutex(f)
os.Exit(0)
/*
// experiment to add a mutex to the structs. // experiment to add a mutex to the structs.
// this might fix my other not so great lock implementation on sort (?) // this might fix my other not so great lock implementation on sort (?)
// seems to work, but proto.Marshal() breaks with nil reference // seems to work, but proto.Marshal() breaks with nil reference
@ -158,6 +164,7 @@ func main() {
sortmap["mutex"] = "false" sortmap["mutex"] = "false"
} }
} }
*/
} }
// if foo.pb.go still doesn't exist, protoc failed // if foo.pb.go still doesn't exist, protoc failed

View File

@ -43,10 +43,10 @@ func findAutogenpb(names map[string]string) error {
return nil return nil
} }
func findGlobalAutogenpb(filename string) error { func (pb *Files) findGlobalAutogenpb(f *File) error {
// log.Info("starting findAutogenpb() on", filename) // log.Info("starting findAutogenpb() on", filename)
// read in the .proto file // read in the .proto file
data, err := os.ReadFile(filename) data, err := os.ReadFile(f.Filename)
if err != nil { if err != nil {
// log.Info("open config file :", err) // log.Info("open config file :", err)
return err return err

View File

@ -42,6 +42,11 @@ func protocBuild(names map[string]string) error {
pwd, _ := os.Getwd() pwd, _ := os.Getwd()
log.Info("go.Getwd()", pwd) log.Info("go.Getwd()", pwd)
if !strings.HasPrefix(pwd, argv.GoSrc) { if !strings.HasPrefix(pwd, argv.GoSrc) {
log.Info("are you building using a go.work file? If so,")
log.Info("your paths will not match because the default")
log.Info("is to use ~/go/src so you have to specify")
log.Info("where your path is with --go-src")
log.Info("todo: use forgepb to figure this out")
return errors.New("paths don't match") return errors.New("paths don't match")
} }
gopath := strings.TrimPrefix(pwd, argv.GoSrc) gopath := strings.TrimPrefix(pwd, argv.GoSrc)