boo. big mistake on naming protobufs

It's important to really choose good names from the
	start. do not think you can rename .proto files later
	Good software engineering practices enforced here!
	no bullshit. you really want to know what you are planning.
This commit is contained in:
Jeff Carr 2024-11-27 21:05:12 -06:00
parent 5d03131047
commit 0fc7c2d753
9 changed files with 276 additions and 30 deletions

View File

@ -5,7 +5,7 @@
# go install
all: repo.pb.go
all: repo.pb.go forgeConfig.pb.go
make -C forgeConfig
vet: lint
@ -34,3 +34,9 @@ repo.pb.go: repo.proto
cd ~/go/src && protoc --go_out=. --proto_path=go.wit.com/lib/protobuf/forgepb \
--go_opt=Mrepo.proto=go.wit.com/lib/protobuf/forgepb \
repo.proto
forgeConfig.pb.go: forgeConfig.proto
# I'm using version v1.35.x from google.golang.org/protobuf/cmd/protoc-gen-go
cd ~/go/src && protoc --go_out=. --proto_path=go.wit.com/lib/protobuf/forgepb \
--go_opt=MforgeConfig.proto=go.wit.com/lib/protobuf/forgepb \
forgeConfig.proto

View File

@ -12,7 +12,7 @@ import (
)
// write to ~/.config/forge/ unless ENV{FORGE_HOME} is set
func (m *Repos) ConfigSave() error {
func (m *ForgeConfigs) ConfigSave() error {
if os.Getenv("FORGE_HOME") == "" {
homeDir, _ := os.UserHomeDir()
fullpath := filepath.Join(homeDir, ".config/forge")
@ -39,7 +39,7 @@ func (m *Repos) ConfigSave() error {
}
// load the ~/.config/forge/ files
func (c *Repos) ConfigLoad() error {
func (c *ForgeConfigs) ConfigLoad() error {
if os.Getenv("FORGE_HOME") == "" {
homeDir, _ := os.UserHomeDir()
fullpath := filepath.Join(homeDir, ".config/forge")
@ -66,7 +66,7 @@ func (c *Repos) ConfigLoad() error {
log.Warn("broken forge.pb config file")
return err
}
log.Info("config load found", len(c.Repos), "repos")
log.Info("config load found", len(c.ForgeConfigs), "repos")
return nil
}
@ -86,7 +86,7 @@ func (c *Repos) ConfigLoad() error {
log.Warn("broken forge.text config file")
return err
}
log.Info("config load found", len(c.Repos), "repos")
log.Info("config load found", len(c.ForgeConfigs), "repos")
return nil
}
@ -106,7 +106,7 @@ func (c *Repos) ConfigLoad() error {
log.Warn("broken forge.json config file")
return err
}
log.Info("config load found", len(c.Repos), "repos")
log.Info("config load found", len(c.ForgeConfigs), "repos")
return nil
}

50
forgeConfig.marshal.go Normal file
View File

@ -0,0 +1,50 @@
package forgepb
// TODO: autogen this
// functions to import and export the protobuf
// data to and from config files
import (
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/proto"
// "google.golang.org/protobuf/proto"
)
// human readable JSON
func (p *ForgeConfigs) FormatJSON() string {
return protojson.Format(p)
}
// apparently this isn't supposed to be used?
// https://protobuf.dev/reference/go/faq/#unstable-text
// this is a shame because this is much nicer output than JSON Format()
// TODO: fix things so this is the default
func (p *ForgeConfigs) FormatTEXT() string {
return prototext.Format(p)
}
// unmarshalTEXT
func (p *ForgeConfigs) UnmarshalTEXT(data []byte) error {
return prototext.Unmarshal(data, p)
}
// marshal json
func (p *ForgeConfigs) MarshalJSON() ([]byte, error) {
return protojson.Marshal(p)
}
// unmarshal
func (p *ForgeConfigs) UnmarshalJSON(data []byte) error {
return protojson.Unmarshal(data, p)
}
// marshal to wire
func (m *ForgeConfigs) Marshal() ([]byte, error) {
return proto.Marshal(m)
}
// unmarshal from wire
func (m *ForgeConfigs) Unmarshal(data []byte) error {
return proto.Unmarshal(data, m)
}

39
forgeConfig.proto Normal file
View File

@ -0,0 +1,39 @@
syntax = "proto3";
package forgepb;
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
// define 3 branches. that is all that is supported
// the term 'master' is used in the code because 'main' is a reserved word in golang already
// allow 'read only' and 'private' flags
// package names sometimes must be different than the binary name
// for example 'zookeeper' is packaged as 'zookeeper-go'
// due to the prior apache foundation project. This happens and is ok!
message ForgeConfig {
string goPath = 1; // Examples: 'go.wit.com/apps/go-clone' or "~/mythings" or "/home/src/foo"
bool writable = 2; // if you have write access to the repo
bool readOnly = 3; // the opposite, but needed for now because I don't know what I'm doing
bool private = 4; // if the repo can be published
bool directory = 5; // everything in this directory should use these writable & private values
bool favorite = 6; // you like this. always git clone/go clone this repo
bool interesting = 7; // this is something interesting you found and want to remember it
string masterBranch = 8; // git 'main' or 'master' branch name
string develBranch = 9; // whatever the git 'devel' branch name is
string userBranch = 10; // whatever your username branch is
string debName = 11; // the actual name used with 'apt install' (or distro apt equivalent.
// todo: appeal to everyone to alias 'apt' on rhat, gentoo, arch, etc to alias 'apt install'
// so we can make easier instructions for new linux users. KISS
google.protobuf.Timestamp verstamp = 12; // the git commit timestamp of the version
}
// TODO: autogen 'Repos'
message ForgeConfigs {
string uuid = 1; // could be useful for /usr/share/file/magic someday?
string version = 2; // could be used for protobuf schema change violations?
repeated ForgeConfig ForgeConfigs = 3;
}

151
forgeConfig.sort.go Normal file
View File

@ -0,0 +1,151 @@
package forgepb
// TODO: autogen this? (probably not feasible. need go-arglike tricks in proto)
import (
"fmt"
"os"
"sort"
sync "sync"
"time"
)
// bad global lock until I figure out some other plan
var forgeConfigsLock sync.RWMutex
type ForgeConfigIterator struct {
sync.RWMutex
packs []*ForgeConfig
index int
}
// NewForgeConfigIterator initializes a new iterator.
func NewForgeConfigIterator(packs []*ForgeConfig) *ForgeConfigIterator {
return &ForgeConfigIterator{packs: packs}
}
// Scan moves to the next element and returns false if there are no more packs.
func (it *ForgeConfigIterator) Scan() bool {
if it.index >= len(it.packs) {
return false
}
it.index++
return true
}
// ForgeConfig returns the current forgeConfig.
func (it *ForgeConfigIterator) Next() *ForgeConfig {
if it.packs[it.index-1] == nil {
for i, d := range it.packs {
fmt.Println("i =", i, d)
}
fmt.Println("len =", len(it.packs))
fmt.Println("forgeConfig == nil", it.index, it.index-1)
os.Exit(-1)
}
return it.packs[it.index-1]
}
// Use Scan() in a loop, similar to a while loop
//
// for iterator.Scan() {
// d := iterator.ForgeConfig()
// fmt.Println("ForgeConfig UUID:", d.Uuid)
// }
func (r *ForgeConfigs) All() *ForgeConfigIterator {
forgeConfigPointers := r.selectAllForgeConfigs()
iterator := NewForgeConfigIterator(forgeConfigPointers)
return iterator
}
func (r *ForgeConfigs) SortByPath() *ForgeConfigIterator {
packs := r.selectAllForgeConfigs()
sort.Sort(ByForgeConfigPath(packs))
iterator := NewForgeConfigIterator(packs)
return iterator
}
// enforces no duplicate forgeConfig paths
func (r *ForgeConfigs) Append(newP *ForgeConfig) bool {
forgeConfigsLock.Lock()
defer forgeConfigsLock.Unlock()
for _, p := range r.ForgeConfigs {
if p.GoPath == newP.GoPath {
return false
}
}
r.ForgeConfigs = append(r.ForgeConfigs, newP)
return true
}
// returns time.Duration since last Update()
func (r *ForgeConfig) Age(newP *ForgeConfig) time.Duration {
t := time.Since(r.Verstamp.AsTime())
return t
}
// find a forgeConfig by path
func (r *ForgeConfigs) FindByPath(gopath string) *ForgeConfig {
forgeConfigsLock.RLock()
defer forgeConfigsLock.RUnlock()
for _, p := range r.ForgeConfigs {
if p.GoPath == gopath {
return p
}
}
return nil
}
func (r *ForgeConfigs) Len() int {
forgeConfigsLock.RLock()
defer forgeConfigsLock.RUnlock()
return len(r.ForgeConfigs)
}
type ByForgeConfigPath []*ForgeConfig
func (a ByForgeConfigPath) Len() int { return len(a) }
func (a ByForgeConfigPath) Less(i, j int) bool { return a[i].GoPath < a[j].GoPath }
func (a ByForgeConfigPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (all *ForgeConfigs) DeleteByPath(gopath string) *ForgeConfig {
forgeConfigsLock.Lock()
defer forgeConfigsLock.Unlock()
var newr ForgeConfig
for i, _ := range all.ForgeConfigs {
if all.ForgeConfigs[i].GoPath == gopath {
newr = *all.ForgeConfigs[i]
all.ForgeConfigs[i] = all.ForgeConfigs[len(all.ForgeConfigs)-1]
all.ForgeConfigs = all.ForgeConfigs[:len(all.ForgeConfigs)-1]
return &newr
}
}
return nil
}
// safely returns a slice of pointers to the ForgeConfig protobufs
func (r *ForgeConfigs) selectAllForgeConfigs() []*ForgeConfig {
forgeConfigsLock.RLock()
defer forgeConfigsLock.RUnlock()
// Create a new slice to hold pointers to each ForgeConfig
var allPacks []*ForgeConfig
allPacks = make([]*ForgeConfig, len(r.ForgeConfigs))
for i, p := range r.ForgeConfigs {
allPacks[i] = p // Copy pointers for safe iteration
}
return allPacks
}

View File

@ -11,7 +11,7 @@ import (
var VERSION string
func main() {
var repos forgepb.Repos
var repos forgepb.ForgeConfigs
if err := repos.ConfigLoad(); err != nil {
log.Warn("forgepb.ConfigLoad() failed", err)
os.Exit(-1)
@ -55,7 +55,7 @@ func main() {
// try to add, then save config and exit
if argv.Add {
log.Info("going to add a new repo", argv.GoPath)
new1 := forgepb.Repo{
new1 := forgepb.ForgeConfig{
GoPath: argv.GoPath,
Writable: argv.Writable,
ReadOnly: argv.ReadOnly,

View File

@ -18,7 +18,7 @@ func standardHeader() string {
return fmt.Sprintf("%-4s %-40s %s", "", "Path", "flags")
}
func (all *Repos) standardHeader(r *Repo) string {
func (all *ForgeConfigs) standardHeader(r *ForgeConfig) string {
var flags string
var readonly string
if all.IsPrivate(r.GoPath) {
@ -36,7 +36,7 @@ func (all *Repos) standardHeader(r *Repo) string {
}
// print a human readable table to STDOUT
func (all *Repos) PrintTable() {
func (all *ForgeConfigs) PrintTable() {
if all == nil {
log.Info("WTF")
os.Exit(0)
@ -44,7 +44,7 @@ func (all *Repos) PrintTable() {
log.Info(standardHeader())
loop := all.SortByPath()
for loop.Scan() {
r := loop.Repo()
r := loop.Next()
log.Info(all.standardHeader(r))
}
}

View File

@ -6,8 +6,8 @@ import (
"go.wit.com/log"
)
func (all *Repos) SampleConfig() {
new1 := new(Repo)
func (all *ForgeConfigs) SampleConfig() {
new1 := new(ForgeConfig)
new1.GoPath = "go.wit.com"
new1.Writable = true
new1.Directory = true
@ -17,7 +17,7 @@ func (all *Repos) SampleConfig() {
log.Info("added", new1.GoPath, "failed")
}
new1 = new(Repo)
new1 = new(ForgeConfig)
new1.GoPath = "go.wit.com/apps/zookeeper"
new1.DebName = "zookeeper-go"
if all.Append(new1) {
@ -26,7 +26,7 @@ func (all *Repos) SampleConfig() {
log.Info("added", new1.GoPath, "failed")
}
new1 = new(Repo)
new1 = new(ForgeConfig)
new1.GoPath = "go.wit.com/apps/wit-package"
new1.Private = true
if all.Append(new1) {
@ -35,7 +35,7 @@ func (all *Repos) SampleConfig() {
log.Info("added", new1.GoPath, "failed")
}
new1 = new(Repo)
new1 = new(ForgeConfig)
new1.GoPath = "go.wit.com/apps/networkQuality"
new1.DebName = "networkquality"
new1.ReadOnly = true
@ -45,7 +45,7 @@ func (all *Repos) SampleConfig() {
log.Info("added", new1.GoPath, "failed")
}
new2 := new(Repo)
new2 := new(ForgeConfig)
new2.GoPath = "go.wit.com/apps/go-clone"
if all.Append(new2) {
log.Info("added", new2.GoPath, "ok")
@ -59,5 +59,5 @@ func (all *Repos) SampleConfig() {
log.Info("added", new2.GoPath, "failed (but ok)")
}
fmt.Println("first time user. adding an example config file with", len(all.Repos), "repos")
fmt.Println("first time user. adding an example config file with", len(all.ForgeConfigs), "repos")
}

View File

@ -14,7 +14,7 @@ import (
"strings"
)
func (all *Repos) UpdateGoPath(name string, gopath string) bool {
func (all *ForgeConfigs) UpdateGoPath(name string, gopath string) bool {
oldr := all.DeleteByPath(name)
if oldr == nil {
// nothing to update
@ -28,12 +28,12 @@ func (all *Repos) UpdateGoPath(name string, gopath string) bool {
// returns true if gopath is readonly()
// will attempt to match IsWritable("foo") against anything ending in "foo"
func (all *Repos) IsReadOnly(gopath string) bool {
var match *Repo
func (all *ForgeConfigs) IsReadOnly(gopath string) bool {
var match *ForgeConfig
loop := all.SortByPath() // get the list of repos
for loop.Scan() {
r := loop.Repo()
r := loop.Next()
if r.GoPath == gopath {
// exact gopath match
if r.Writable {
@ -88,13 +88,13 @@ func (all *Repos) IsReadOnly(gopath string) bool {
// this let's you check a git tag version against a package .deb version
// allows gopath's to not need to match the .deb name
// this is important in lots of cases! It is normal and happens often enough.
func (all *Repos) DebName(gopath string) string {
func (all *ForgeConfigs) DebName(gopath string) string {
// get "zookeeper" from "go.wit.com/apps/zookeeper"
normalBase := filepath.Base(gopath)
loop := all.SortByPath()
for loop.Scan() {
r := loop.Repo()
r := loop.Next()
if r.GoPath == gopath {
// returns "zookeeper-go" for "go.wit.com/apps/zookeeper"
if r.DebName != "" {
@ -115,15 +115,15 @@ func (all *Repos) DebName(gopath string) string {
//
// IsPrivate("go.foo.com/jcarr/foo") returns true if private
// IsPrivate("foo") also returns true if "go.bar.com/jcarr/foo" is private
func (all *Repos) IsPrivate(thing string) bool {
var match *Repo
func (all *ForgeConfigs) IsPrivate(thing string) bool {
var match *ForgeConfig
// sort by path means the simple 'match' logic
// here works in the sense the last directory match
// is the one that is used
loop := all.SortByPath() // get the list of repos
for loop.Scan() {
r := loop.Repo()
r := loop.Next()
if r.GoPath == thing {
// if private is set here, then ok, otherwise
// still check if a Directory match exists
@ -159,12 +159,12 @@ func (all *Repos) IsPrivate(thing string) bool {
// file that lets you set things as favorites
// so you can just go-clone a bunch of common things
// on a new box or after you reset/delete your ~/go/src dir
func (all *Repos) IsFavorite(thing string) bool {
var match *Repo
func (all *ForgeConfigs) IsFavorite(thing string) bool {
var match *ForgeConfig
loop := all.SortByPath() // get the list of repos
for loop.Scan() {
r := loop.Repo()
r := loop.Next()
if r.GoPath == thing {
if r.Favorite {
return true