diff --git a/argv.go b/argv.go index eebcfa3..5d5b795 100644 --- a/argv.go +++ b/argv.go @@ -20,7 +20,6 @@ type args struct { Clean *CleanCmd `arg:"subcommand:clean" help:"start over at the beginning"` Commit *CommitCmd `arg:"subcommand:commit" help:"'git commit' but errors out if on wrong branch"` Config *ConfigCmd `arg:"subcommand:config" help:"show your .config/forge/ settings"` - Debug *EmptyCmd `arg:"subcommand:debug" help:"debug forge"` Dirty *DirtyCmd `arg:"subcommand:dirty" help:"show dirty git repos"` GitFetch *FindCmd `arg:"subcommand:fetch" help:"run 'git fetch master'"` Gui *EmptyCmd `arg:"subcommand:gui" help:"open the gui"` diff --git a/config.go b/config.go new file mode 100644 index 0000000..01721d9 --- /dev/null +++ b/config.go @@ -0,0 +1,71 @@ +package main + +// functions to import and export the protobuf +// data to and from config files + +import ( + "errors" + "fmt" + "os" + "strings" + + "go.wit.com/lib/config" + "go.wit.com/lib/protobuf/forgepb" + "go.wit.com/log" +) + +func forgeConfigSave() error { + return config.ConfigSave(me.forge.Config) +} + +func configInit() (*forgepb.ForgeConfigs, error) { + /* + // the default forged dir is /home/forge + if os.Getenv("FORGE_GOSRC") == "" { + os.Setenv("FORGE_GOSRC", "/home/forge") + } + + if os.Getenv("FORGE_PATCHDIR") == "" { + os.Setenv("FORGE_PATCHDIR", "/var/lib/forged") + } + */ + + me.urlbase = argv.URL + if me.urlbase == "" { + me.urlbase = "https://go.wit.com/" + } + if os.Getenv("FORGE_URL") != "" { + me.urlbase = os.Getenv("FORGE_URL") + log.Info("got forge url", me.urlbase) + } + me.urlbase = strings.Trim(me.urlbase, "/") // track down why trailing '/' makes http POST not work + + configs := new(forgepb.ForgeConfigs) + err := config.ConfigLoad(configs, ARGNAME, "forge") + if errors.Is(err, os.ErrNotExist) { + // if forgepb.FirstTimeUser() { + log.Info("You are running forge for the first time here") + // } + configs.ReposDir = "/home/forge" + configs.ReposPB = "/home/forge/repos.pb" + configs.PatchDir = "/var/lib/forged" + if err := forgeConfigSave(); err != nil { + return nil, err + } + log.Info("WARNING: made a new default config file here", configs.Filename) + okExit("") + } + if err != nil { + } + return configs, err +} + +func sampleConfig(all *forgepb.ForgeConfigs) { + new1 := new(forgepb.ForgeConfig) + new1.GoPath = "go.wit.com" + new1.Writable = true + new1.Directory = true + all.Append(new1) + + fmt.Println("first time user. adding an example config file with", len(all.ForgeConfigs), "repos") +} diff --git a/doDebug.go b/doDebug.go deleted file mode 100644 index f900332..0000000 --- a/doDebug.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2017-2025 WIT.COM Inc. All rights reserved. -// Use of this source code is governed by the GPL 3.0 - -package main - -import ( - "bytes" - "fmt" - "io" - "log" - "reflect" - "unicode/utf8" - - "go.wit.com/lib/protobuf/bugpb" - "go.wit.com/lib/protobuf/forgepb" - "golang.org/x/text/encoding/charmap" - "google.golang.org/protobuf/proto" -) - -func doDebug() { - me.forge = forgepb.InitPB() - me.forge.ScanGoSrc() - if err := me.forge.ConfigSave(); err != nil { - if err := me.forge.Repos.ConfigSave(); err != nil { - err := ValidateProtoUTF8(me.forge.Repos) - if err != nil { - log.Printf("Protobuf UTF-8 validation failed: %v\n", err) - } - if err := bugpb.SanitizeProtoUTF8(me.forge.Repos); err != nil { - log.Fatalf("Sanitization failed: %v", err) - } - } - // badExit(err) - } - me.forge.SetConfigSave(true) - me.forge.Exit() - okExit("this never runs") -} - -// ValidateProtoUTF8 checks all string fields in a proto.Message recursively. -func ValidateProtoUTF8(msg proto.Message) error { - return validateValue(reflect.ValueOf(msg), "") -} - -func validateValue(val reflect.Value, path string) error { - if !val.IsValid() { - return nil - } - - if val.Kind() == reflect.Ptr { - if val.IsNil() { - return nil - } - return validateValue(val.Elem(), path) - } - - switch val.Kind() { - case reflect.Struct: - for i := 0; i < val.NumField(); i++ { - field := val.Field(i) - fieldType := val.Type().Field(i) - fieldPath := fmt.Sprintf("%s.%s", path, fieldType.Name) - if err := validateValue(field, fieldPath); err != nil { - return err - } - } - - case reflect.String: - s := val.String() - if !utf8.ValidString(s) { - return fmt.Errorf("invalid UTF-8 string at %s: %q", path, s) - } - - case reflect.Slice: - if val.Type().Elem().Kind() == reflect.Uint8 { - return nil // skip []byte - } - for i := 0; i < val.Len(); i++ { - if err := validateValue(val.Index(i), fmt.Sprintf("%s[%d]", path, i)); err != nil { - return err - } - } - - case reflect.Map: - for _, key := range val.MapKeys() { - valItem := val.MapIndex(key) - if err := validateValue(valItem, fmt.Sprintf("%s[%v]", path, key)); err != nil { - return err - } - } - } - - return nil -} - -// SanitizeProtoUTF8 fixes all invalid UTF-8 strings in a proto.Message recursively. -func SanitizeProtoUTF8(msg proto.Message) error { - return sanitizeValue(reflect.ValueOf(msg), "") -} - -func sanitizeValue(val reflect.Value, path string) error { - if !val.IsValid() { - return nil - } - - if val.Kind() == reflect.Ptr { - if val.IsNil() { - return nil - } - return sanitizeValue(val.Elem(), path) - } - - switch val.Kind() { - case reflect.Struct: - for i := 0; i < val.NumField(); i++ { - field := val.Field(i) - fieldType := val.Type().Field(i) - if !field.CanSet() { - continue - } - if err := sanitizeValue(field, fmt.Sprintf("%s.%s", path, fieldType.Name)); err != nil { - return err - } - } - - case reflect.String: - s := val.String() - if !utf8.ValidString(s) { - utf8Str, err := latin1ToUTF8(s) - if err != nil { - return fmt.Errorf("failed to convert %s to UTF-8: %v", path, err) - } - val.SetString(utf8Str) - } - - case reflect.Slice: - if val.Type().Elem().Kind() == reflect.Uint8 { - return nil // skip []byte - } - for i := 0; i < val.Len(); i++ { - if err := sanitizeValue(val.Index(i), fmt.Sprintf("%s[%d]", path, i)); err != nil { - return err - } - } - - case reflect.Map: - for _, key := range val.MapKeys() { - valItem := val.MapIndex(key) - newItem := reflect.New(valItem.Type()).Elem() - newItem.Set(valItem) - if err := sanitizeValue(newItem, fmt.Sprintf("%s[%v]", path, key)); err != nil { - return err - } - val.SetMapIndex(key, newItem) - } - } - - return nil -} - -func latin1ToUTF8(input string) (string, error) { - reader := charmap.ISO8859_1.NewDecoder().Reader(bytes.NewReader([]byte(input))) - result, err := io.ReadAll(reader) - if err != nil { - return "", err - } - return string(result), nil -} diff --git a/main.go b/main.go index d4526a8..c9a4061 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,6 @@ package main import ( "embed" "fmt" - "os" "strings" "time" @@ -50,37 +49,12 @@ func main() { me.myGui = prep.Gui() // prepares the GUI package for go-args me.pp = arg.MustParse(&argv) - /* - if argv.Bash { - fhelp.DoBash(ARGNAME) - os.Exit(0) - } - if len(argv.BashAuto) != 0 { - argv.doBashAuto() - os.Exit(0) - } - */ - me.urlbase = argv.URL - if me.urlbase == "" { - me.urlbase = "https://go.wit.com/" - } - if os.Getenv("FORGE_URL") != "" { - me.urlbase = os.Getenv("FORGE_URL") - log.Info("got forge url", me.urlbase) - } - me.urlbase = strings.Trim(me.urlbase, "/") // track down why trailing '/' makes http POST not work - - // internally debugging can be triggered here before Init() - if argv.Debug != nil { - doDebug() - okExit("") - } - - if forgepb.FirstTimeUser() { - log.Info("You are running forge for the first time here") - } // load the ~/.config/forge/ config - me.forge = forgepb.Init() + cfg, err := configInit() + if err != nil { + badExit(err) + } + me.forge = forgepb.InitFromConfig(cfg) // initialize patches doPatchInit()