// Package config keeps the Hammerhead address and token between runs. package config import ( "encoding/json" "errors" "os" "path/filepath" "strings" ) type Config struct { Hammerhead string `json:"hammerhead"` Token string `json:"token"` } // Path is where `shark login` saves the settings; SHARK_CONFIG overrides it. func Path() (string, error) { if p := os.Getenv("SHARK_CONFIG"); p != "" { return p, nil } dir, err := os.UserConfigDir() if err != nil { return "", err } return filepath.Join(dir, "shark", "config.json"), nil } // Load reads the saved settings, then lets SHARK_HAMMERHEAD and SHARK_TOKEN override them. // A missing file is not an error. func Load() (Config, error) { var c Config p, err := Path() if err == nil { b, rerr := os.ReadFile(p) switch { case rerr == nil: if err := json.Unmarshal(b, &c); err != nil { return c, errors.New(p + " is not valid JSON: " + err.Error()) } case !errors.Is(rerr, os.ErrNotExist): return c, rerr } } if v := os.Getenv("SHARK_HAMMERHEAD"); v != "" { c.Hammerhead = v } if v := os.Getenv("SHARK_TOKEN"); v != "" { c.Token = v } c.Hammerhead = strings.TrimRight(c.Hammerhead, "/") return c, nil } // Save writes the settings so that only the user can read them (the token is a credential). func Save(c Config) (string, error) { p, err := Path() if err != nil { return "", err } if err := os.MkdirAll(filepath.Dir(p), 0o700); err != nil { return "", err } b, _ := json.MarshalIndent(c, "", " ") return p, os.WriteFile(p, append(b, '\n'), 0o600) }