refactor again. I want to make this clean

as clean as possible because, I use this tool alot. everywhere.
	I want it to always work. I need do not want it to break
This commit is contained in:
Jeff Carr 2025-01-12 01:32:52 -06:00
parent 0d2dc9fb25
commit cfd9ec5ccd
10 changed files with 541 additions and 72 deletions

View File

@ -1,15 +1,27 @@
VERSION = $(shell git describe --tags) VERSION = $(shell git describe --tags)
BUILDTIME = $(shell date +%Y.%m.%d_%H%M) BUILDTIME = $(shell date +%Y.%m.%d_%H%M)
simple: build simple: test
make -C example clean simpleMutexGlobal goimports vet # make -C example clean simpleMutexGlobal goimports vet
make -C example clean simpleMutexProtoc goimports vet # make -C example clean simpleMutexProtoc goimports vet
# make -C example deleteproto # make -C example deleteproto
full: install clean auto goimports vet build test install full: install clean auto goimports vet build test install
@echo everything worked and the example ran @echo everything worked and the example ran
test: goimports build test
# if this passes, it should be OK to 'go install'
test:
reset
make goimports vet build
make -C example testGlobal
make -C example testProtoc
dryrun: build
make -C example dryrun
dryrun-clean: clean auto build
make -C example dryrun
vet: vet:
@GO111MODULE=off go vet @GO111MODULE=off go vet
@ -31,7 +43,7 @@ build: goimports
bak: bak:
mv -f autogenpb autogenpb.last mv -f autogenpb autogenpb.last
install: install: test
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}"
@ -40,12 +52,6 @@ auto:
autogenpb --proto file.proto --package main autogenpb --proto file.proto --package main
# rm -f auto.sort.pb.go auto.newsort.pb.go # auto.marshal.pb.go # rm -f auto.sort.pb.go auto.newsort.pb.go # auto.marshal.pb.go
test:
make -C example rawproto
# The Go Protocol Buffers library embeds a sync.Mutex within the MessageState struct to prevent unintended shallow copies of message structs
# It only fails in Marshal() functions though. That is dumb.
make -C example modproto # THIS DOES NOT WORK. It could work however. This autogenerated code could be used to debug it.
junk: junk:
cd example; rm -f go.* *.pb.go cd example; rm -f go.* *.pb.go
cd example; ../autogenpb --proto file.proto --package yellow cd example; ../autogenpb --proto file.proto --package yellow

View File

@ -4,6 +4,20 @@ BUILDTIME = $(shell date +%Y.%m.%d_%H%M)
all: clean simpleMutexProtoc goimports build all: clean simpleMutexProtoc goimports build
./example ./example
# if this passes, then autogenpb should be working
# and it is OK to 'go install' the binary
test: testGlobal testProtoc
testGlobal:
make clean
../autogenpb --proto fruit.proto --package main --mutex=false # first build with a global mutex
make build
testProtoc:
make clean
../autogenpb --proto fruit.proto --package main # inserts mutex into protoc .pb.go file
make build
modproto: clean withMutex goimports vet build modproto: clean withMutex goimports vet build
./example ./example
@ -47,6 +61,10 @@ withoutMutex: clean
../autogenpb --proto file.proto --package main --mutex=false ../autogenpb --proto file.proto --package main --mutex=false
../autogenpb --proto patchset.proto --package main --mutex=false ../autogenpb --proto patchset.proto --package main --mutex=false
dryrun:
../autogenpb --proto fruit.proto --package main --dry-run
# ../autogenpb --proto file.proto --package main
goimports: goimports:
goimports -w *.go goimports -w *.go

View File

