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:
parent
5d03131047
commit
0fc7c2d753
8
Makefile
8
Makefile
|
@ -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
|
||||
|
|
10
config.go
10
config.go
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
|
|
6
human.go
6
human.go
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
24
settings.go
24
settings.go
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue