This repository has been archived on 2023-11-08. You can view files and clone it, but cannot push or open issues/pull-requests.
eget/meta/meta.go

150 lines
2.7 KiB
Go

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
}