package meta import ( "encoding/json" "errors" "fmt" "io/fs" "os" "path/filepath" "runtime" "strings" "go.jolheiser.com/eget/disk" ) type Meta struct { Packages map[string]Package `json:"packages"` } type Package struct { Repo string `json:"repo"` Version string `json:"version"` } func Upsert(name, repo, version string) error { m, err := Read() if err != nil { return err } for n := range m.Packages { if strings.EqualFold(n, name) { m.Packages[n] = Package{ Repo: repo, Version: version, } return save(m) } } m.Packages[name] = Package{ Repo: repo, Version: version, } return save(m) } func Read() (Meta, error) { m := Meta{ Packages: make(map[string]Package), } fp := metaPath() fi, err := os.Open(fp) if err != nil { if errors.Is(err, fs.ErrNotExist) { return m, json.Unmarshal([]byte(`{}`), &m) } return m, fmt.Errorf("could not open meta file: %w", err) } defer fi.Close() if err := json.NewDecoder(fi).Decode(&m); err != nil { return m, fmt.Errorf("could not decode meta: %w", err) } return m, nil } func Remove(name string) error { m, err := Read() if err != nil { return err } for n := range m.Packages { if strings.EqualFold(n, name) { delete(m.Packages, name) return save(m) } } return fmt.Errorf("could not find package to remove for %q", name) } func metaPath() string { home, err := os.UserHomeDir() if err != nil { home = "." } return filepath.Join(home, ".eget", "packages.json") } func save(m Meta) error { fp := metaPath() fi, err := os.Create(fp) if err != nil { return fmt.Errorf("could not create meta file: %w", err) } if err := json.NewEncoder(fi).Encode(m); err != nil { return err } if err := fi.Close(); err != nil { return err } if err := m.writeShellEnv("nu"); err != nil { return err } if err := m.writeShellEnv("sh"); err != nil { return err } if err := m.writeShellEnv("ps1"); err != nil { return err } return nil } func (m Meta) writeShellEnv(shell string) error { var tmpl string switch shell { case "nu": path := "PATH" if runtime.GOOS == "windows" { path = "Path" } tmpl = fmt.Sprintf("let-env %[1]s = ($env.%[1]s | append %%q)\n", path) case "sh": tmpl = "PATH=$PATH:%s\n" case "ps1": tmpl = `$env:Path = "$env:Path;%s"` + "\n" default: return errors.New("shell not recognized") } home, err := os.UserHomeDir() if err != nil { home = "." } fp := filepath.Join(home, ".eget", "eget."+shell) fi, err := os.Create(fp) if err != nil { return err } defer fi.Close() var out strings.Builder out.WriteString("# managed by eget; DO NOT EDIT\n\n") for name := range m.Packages { out.WriteString(fmt.Sprintf(tmpl, disk.Path(name))) } fi.WriteString(out.String()) return nil }