@ -41,6 +41,7 @@ message MsgName {
repeated string sort = 7; // keys to sort on repeated string sort = 7; // keys to sort on
repeated string unique = 8; // if the fields should have AppendUnique() functions repeated string unique = 8; // if the fields should have AppendUnique() functions
repeated MsgVar vars = 9; // store all the vars in the message repeated MsgVar vars = 9; // store all the vars in the message
bool needIter = 10; // true if the sort iterator has not been generated yet
} }
message File { message File {

View File

@ -22,8 +22,23 @@ message Apple { // `autogenpb:marshal`
} }
message Pear { message Pear {
string name = 1; // string name = 1; // `autogenpb:sort`
string favorite = 2; // `autogenpb:sort` string favorite = 2; // `autogenpb:sort` `autogenpb:unique`
}
message Banana {
repeated string name = 1; // `autogenpb:sort`
string favorite = 2; // `autogenpb:sort` `autogenpb:unique`
string country = 3; // `autogenpb:sort`
}
message Basket {
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 // "Fruit" must exist. you can put anything in it
@ -33,6 +48,9 @@ message Fruit { // `autogenpb:marshal`
repeated Pear pears = 3; repeated Pear pears = 3;
string UPC = 4; // `autogenpb:sort` `autogenpb:unique` string UPC = 4; // `autogenpb:sort` `autogenpb:unique`
string city = 5; // `autogenpb:sort` string city = 5; // `autogenpb:sort`
repeated Pear notpears = 6;
repeated Pear fakepears = 7;
repeated Basket gifts = 8;
} }
// "Fruits" MUST EXIST and start exactly this way // "Fruits" MUST EXIST and start exactly this way
@ -43,4 +61,5 @@ message Fruits { // `autogenpb:marshal` `autogenpb:mutex`
repeated Fruit Fruits = 3; // THIS MUST BE "Fruit" and then "Fruit" + "s" 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 // you can add additional things here but the three lines above must conform to the standard above
int64 cost = 4; int64 cost = 4;
map<string, string> junk = 5;
} }

View File

@ -43,9 +43,27 @@ message MsgName {
repeated string sort = 7; // keys to sort on repeated string sort = 7; // keys to sort on
repeated string unique = 8; // if the fields should have AppendUnique() functions repeated string unique = 8; // if the fields should have AppendUnique() functions
repeated MsgVar vars = 9; // store all the vars in the message 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
}
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 { message File {
// `autogenpb:var:w io.Writer`
string Package = 1; // whatever the package name is at the top of the .go file string Package = 1; // whatever the package name is at the top of the .go file
string filename = 2; // yellow.proto string filename = 2; // yellow.proto
string pbfilename = 3; // yellow.pb.go string pbfilename = 3; // yellow.pb.go
@ -58,6 +76,8 @@ message File {
// every struct in this proto file, this file has: "Apple", "Apples", ... "File", etc... // every struct in this proto file, this file has: "Apple", "Apples", ... "File", etc...
repeated MsgName msgNames = 9; repeated MsgName msgNames = 9;
repeated MsgName sortNames = 10; // variables that are repeated can have the standard functions generated (Sort(), etc) 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)
} }
// I know, I know, the whole point of using protobuf // I know, I know, the whole point of using protobuf

View File

@ -15,19 +15,212 @@ import (
func (pb *Files) makeNewSortfile(pf *File) error { func (pb *Files) makeNewSortfile(pf *File) error {
wSort, _ := os.OpenFile(pf.Filebase+".sort.pb.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) wSort, _ := os.OpenFile(pf.Filebase+".sort.pb.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
defer wSort.Close() defer wSort.Close()
wFind, _ := os.OpenFile(pf.Filebase+".find.pb.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
defer wFind.Close()
header(wSort, pf) header(wSort, pf)
pf.syncLock(wSort)
// pf.Base.iterTop(wSort) log.Printf("START ITERATORS\n")
// pf.Base.iterNext(wSort) // add iterators for all the structs to be used
// pf.selectAllFunc(wSort) for i, msg := range pf.allMsg() {
// pf.iterSelect(wSort) PARENT := msg.Name
LOCK := msg.Lockname
// pf.sortByFunc(wSort, pf.Bases, pf.Base) funcdef := newIter(wSort, msg)
log.Printf("ITER: %-2d %20s %20s %20s %20s %s\n", i, PARENT, "", "", LOCK, funcdef)
}
log.Printf("END ITERATORS\n")
log.Printf("\n")
log.Printf("START COMPARE\n")
for i, msg := range pf.allMsg() {
PARENT := msg.Name
for _, v := range msg.Vars {
if !v.HasSort {
continue
}
VARNAME := v.VarName
funcdef := newSortType(wSort, PARENT, VARNAME)
log.Printf("TYPE: %-2d %20s %20s %20s %10s %s\n", i, PARENT, "", "", "", funcdef)
}
}
log.Printf("END COMPARE\n")
log.Printf("\n")
// add selectAll() functions for all the sort combinations that will be used
for i, s := range pf.ToSort {
// log.Printf("SORT: %-2d %20s %20s %20s %20s\n", i, s.MsgName, s.VarType, s.VarName, s.Lockname)
FRUIT := s.MsgName
APPLE := s.VarType
APPLES := s.VarName
LOCK := s.Lockname
funcdef := newIterAll(wSort, FRUIT, APPLE, APPLES, LOCK)
log.Printf("JUNK: %-2d %20s %20s %20s %20s %s\n", i, FRUIT, APPLE, "", LOCK, funcdef)
}
log.Printf("\n")
// make the sort iterators selectAll()
for i, s := range pf.ToSort {
PARENT := s.MsgName
CHILD := s.VarType
VARNAME := s.VarName
LOCK := s.Lockname
funcdef := addSelectAll(wSort, PARENT, CHILD, VARNAME, LOCK)
log.Printf("SORT: %-2d %20s %20s %20s %20s %s\n", i, PARENT, CHILD, VARNAME, LOCK, funcdef)
}
log.Printf("\n")
// make Len()
for _, msg := range pf.allMsg() {
PARENT := msg.Name
LOCK := msg.Lockname
for i, v := range msg.Vars {
if v.IsRepeated {
CHILD := v.VarType
VARNAME := v.VarName
// funcdef := "func (x *" + PARENT + ") Len" + VARNAME + "() int " + CHILD + " name:" + VARNAME
if PARENT == VARNAME {
// special case
funcdef := addLenFunc(wSort, PARENT, VARNAME, LOCK) // + " " + v.VarType + " name:" + v.VarName
funcdef += " # is special struct=varname"
log.Printf("LEN: %-2d %20s %20s %20s %20s %s\n", i, PARENT, CHILD, VARNAME, LOCK, funcdef)
}
}
}
}
log.Printf("\n")
log.Printf(" %-2s %20s %20s %20s %20s\n", "", "PARENT STRUCT", "VAR STRUCT TYPE", "VAR NAME", "LOCK")
// for i, s := range slices.Backward(pf.ToSort) {
for i, s := range pf.ToSort {
var funcname string
PARENT := s.MsgName
CHILD := s.VarType
VARNAME := s.VarName
LOCK := s.Lockname
log.Printf("SORT: %-2d %20s %20s %20s %20s %s\n", i, PARENT, CHILD, VARNAME, LOCK, "")
var FUNCTYPE string
if PARENT == VARNAME {
FUNCTYPE = PARENT
} else {
FUNCTYPE = VARNAME
}
if PARENT == VARNAME {
funcname := addAllFunc(wSort, PARENT, CHILD, VARNAME)
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "done", "", funcname)
}
if s.VarType+"s" == s.VarName {
funcname = "func (x *" + FUNCTYPE + ") All() *[]iter" + s.VarType
} else {
funcname = "func (x *" + FUNCTYPE + ") all" + s.VarName + "() *[]iter" + s.VarType
}
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
msg := pf.findMsg(s.VarType)
if msg == nil {
return fmt.Errorf("failed to find struct %s", s.VarType)
}
for _, v := range msg.Vars {
if v.HasSort {
funcname := "func (x *" + FUNCTYPE + ") SortBy" + v.VarName + "(" + v.VarType + ") *[]iter" + s.VarType
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
// funcdef := "func (x *"+FRUIT+") SortBy"+COLOR+"() *"+APPLE+"Iterator"
if v.VarType == "string" {
funcdef := newSortBy(wSort, FUNCTYPE, CHILD, VARNAME, v.VarName)
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcdef)
} else {
funcname := "func (x *" + FUNCTYPE + ") SortBy" + v.VarName + "(" + v.VarType + ") *[]iter" + s.VarType + " # can not do this yet"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
}
var ucount int
for _, v := range msg.Vars {
if v.HasUnique {
ucount += 1
funcname := "func (x *" + FUNCTYPE + ") AppendUnique" + v.VarName + "(" + v.VarType + ")"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
for _, v := range msg.Vars {
if v.HasUnique {
funcname := "func (x *" + FUNCTYPE + ") DeleteBy" + v.VarName + "(" + v.VarType + ") bool"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
for _, v := range msg.Vars {
if v.HasUnique {
funcname = "func (x *" + FUNCTYPE + ") FindBy" + v.VarName + "(a " + v.VarType + ") *" + s.VarType + "(using" + v.VarName + ")"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
} else {
if v.VarType == "string" {
funcname = "func (x *" + FUNCTYPE + ") FindBy" + v.VarName + "(a string) []*" + s.VarType + " ???"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
}
if ucount == 1 {
for _, v := range msg.Vars {
if !v.HasUnique {
continue
}
funcname = "func (x *" + FUNCTYPE + ") Insert(a *" + v.VarType + ") (*" + CHILD + ", isNew bool)"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
if ucount > 1 {
funcname = "func (x *" + FUNCTYPE + ") Insert(a *" + CHILD + ") (*" + CHILD + ", isNew bool)"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
/*
// everything struct used in here needs a sort iterator (but just one)
for FRUIT, APPLE := range pf.IterMap {
msg := pf.findMsg(FRUIT)
if msg == nil {
return fmt.Errorf("failed to find struct %s", FRUIT)
}
log.Printf("Add newIter() message %s\n", FRUIT)
newIter(wSort, msg)
child := pf.findMsg(APPLE)
if child == nil {
return fmt.Errorf("failed to find struct %s", APPLE)
}
log.Printf("Add newIter() message %s\n", APPLE)
newIter(wSort, child)
// now add the allKEY() functions
msg.newIterAll(wSort, FRUIT, APPLE)
}
*/
/*
log.Info("START")
log.Printf("Add all() FRUIT=%s APPLE=%s\n", FRUIT, APPLE)
addAllFunc(w, FRUIT, APPLE, LOCK)
log.Printf("Add len() FRUIT=%s APPLES=%s\n", FRUIT, APPLES)
addLenFunc(w, FRUIT, APPLES, LOCK)
log.Printf("Add selectAll() FRUIT=%s APPLE=%s APPLES=%s\n", FRUIT, APPLE, APPLES)
addSelectAll(w, FRUIT, APPLE, APPLES, LOCK)
// newIter(w, FRUIT, APPLE, APPLES, LOCK)
log.Info("END")
*/
/*
return nil
pf.newGenerateSort(wSort, pf.Bases) pf.newGenerateSort(wSort, pf.Bases)
pf.newGenerateSort(wSort, pf.Base) pf.newGenerateSort(wSort, pf.Base)
*/
/* /*
pf.appendUnique(wFind) // Append() enforce no unique keys pf.appendUnique(wFind) // Append() enforce no unique keys
@ -39,8 +232,10 @@ func (pb *Files) makeNewSortfile(pf *File) error {
pf.findFunc(wFind) pf.findFunc(wFind)
*/ */
/*
wFind, _ := os.OpenFile(pf.Filebase+".find.pb.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
defer wFind.Close()
header(wFind, pf) header(wFind, pf)
pf.syncLock(wFind)
pf.specialBases(wFind) pf.specialBases(wFind)
// attempt to add sort functions for pf.Base // attempt to add sort functions for pf.Base
@ -50,33 +245,46 @@ func (pb *Files) makeNewSortfile(pf *File) error {
if err := pf.processMessage(pf.Base, wSort, wFind); err != nil { if err := pf.processMessage(pf.Base, wSort, wFind); err != nil {
return err return err
} }
*/
return nil return nil
} }
/*
func addIterNew(w io.Write, msg *MsgName {
var FRUIT string = parent.Name
var LOCK string = parent.Lockname
newIter(w, FRUIT, APPLE, APPLES, LOCK)
}
*/
func (pf *File) newGenerateSort(w io.Writer, parent *MsgName) error { func (pf *File) newGenerateSort(w io.Writer, parent *MsgName) error {
var FRUIT string = parent.Name var FRUIT string = parent.Name
var LOCK string = parent.Lockname var LOCK string = parent.Lockname
var allLen bool
for _, v := range parent.Vars { for _, v := range parent.Vars {
if !v.IsRepeated { if !v.IsRepeated {
continue continue
} }
var APPLES string = v.VarName var APPLES string = v.VarName
var APPLE string = v.VarType var APPLE string = v.VarType
if !allLen {
// only can run these once for now
addAllFunc(w, FRUIT, APPLE, LOCK)
addLenFunc(w, FRUIT, APPLES, LOCK)
allLen = true
}
addSelectAll(w, FRUIT, APPLE, APPLES, LOCK)
newIter(w, FRUIT, APPLE, APPLES, LOCK)
msg := pf.findMsg(APPLE) msg := pf.findMsg(APPLE)
if msg == nil { if msg == nil {
return fmt.Errorf("failed to find struct %s", APPLE) return fmt.Errorf("failed to find struct %s", APPLE)
} }
if msg.NeedIter {
parent.NeedIter = false
// only can run these once for now
log.Info("START")
log.Printf("Add all() FRUIT=%s APPLE=%s\n", FRUIT, APPLE)
// addAllFunc(w, FRUIT, APPLE, LOCK)
log.Printf("Add len() FRUIT=%s APPLES=%s\n", FRUIT, APPLES)
addLenFunc(w, FRUIT, APPLES, LOCK)
log.Printf("Add selectAll() FRUIT=%s APPLE=%s APPLES=%s\n", FRUIT, APPLE, APPLES)
addSelectAll(w, FRUIT, APPLE, APPLES, LOCK)
// newIter(w, FRUIT, APPLE, APPLES, LOCK)
log.Info("END")
}
for _, v := range msg.Vars { for _, v := range msg.Vars {
if !v.HasSort { if !v.HasSort {
continue continue
@ -104,6 +312,16 @@ func (pf *File) findMsg(s string) *MsgName {
return nil return nil
} }
func (pf *File) allMsg() []*MsgName {
var all []*MsgName
all = append(all, pf.Bases)
all = append(all, pf.Base)
for _, msg := range pf.MsgNames {
all = append(all, msg)
}
return all
}
func (pf *File) specialBases(wFind io.Writer) { func (pf *File) specialBases(wFind io.Writer) {
var FRUIT string = cases.Title(language.English, cases.NoLower).String(pf.Bases.Name) var FRUIT string = cases.Title(language.English, cases.NoLower).String(pf.Bases.Name)
var APPLES string = cases.Title(language.English, cases.NoLower).String(pf.Bases.Name) var APPLES string = cases.Title(language.English, cases.NoLower).String(pf.Bases.Name)

View File

@ -5,16 +5,11 @@ import (
"io" "io"
) )
// only make one of these for each message in the protobuf file func newIterAll(w io.Writer, FRUIT, APPLE, APPLES, LOCK string) string {
func newIter(w io.Writer, FRUIT, APPLE, APPLES, LOCK string) { funcdef := "func (x *" + FRUIT + ") all" + APPLES + "() []*" + APPLE + " {"
fmt.Fprintln(w, "// DEFINE THE ITERATOR. is unique to the "+APPLE+" protobuf message")
fmt.Fprintln(w, "// itializes a new iterator.")
fmt.Fprintln(w, "func New"+APPLE+"Iterator(things []*"+APPLE+") *"+APPLE+"Iterator {")
fmt.Fprintln(w, " return &"+APPLE+"Iterator{things: things}")
fmt.Fprintln(w, "}")
fmt.Fprintln(w, "")
fmt.Fprintln(w, "// safely returns a slice of pointers to the FRUIT protobufs") fmt.Fprintln(w, "// safely returns a slice of pointers to the FRUIT protobufs")
fmt.Fprintln(w, "func (x *"+FRUIT+") all"+APPLES+"() []*"+APPLE+" {") fmt.Fprintln(w, funcdef)
fmt.Fprintln(w, " "+LOCK+".RLock()") fmt.Fprintln(w, " "+LOCK+".RLock()")
fmt.Fprintln(w, " defer "+LOCK+".RUnlock()") fmt.Fprintln(w, " defer "+LOCK+".RUnlock()")
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
@ -28,6 +23,26 @@ func newIter(w io.Writer, FRUIT, APPLE, APPLES, LOCK string) {
fmt.Fprintln(w, " return tmp") fmt.Fprintln(w, " return tmp")
fmt.Fprintln(w, "}") fmt.Fprintln(w, "}")
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
return funcdef
}
// only make one of these for each message in the protobuf file
func newIter(w io.Writer, msg *MsgName) string {
if !msg.NeedIter {
return "iter already done for " + msg.Name
}
msg.NeedIter = false
APPLE := msg.Name
funcdef := "func New" + APPLE + "Iterator(things []*" + APPLE + ") *" + APPLE + "Iterator"
fmt.Fprintln(w, "// DEFINE THE", APPLE, "ITERATOR.")
fmt.Fprintln(w, "// itializes a new iterator.")
fmt.Fprintln(w, funcdef, "{")
fmt.Fprintln(w, " return &"+APPLE+"Iterator{things: things}")
fmt.Fprintln(w, "}")
fmt.Fprintln(w, "")
fmt.Fprintln(w, "type "+APPLE+"Iterator struct {") fmt.Fprintln(w, "type "+APPLE+"Iterator struct {")
fmt.Fprintln(w, " sync.RWMutex // this isn't getting used properly yet?") fmt.Fprintln(w, " sync.RWMutex // this isn't getting used properly yet?")
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
@ -53,9 +68,28 @@ func newIter(w io.Writer, FRUIT, APPLE, APPLES, LOCK string) {
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
fmt.Fprintln(w, "// END DEFINE THE ITERATOR") fmt.Fprintln(w, "// END DEFINE THE ITERATOR")
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
return funcdef
} }
func newSortBy(w io.Writer, FRUIT, APPLE, APPLES, COLOR string) { // maybe there are better ways in GO now adays // that's fine though. this is easy to read
// TODO; figure out what types this actually works on
// TODO; add timestamppb compare
func newSortType(w io.Writer, STRUCT, VARNAME string) string {
fmt.Fprintln(w, "// sort struct by", VARNAME)
fmt.Fprintln(w, "type "+STRUCT+VARNAME+" []*"+STRUCT+"")
fmt.Fprintln(w, "")
fmt.Fprintln(w, "func (a "+STRUCT+VARNAME+") Len() int { return len(a) }")
fmt.Fprintln(w, "func (a "+STRUCT+VARNAME+") Less(i, j int) bool { return a[i]."+VARNAME+" < a[j]."+VARNAME+" }")
fmt.Fprintln(w, "func (a "+STRUCT+VARNAME+") Swap(i, j int) { a[i], a[j] = a[j], a[i] }")
fmt.Fprintln(w, "")
return "type " + STRUCT + VARNAME + " []*" + STRUCT + " // { return a[i]." + VARNAME + " < a[j]." + VARNAME + " }"
}
func newSortBy(w io.Writer, FRUIT, APPLE, APPLES, COLOR string) string {
funcdef := "func (x *" + FRUIT + ") SortBy" + COLOR + "() *" + APPLE + "Iterator // field: " + COLOR
fmt.Fprintln(w, "// START sort by ", COLOR, "(this is all you need once the Iterator is defined)") fmt.Fprintln(w, "// START sort by ", COLOR, "(this is all you need once the Iterator is defined)")
fmt.Fprintln(w, "type "+APPLE+COLOR+" []*"+APPLE+"") fmt.Fprintln(w, "type "+APPLE+COLOR+" []*"+APPLE+"")
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
@ -72,32 +106,42 @@ func newSortBy(w io.Writer, FRUIT, APPLE, APPLES, COLOR string) {
fmt.Fprintln(w, " return iterator") fmt.Fprintln(w, " return iterator")
fmt.Fprintln(w, "}") fmt.Fprintln(w, "}")
fmt.Fprintln(w, "// END sort by", COLOR) fmt.Fprintln(w, "// END sort by", COLOR)
return funcdef
} }
func addAllFunc(w io.Writer, FRUIT, APPLE, LOCK string) { func addAllFunc(w io.Writer, FRUIT, APPLE, APPLES string) string {
fmt.Fprintln(w, "func (x *"+FRUIT+") All() *"+APPLE+"Iterator {") funcdef := "func (x *" + FRUIT + ") All() *" + APPLE + "Iterator {"
fmt.Fprintln(w, " "+APPLE+"Pointers := x.selectAll"+APPLE+"()")
fmt.Fprintln(w, funcdef)
fmt.Fprintln(w, " "+APPLE+"Pointers := x.selectAll"+APPLES+"()")
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
fmt.Fprintln(w, " iterator := New"+APPLE+"Iterator("+APPLE+"Pointers)") fmt.Fprintln(w, " iterator := New"+APPLE+"Iterator("+APPLE+"Pointers)")
fmt.Fprintln(w, " return iterator") fmt.Fprintln(w, " return iterator")
fmt.Fprintln(w, "}") fmt.Fprintln(w, "}")
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
return funcdef
} }
func addLenFunc(w io.Writer, FRUIT, APPLES, LOCK string) { func addLenFunc(w io.Writer, FRUIT, APPLES, LOCK string) string {
funcdef := "func (x *" + FRUIT + ") Len() int {"
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
fmt.Fprintln(w, "func (x *"+FRUIT+") Len() int {") fmt.Fprintln(w, funcdef)
fmt.Fprintln(w, " "+LOCK+".RLock()") fmt.Fprintln(w, " "+LOCK+".RLock()")
fmt.Fprintln(w, " defer "+LOCK+".RUnlock()") fmt.Fprintln(w, " defer "+LOCK+".RUnlock()")
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
fmt.Fprintln(w, " return len(x."+APPLES+")") fmt.Fprintln(w, " return len(x."+APPLES+")")
fmt.Fprintln(w, "}") fmt.Fprintln(w, "}")
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
return funcdef
} }
func addSelectAll(w io.Writer, FRUIT, APPLE, APPLES, LOCK string) { func addSelectAll(w io.Writer, FRUIT, APPLE, APPLES, LOCK string) string {
funcdef := "func (x *" + FRUIT + ") selectAll" + APPLES + "() []*" + APPLE
fmt.Fprintln(w, "// safely returns a slice of pointers to the "+APPLE+" protobufs") fmt.Fprintln(w, "// safely returns a slice of pointers to the "+APPLE+" protobufs")
fmt.Fprintln(w, "func (x *"+FRUIT+") selectAll"+APPLE+"() []*"+APPLE+" {") fmt.Fprintln(w, funcdef, "{")
fmt.Fprintln(w, " "+LOCK+".RLock()") fmt.Fprintln(w, " "+LOCK+".RLock()")
fmt.Fprintln(w, " defer "+LOCK+".RUnlock()") fmt.Fprintln(w, " defer "+LOCK+".RUnlock()")
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
@ -110,4 +154,6 @@ func addSelectAll(w io.Writer, FRUIT, APPLE, APPLES, LOCK string) {
fmt.Fprintln(w, "") fmt.Fprintln(w, "")
fmt.Fprintln(w, " return tmp") fmt.Fprintln(w, " return tmp")
fmt.Fprintln(w, "}") fmt.Fprintln(w, "}")
return funcdef
} }

View File

@ -1,11 +1,18 @@
package main package main
import ( import (
"fmt"
"go.wit.com/log" "go.wit.com/log"
) )
// This was just going to be a function to print the results to stdout
// instead, it's the core logic of the whole app
// --dry-run on the command line will just print what would be generated
// print the protobuf in human form // print the protobuf in human form
func (pf *File) printMsgTable() { func (pf *File) printMsgTable() error {
pf.Bases.printMsg() pf.Bases.printMsg()
pf.Base.printMsg() pf.Base.printMsg()
@ -13,6 +20,85 @@ func (pf *File) printMsgTable() {
for _, msg := range pf.MsgNames { for _, msg := range pf.MsgNames {
msg.printMsg() msg.printMsg()
} }
log.Printf("\n")
log.Printf(" %-2s %20s %20s %20s %20s\n", "", "PARENT STRUCT", "VAR STRUCT TYPE", "VAR NAME", "LOCK")
// for i, s := range slices.Backward(pf.ToSort) {
for i, s := range pf.ToSort {
var funcname string
STRUCT := s.MsgName
CHILD := s.VarType
VARNAME := s.VarName
LOCK := s.Lockname
log.Printf("SORT: %-2d %20s %20s %20s %20s %s\n", i, STRUCT, CHILD, VARNAME, LOCK, "")
var FUNCTYPE string
if STRUCT == VARNAME {
FUNCTYPE = STRUCT
} else {
FUNCTYPE = VARNAME
}
if s.VarType+"s" == s.VarName {
funcname = "func (x *" + FUNCTYPE + ") All() *[]iter" + s.VarType
} else {
funcname = "func (x *" + FUNCTYPE + ") all" + s.VarName + "() *[]iter" + s.VarType
}
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
msg := pf.findMsg(s.VarType)
if msg == nil {
return fmt.Errorf("failed to find struct %s", s.VarType)
}
for _, v := range msg.Vars {
if v.HasSort {
funcname := "func (x *" + FUNCTYPE + ") SortBy" + v.VarName + "(" + v.VarType + ") *[]iter" + s.VarType
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
var ucount int
for _, v := range msg.Vars {
if v.HasUnique {
ucount += 1
funcname := "func (x *" + FUNCTYPE + ") AppendUnique" + v.VarName + "(" + v.VarType + ")"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
for _, v := range msg.Vars {
if v.HasUnique {
funcname := "func (x *" + FUNCTYPE + ") DeleteBy" + v.VarName + "(" + v.VarType + ") bool"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
for _, v := range msg.Vars {
if v.HasUnique {
funcname = "func (x *" + FUNCTYPE + ") FindBy" + v.VarName + "(a " + v.VarType + ") *" + s.VarType + "(using" + v.VarName + ")"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
} else {
if v.VarType == "string" {
funcname = "func (x *" + FUNCTYPE + ") FindBy" + v.VarName + "(a string) []*" + s.VarType + " ???"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
}
if ucount == 1 {
for _, v := range msg.Vars {
if !v.HasUnique {
continue
}
funcname = "func (x *" + FUNCTYPE + ") Insert(a *" + v.VarType + ") (*" + CHILD + ", isNew bool)"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
if ucount > 1 {
funcname = "func (x *" + FUNCTYPE + ") Insert(a *" + CHILD + ") (*" + CHILD + ", isNew bool)"
log.Printf(" %-2s %20s %20s %20s %s %s\n", "", "", "", "", "", funcname)
}
}
return nil
} }
func (msg *MsgName) printMsg() { func (msg *MsgName) printMsg() {

23
main.go
View File

@ -2,9 +2,10 @@
// +build go1.20 // +build go1.20
// protobuf the way I am using them, require GO 1.20. I think. I could be wrong. // protobuf the way I am using them, require GO 1.20. I think. I could be wrong.
// The Go Protocol Buffers library embeds a sync.Mutex within the MessageState struct to prevent unintended shallow copies of message structs
// this optionally (but it is the default) inserts a mutex into the struct generated by protoc
// go:generate go-mod-clean // go:generate autogenpb --proto file.proto
// go:generate autogenpb auto.proto
package main package main
@ -25,6 +26,8 @@ import (
var VERSION string var VERSION string
var BUILDTIME string var BUILDTIME string
var fsort *os.File // the sort.pb.go output file
func main() { func main() {
pp := arg.MustParse(&argv) pp := arg.MustParse(&argv)
@ -51,6 +54,7 @@ func main() {
pf := new(File) pf := new(File)
pb.Files = append(pb.Files, pf) pb.Files = append(pb.Files, pf)
pf.Filename = argv.Proto pf.Filename = argv.Proto
pf.IterMap = make(map[string]string)
pf.Filebase = strings.TrimSuffix(argv.Proto, ".proto") pf.Filebase = strings.TrimSuffix(argv.Proto, ".proto")
@ -69,6 +73,21 @@ func main() {
badExit(fmt.Errorf("Base was nil. 'message %s {` did not exist", pf.Filebase)) badExit(fmt.Errorf("Base was nil. 'message %s {` did not exist", pf.Filebase))
} }
/*
// prep the output file
if !argv.DryRun {
var err error
fsort, err = os.OpenFile(pf.Filebase+".newsort.pb.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
badExit(err)
}
defer fsort.Close()
header(fsort, pf)
pf.syncLock(fsort)
}
*/
// show the protobuf of the protobuf. It's like Inception // show the protobuf of the protobuf. It's like Inception
pf.printMsgTable() pf.printMsgTable()

View File

@ -56,15 +56,15 @@ func (pb *Files) hasPluralMessage(f *File) error {
return fmt.Errorf("proto file error %s", f.Filename) return fmt.Errorf("proto file error %s", f.Filename)
} }
func (pb *Files) protoParse(f *File) error { func (pb *Files) protoParse(pf *File) error {
// does the file conform to the standard? (also reads in UUID & Version) // does the file conform to the standard? (also reads in UUID & Version)
if err := pb.hasPluralMessage(f); err != nil { if err := pb.hasPluralMessage(pf); err != nil {
return err return err
} }
log.Info(f.Filename, "is valid so far") log.Info(pf.Filename, "is valid so far")
// read in the .proto file // read in the .proto file
data, err := os.ReadFile(f.Filename) data, err := os.ReadFile(pf.Filename)
if err != nil { if err != nil {
return err return err
} }
@ -74,7 +74,7 @@ func (pb *Files) protoParse(f *File) error {
// parse the proto file for message struct names // parse the proto file for message struct names
for _, line := range strings.Split(string(data), "\n") { for _, line := range strings.Split(string(data), "\n") {
if strings.HasPrefix(line, "message ") { if strings.HasPrefix(line, "message ") {
curmsg = f.parseForMessage(line) curmsg = pf.parseForMessage(line)
} }
// this logic isn't right. find end of message with more bravado // this logic isn't right. find end of message with more bravado
if strings.HasPrefix(line, "}") { if strings.HasPrefix(line, "}") {
@ -93,6 +93,10 @@ func (pb *Files) protoParse(f *File) error {
// log.Info("Junk in .proto file? line did not contain a message var:", line) // log.Info("Junk in .proto file? line did not contain a message var:", line)
continue continue
} }
if msgvar.IsRepeated {
log.Info("ADDING ITER MAP", curmsg.Name, msgvar.VarType)
pf.IterMap[curmsg.Name] = msgvar.VarType
}
if strings.Contains(line, "autogenpb:sort") { if strings.Contains(line, "autogenpb:sort") {
newS := cases.Title(language.English, cases.NoLower).String(parts[1]) newS := cases.Title(language.English, cases.NoLower).String(parts[1])
@ -110,9 +114,40 @@ func (pb *Files) protoParse(f *File) error {
} }
curmsg.Vars = append(curmsg.Vars, msgvar) curmsg.Vars = append(curmsg.Vars, msgvar)
} }
pf.makeSortTable()
// for i, s := range slices.Backward(pf.ToSort) {
return nil return nil
} }
func (pf *File) makeSortTable() {
pf.sortWhat(pf.Bases)
pf.sortWhat(pf.Base)
// everything else
for _, msg := range pf.MsgNames {
pf.sortWhat(msg)
}
}
func (pf *File) sortWhat(msg *MsgName) {
for _, v := range msg.Vars {
if !v.IsRepeated {
continue
}
if check := pf.findMsg(v.VarType); check == nil {
// the VarType must be a struct
continue
}
s := new(Sort)
s.MsgName = msg.Name
s.VarType = v.VarType
s.VarName = v.VarName
s.Lockname = msg.Lockname
pf.ToSort = append(pf.ToSort, s)
}
}
func parseMsgVar(line string) *MsgVar { func parseMsgVar(line string) *MsgVar {
if strings.Contains(line, "//") { if strings.Contains(line, "//") {
parts := strings.Split(line, "//") parts := strings.Split(line, "//")
@ -169,6 +204,7 @@ func (pf *File) parseForMessage(line string) *MsgName {
log.Info("found messge:", msgName) log.Info("found messge:", msgName)
msg.Name = msgName msg.Name = msgName
msg.Lockname = pf.Filebase + "Mu" // this should be lowercase. do not export the Mutex msg.Lockname = pf.Filebase + "Mu" // this should be lowercase. do not export the Mutex
msg.NeedIter = true
if strings.Contains(line, "`autogenpb:mutex`") { if strings.Contains(line, "`autogenpb:mutex`") {
msg.DoMutex = true msg.DoMutex = true