From 98467dec72f0a894b7a2fef319d73d3320d94d0f Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Thu, 11 Sep 2025 02:20:06 -0500 Subject: using new config package --- config.common.go | 337 -------------------------------------------------- config.go | 135 +------------------- doDirty.go | 3 +- forgeConfig.common.go | 337 ++++++++++++++++++++++++++++++++++++++++++++++++++ forgeConfig.config.go | 25 ++++ patchset.Send.go | 31 +++++ 6 files changed, 397 insertions(+), 471 deletions(-) delete mode 100644 config.common.go create mode 100644 forgeConfig.common.go create mode 100644 forgeConfig.config.go diff --git a/config.common.go b/config.common.go deleted file mode 100644 index 5a230a8..0000000 --- a/config.common.go +++ /dev/null @@ -1,337 +0,0 @@ -package forgepb - -/* - lookup settings for a particular *gitpb.Repo or gopath string - - user settings are configured in ~/.config/forge/forge.text - - // searchs by string - Configs.IsReadOnly(path) // user can't push commits - Configs.IsWritable(path) // the opposite, but maybe different so I put both here - - IsPrivate(repo) // repo can't be published to the pkg.go.dev system - DebName() // for 'zookeeper' returns 'zookeeper-go' - - This code is practical, not perfect -*/ - -import ( - "path/filepath" - "strings" - - "go.wit.com/lib/protobuf/gitpb" -) - -/* -func (all *ForgeConfigs) UpdateGoPath(name string, gopath string) bool { - oldr := all.DeleteByGoPath(name) - if oldr == nil { - // nothing to update - return false - } - - // update gopath and append it back to the list - oldr.GoPath = gopath - return all.Append(oldr) -} -*/ - -// returns true if gopath is readonly() -// will attempt to match IsWritable("foo") against anything ending in "foo" -func (fc *ForgeConfigs) IsReadOnly(gopath string) bool { - var match *ForgeConfig - - all := fc.SortByGoPath() // get the list of repos - for all.Scan() { - r := all.Next() - if r.GoPath == gopath { - // exact gopath match - if r.Writable { - return false - } - if r.ReadOnly { - return true - } - // private is assumed to be r/w unless above is specifically set - if r.Private { - return false - } - } - // if gopath == "foo" will return false if "go.wit.com/apps/foo" is Writable - base := filepath.Base(r.GoPath) - if base == gopath { - if r.Writable { - return false - } - } - // search for potential dir matches - if r.Directory { - // test the dir - if strings.HasPrefix(gopath, r.GoPath) { - match = r - } - } - } - - if match == nil { - // log.Info("did not match in IsReadOnly()", gopath) - return true - } - - // take the settings from the directory match - if match.Writable { - return false - } - if match.ReadOnly { - return true - } - // private is assumed to be r/w unless above is specifically set - if match.Private { - return false - } - - // always assume readonly - return true -} - -// returns the deb package name -// 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 (fc *ForgeConfigs) DebName(gopath string) string { - // get "zookeeper" from "go.wit.com/apps/zookeeper" - normalBase := filepath.Base(gopath) - - all := fc.SortByGoPath() - for all.Scan() { - r := all.Next() - if r.GoPath == gopath { - // returns "zookeeper-go" for "go.wit.com/apps/zookeeper" - if r.DebName != "" { - // log.Info("FOUND DebName", r.DebName) - return r.DebName - } else { - return normalBase - } - } - } - return normalBase -} - -// a work in progress -func (f *Forge) IsPrivate(repo *gitpb.Repo) bool { - namespace := repo.GetNamespace() - if namespace == "" { - // assume true - return true - } - - return f.Config.IsPrivate(namespace) -} - -// is this a non-publishable repo? -// matches package names from apt -// -// IsPrivate("foo") will match anything in the config file ending in "foo" -// -// IsPrivate("go.foo.com/jcarr/foo") returns true if private -// IsPrivate("foo") also returns true if "go.bar.com/jcarr/foo" is private -func (fc *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 - all := fc.SortByGoPath() // get the list of repos - for all.Scan() { - r := all.Next() - if r.GoPath == thing { - // if private is set here, then ok, otherwise - // still check if a Directory match exists - if r.Private { - return true - } - } - base := filepath.Base(r.GoPath) - if base == thing { - if r.Private { - return true - } - } - // check to see if IsPrivate("foo") - // search for potential dir matches - if r.Directory { - // test the dir - if strings.HasPrefix(thing, r.GoPath) { - match = r - } - } - } - if match == nil { - // log.Info("did not match in IsPrivate()", thing) - return false - } - - // otherwise, assume not private - return match.Private -} - -// IsFavorite() -- fun option for the config -// 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 (fc *ForgeConfigs) IsFavorite(thing string) bool { - var match *ForgeConfig - - all := fc.SortByGoPath() // get the list of repos - for all.Scan() { - r := all.Next() - if r.GoPath == thing { - if r.Favorite { - return true - } - } - base := filepath.Base(r.GoPath) - if base == thing { - if r.Favorite { - return true - } - } - if r.Directory { - if strings.HasPrefix(thing, r.GoPath) { - match = r - } - } - } - if match == nil { - return false - } - - return match.Favorite -} - -// IsWritable() checks your .config/forge/ settings -// looks for an exact match, then -// looks for a directory match -func (fc *ForgeConfigs) IsWritable(thing string) bool { - var match *ForgeConfig - - all := fc.SortByGoPath() // get the list of repos - for all.Scan() { - r := all.Next() - if r.GoPath == thing { - if r.Writable { - return true - } - } - base := filepath.Base(r.GoPath) - if base == thing { - if r.Writable { - return true - } - } - if r.Directory { - if strings.HasPrefix(thing, r.GoPath) { - match = r - } - } - } - if match == nil { - return false - } - - return match.Writable -} - -// allows custom user branch names in the forge config -func (fc *ForgeConfigs) FindUserBranch(thing string) string { - var match *ForgeConfig - - all := fc.SortByGoPath() // get the list of repos - for all.Scan() { - r := all.Next() - if r.GoPath == thing { - if r.UserBranchName != "" { - return r.UserBranchName - } - } - base := filepath.Base(r.GoPath) - if base == thing { - if r.UserBranchName != "" { - return r.UserBranchName - } - } - if r.Directory { - if strings.HasPrefix(thing, r.GoPath) { - match = r - } - } - } - if match == nil { - return "" - } - - return match.UserBranchName -} - -// allows custom devel branch names in the forge config -func (fc *ForgeConfigs) FindDevelBranch(thing string) string { - var match *ForgeConfig - - all := fc.SortByGoPath() // get the list of repos - for all.Scan() { - r := all.Next() - if r.GoPath == thing { - if r.DevelBranchName != "" { - return r.DevelBranchName - } - } - base := filepath.Base(r.GoPath) - if base == thing { - if r.DevelBranchName != "" { - return r.DevelBranchName - } - } - if r.Directory { - if strings.HasPrefix(thing, r.GoPath) { - match = r - } - } - } - if match == nil { - return "" - } - - return match.DevelBranchName -} - -// allows custom devel branch names in the forge config -func (fc *ForgeConfigs) FindMasterBranch(thing string) string { - var match *ForgeConfig - - all := fc.SortByGoPath() // get the list of repos - for all.Scan() { - r := all.Next() - if r.GoPath == thing { - if r.MasterBranchName != "" { - return r.MasterBranchName - } - } - base := filepath.Base(r.GoPath) - if base == thing { - if r.MasterBranchName != "" { - return r.MasterBranchName - } - } - if r.Directory { - if strings.HasPrefix(thing, r.GoPath) { - match = r - } - } - } - if match == nil { - return "" - } - - return match.MasterBranchName -} diff --git a/config.go b/config.go index 963202f..dc94480 100644 --- a/config.go +++ b/config.go @@ -2,31 +2,16 @@ package forgepb -// functions to import and export the protobuf -// data to and from config files - import ( - "errors" - "fmt" - "os" - "path/filepath" "time" "go.wit.com/log" timestamppb "google.golang.org/protobuf/types/known/timestamppb" ) +// returns err1 || err2 func (f *Forge) ConfigSave() error { var err error - /* - // backup the current config files - if e := f.backupConfig(); e != nil { - log.Info("forge.BackupConfig() error", e) - err = e - // continue here? notsure. could be bad either way - // out of disk space? - } - */ if f.Config != nil { if e := f.Config.ConfigSave(); e != nil { log.Info("forge.Config.ConfigSave() error", e) @@ -34,6 +19,7 @@ func (f *Forge) ConfigSave() error { } } if f.Repos != nil { + // ??? if f.HasFullScan() { f.Repos.HasFullScan = true t := time.Now() @@ -46,120 +32,3 @@ func (f *Forge) ConfigSave() error { } return err } - -// write to ~/.config/forge/ -func (f *ForgeConfigs) ConfigSave() error { - data, err := f.Marshal() - if err != nil { - log.Info("proto.Marshal() failed len", len(data), err) - return err - } - // log.Info("forgepb.ConfigSave() proto.Marshal() worked len", len(data)) - - s := f.FormatTEXT() - configWrite("forge.text", []byte(s)) - - s = f.FormatJSON() - configWrite("forge.json", []byte(s)) - - return nil -} - -// load the ~/.config/forge/ files -func (c *ForgeConfigs) ConfigLoad(fullpath string) error { - // var data []byte - // var err error - if c == nil { - // can't safely do c = new(ForgeConfig) if c is in a struct from the caller. notsure why - // TODO: recheck this. it might work now? It's probably still a bad idea(?) - return errors.New("It's not safe to run ConfigLoad() on a nil") - } - - if err := c.loadText(); err == nil { - return nil - } - - // forge.text doesn't exist. try forge.json - // this lets the user hand edit the JSON config - // probably just deprecate this - if data, err := loadFile("forge.json"); err != nil { - if data != nil { - // this means the forge.json file exists and was read - if len(data) != 0 { - if err = c.UnmarshalJSON(data); err == nil { - log.Info("forge.ConfigLoad()", len(c.ForgeConfigs), "entries in ~/.config/forge") - // forge.text file was broken. save on load right away - log.Info("attempting forge.ConfigSave()") - c.ConfigSave() - return nil - } - } - } - } - - cpath := filepath.Join(os.Getenv("FORGE_CONFIG"), ".") - if _, err := os.Stat(cpath); err == nil { - log.Info("Something has gone wrong. Your", os.Getenv("FORGE_CONFIG"), "directory exists") - log.Info("However, the config files could not be loaded") - } - - return nil -} - -func (c *ForgeConfigs) loadText() error { - // this lets the user hand edit the config - data, err := loadFile("forge.text") - if err != nil { - return err - } - if data == nil { - return fmt.Errorf("forge.text data was nil") - } - if len(data) == 0 { - return fmt.Errorf("forge.text was empty") - } - - // attempt to marshal forge.text - if err := c.UnmarshalTEXT(data); err != nil { - return err - } - log.Log(INFO, "forge.loadText()", len(c.ForgeConfigs), "entries in ~/.config/forge") - return nil -} - -func loadFile(filename string) ([]byte, error) { - fullname := filepath.Join(os.Getenv("FORGE_CONFIG"), filename) - data, err := os.ReadFile(fullname) - if errors.Is(err, os.ErrNotExist) { - // if file does not exist, just return nil. this - // will cause ConfigLoad() to try the next config file like "forge.text" - // because the user might want to edit the .config by hand - return nil, nil - } - if err != nil { - // log.Info("open config file :", err) - return nil, err - } - return data, nil -} - -func configWrite(filename string, data []byte) error { - fullname := filepath.Join(os.Getenv("FORGE_CONFIG"), filename) - - cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) - defer cfgfile.Close() - if err != nil { - log.Warn("open config file :", err) - return err - } - if filename == "forge.text" { - log.Infof("%s : your preferences file has been updated. (%d) bytes\n", fullname, len(data)) - // add header - cfgfile.Write([]byte("\n")) - cfgfile.Write([]byte("# this file is intended to be used to customize settings on what\n")) - cfgfile.Write([]byte("# git repos you have write access to. That is, where you can run 'git push'\n")) - cfgfile.Write([]byte("\n")) - } - cfgfile.Write(data) - return nil -} diff --git a/doDirty.go b/doDirty.go index 70e018a..4a45ed3 100644 --- a/doDirty.go +++ b/doDirty.go @@ -22,7 +22,7 @@ func (f *Forge) CheckDirtyQuiet() { for _, s := range stats { if s.Err == nil { } else { - // log.Info(i, s.Err) + log.Info("forge SetConfigSave(true)") f.SetConfigSave(true) changed = true } @@ -73,6 +73,7 @@ func doCheckDirty(repo *gitpb.Repo) error { // nothing changed } else { log.Info("Repo changed to clean", repo.FullPath) + return log.Errorf("%s repo changed to clean", repo.FullPath) // f.SetConfigSave(true) } } else { diff --git a/forgeConfig.common.go b/forgeConfig.common.go new file mode 100644 index 0000000..5a230a8 --- /dev/null +++ b/forgeConfig.common.go @@ -0,0 +1,337 @@ +package forgepb + +/* + lookup settings for a particular *gitpb.Repo or gopath string + + user settings are configured in ~/.config/forge/forge.text + + // searchs by string + Configs.IsReadOnly(path) // user can't push commits + Configs.IsWritable(path) // the opposite, but maybe different so I put both here + + IsPrivate(repo) // repo can't be published to the pkg.go.dev system + DebName() // for 'zookeeper' returns 'zookeeper-go' + + This code is practical, not perfect +*/ + +import ( + "path/filepath" + "strings" + + "go.wit.com/lib/protobuf/gitpb" +) + +/* +func (all *ForgeConfigs) UpdateGoPath(name string, gopath string) bool { + oldr := all.DeleteByGoPath(name) + if oldr == nil { + // nothing to update + return false + } + + // update gopath and append it back to the list + oldr.GoPath = gopath + return all.Append(oldr) +} +*/ + +// returns true if gopath is readonly() +// will attempt to match IsWritable("foo") against anything ending in "foo" +func (fc *ForgeConfigs) IsReadOnly(gopath string) bool { + var match *ForgeConfig + + all := fc.SortByGoPath() // get the list of repos + for all.Scan() { + r := all.Next() + if r.GoPath == gopath { + // exact gopath match + if r.Writable { + return false + } + if r.ReadOnly { + return true + } + // private is assumed to be r/w unless above is specifically set + if r.Private { + return false + } + } + // if gopath == "foo" will return false if "go.wit.com/apps/foo" is Writable + base := filepath.Base(r.GoPath) + if base == gopath { + if r.Writable { + return false + } + } + // search for potential dir matches + if r.Directory { + // test the dir + if strings.HasPrefix(gopath, r.GoPath) { + match = r + } + } + } + + if match == nil { + // log.Info("did not match in IsReadOnly()", gopath) + return true + } + + // take the settings from the directory match + if match.Writable { + return false + } + if match.ReadOnly { + return true + } + // private is assumed to be r/w unless above is specifically set + if match.Private { + return false + } + + // always assume readonly + return true +} + +// returns the deb package name +// 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 (fc *ForgeConfigs) DebName(gopath string) string { + // get "zookeeper" from "go.wit.com/apps/zookeeper" + normalBase := filepath.Base(gopath) + + all := fc.SortByGoPath() + for all.Scan() { + r := all.Next() + if r.GoPath == gopath { + // returns "zookeeper-go" for "go.wit.com/apps/zookeeper" + if r.DebName != "" { + // log.Info("FOUND DebName", r.DebName) + return r.DebName + } else { + return normalBase + } + } + } + return normalBase +} + +// a work in progress +func (f *Forge) IsPrivate(repo *gitpb.Repo) bool { + namespace := repo.GetNamespace() + if namespace == "" { + // assume true + return true + } + + return f.Config.IsPrivate(namespace) +} + +// is this a non-publishable repo? +// matches package names from apt +// +// IsPrivate("foo") will match anything in the config file ending in "foo" +// +// IsPrivate("go.foo.com/jcarr/foo") returns true if private +// IsPrivate("foo") also returns true if "go.bar.com/jcarr/foo" is private +func (fc *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 + all := fc.SortByGoPath() // get the list of repos + for all.Scan() { + r := all.Next() + if r.GoPath == thing { + // if private is set here, then ok, otherwise + // still check if a Directory match exists + if r.Private { + return true + } + } + base := filepath.Base(r.GoPath) + if base == thing { + if r.Private { + return true + } + } + // check to see if IsPrivate("foo") + // search for potential dir matches + if r.Directory { + // test the dir + if strings.HasPrefix(thing, r.GoPath) { + match = r + } + } + } + if match == nil { + // log.Info("did not match in IsPrivate()", thing) + return false + } + + // otherwise, assume not private + return match.Private +} + +// IsFavorite() -- fun option for the config +// 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 (fc *ForgeConfigs) IsFavorite(thing string) bool { + var match *ForgeConfig + + all := fc.SortByGoPath() // get the list of repos + for all.Scan() { + r := all.Next() + if r.GoPath == thing { + if r.Favorite { + return true + } + } + base := filepath.Base(r.GoPath) + if base == thing { + if r.Favorite { + return true + } + } + if r.Directory { + if strings.HasPrefix(thing, r.GoPath) { + match = r + } + } + } + if match == nil { + return false + } + + return match.Favorite +} + +// IsWritable() checks your .config/forge/ settings +// looks for an exact match, then +// looks for a directory match +func (fc *ForgeConfigs) IsWritable(thing string) bool { + var match *ForgeConfig + + all := fc.SortByGoPath() // get the list of repos + for all.Scan() { + r := all.Next() + if r.GoPath == thing { + if r.Writable { + return true + } + } + base := filepath.Base(r.GoPath) + if base == thing { + if r.Writable { + return true + } + } + if r.Directory { + if strings.HasPrefix(thing, r.GoPath) { + match = r + } + } + } + if match == nil { + return false + } + + return match.Writable +} + +// allows custom user branch names in the forge config +func (fc *ForgeConfigs) FindUserBranch(thing string) string { + var match *ForgeConfig + + all := fc.SortByGoPath() // get the list of repos + for all.Scan() { + r := all.Next() + if r.GoPath == thing { + if r.UserBranchName != "" { + return r.UserBranchName + } + } + base := filepath.Base(r.GoPath) + if base == thing { + if r.UserBranchName != "" { + return r.UserBranchName + } + } + if r.Directory { + if strings.HasPrefix(thing, r.GoPath) { + match = r + } + } + } + if match == nil { + return "" + } + + return match.UserBranchName +} + +// allows custom devel branch names in the forge config +func (fc *ForgeConfigs) FindDevelBranch(thing string) string { + var match *ForgeConfig + + all := fc.SortByGoPath() // get the list of repos + for all.Scan() { + r := all.Next() + if r.GoPath == thing { + if r.DevelBranchName != "" { + return r.DevelBranchName + } + } + base := filepath.Base(r.GoPath) + if base == thing { + if r.DevelBranchName != "" { + return r.DevelBranchName + } + } + if r.Directory { + if strings.HasPrefix(thing, r.GoPath) { + match = r + } + } + } + if match == nil { + return "" + } + + return match.DevelBranchName +} + +// allows custom devel branch names in the forge config +func (fc *ForgeConfigs) FindMasterBranch(thing string) string { + var match *ForgeConfig + + all := fc.SortByGoPath() // get the list of repos + for all.Scan() { + r := all.Next() + if r.GoPath == thing { + if r.MasterBranchName != "" { + return r.MasterBranchName + } + } + base := filepath.Base(r.GoPath) + if base == thing { + if r.MasterBranchName != "" { + return r.MasterBranchName + } + } + if r.Directory { + if strings.HasPrefix(thing, r.GoPath) { + match = r + } + } + } + if match == nil { + return "" + } + + return match.MasterBranchName +} diff --git a/forgeConfig.config.go b/forgeConfig.config.go new file mode 100644 index 0000000..6102d03 --- /dev/null +++ b/forgeConfig.config.go @@ -0,0 +1,25 @@ +// Copyright 2025 WIT.COM Inc Licensed GPL 3.0 + +package forgepb + +import ( + "go.wit.com/lib/config" +) + +// functions to import and export the protobuf +// data to and from config files + +// write to ~/.config/forge/ +func (cfg *ForgeConfigs) ConfigSave() error { + var header string + header += "\n" + header += "# this file is intended to be used to customize settings on what\n" + header += "# git repos you have write access to. That is, where you can run 'git push'\n" + header += "\n" + return config.ConfigSaveWithHeader(cfg, header) +} + +// load the ~/.config/forge/ files +func (c *ForgeConfigs) ConfigLoad(fullpath string) error { + return nil +} diff --git a/patchset.Send.go b/patchset.Send.go index eaac09e..1601663 100644 --- a/patchset.Send.go +++ b/patchset.Send.go @@ -5,6 +5,8 @@ package forgepb import ( "errors" + "os" + "path/filepath" "strings" "time" @@ -137,3 +139,32 @@ func (f *Forge) SubmitPatchesNew(pset *Patches, urlpath string) (*Patches, error log.Info("Total patches sent ok:", newpb.Len()) return newpb, nil } + +func loadFile(filename string) ([]byte, error) { + fullname := filepath.Join(os.Getenv("FORGE_CONFIG"), filename) + data, err := os.ReadFile(fullname) + if errors.Is(err, os.ErrNotExist) { + // if file does not exist, just return nil. this + // will cause ConfigLoad() to try the next config file like "forge.text" + // because the user might want to edit the .config by hand + return nil, nil + } + if err != nil { + // log.Info("open config file :", err) + return nil, err + } + return data, nil +} + +func configWrite(filename string, data []byte) error { + fullname := filepath.Join(os.Getenv("FORGE_CONFIG"), filename) + + cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) + defer cfgfile.Close() + if err != nil { + log.Warn("open config file :", err) + return err + } + cfgfile.Write(data) + return nil +} -- cgit v1.2.3