pm/db/available.go

114 lines
2.4 KiB
Go
Raw Normal View History

2018-03-02 23:23:13 -08:00
package db
2018-03-02 23:23:04 -08:00
2018-03-02 23:23:11 -08:00
import (
"encoding/json"
2018-03-02 23:23:13 -08:00
"fmt"
"io"
2018-03-02 23:23:11 -08:00
"net/http"
"os"
"path/filepath"
2018-03-02 23:23:13 -08:00
"sort"
2018-03-02 23:23:11 -08:00
"github.com/pkg/errors"
2018-03-02 23:23:13 -08:00
"mcquay.me/fs"
2018-03-02 23:23:11 -08:00
"mcquay.me/pm"
)
const an = "var/lib/pm/available.json"
2018-03-02 23:23:04 -08:00
// Pull updates the available package database.
func Pull(root string) error {
2018-03-02 23:23:11 -08:00
db, err := load(root)
if err != nil {
return errors.Wrap(err, "loading db")
}
o := pm.Available{}
// Order here is important: the guarantee made is that any packages that
// exist in multiple remotes will be fetched by the first configured
// remote, which is why we traverse the database in reverse.
//
// TODO (sm): make this concurrent
for i := range db {
u := db[len(db)-i-1]
resp, err := http.Get(u.String() + "/available.json")
if err != nil {
return errors.Wrap(err, "http get")
}
a := pm.Available{}
if err := json.NewDecoder(resp.Body).Decode(&a); err != nil {
2018-03-02 23:23:14 -08:00
return errors.Wrapf(err, "decode remote available for %q", u.String())
2018-03-02 23:23:11 -08:00
}
a.SetRemote(u)
o.Update(a)
}
if err := saveAvailable(root, o); err != nil {
return errors.Wrap(err, "saving available db")
}
return nil
}
2018-03-02 23:23:13 -08:00
// ListAvailable prints all installable packages
func ListAvailable(root string, w io.Writer) error {
db, err := loadAvailable(root)
if err != nil {
return errors.Wrap(err, "loading")
}
names := pm.Names{}
nvs := map[pm.Name]pm.Versions{}
for n, vers := range db {
names = append(names, n)
for v := range vers {
nvs[n] = append(nvs[n], v)
}
sort.Sort(nvs[n])
}
sort.Sort(names)
for _, n := range names {
for _, v := range nvs[n] {
m := db[n][v]
fmt.Fprintf(w, "%v\t%v\t%v\n", m.Name, m.Version, m.Remote.String())
}
}
return nil
}
func loadAvailable(root string) (pm.Available, error) {
r := pm.Available{}
dbn := filepath.Join(root, rn)
if !fs.Exists(dbn) {
return r, nil
}
f, err := os.Open(filepath.Join(root, an))
if err != nil {
return r, errors.Wrap(err, "open")
}
if err := json.NewDecoder(f).Decode(&r); err != nil {
return r, errors.Wrap(err, "decoding db")
}
return r, nil
}
2018-03-02 23:23:11 -08:00
func saveAvailable(root string, db pm.Available) error {
f, err := os.Create(filepath.Join(root, an))
if err != nil {
return errors.Wrap(err, "create")
}
enc := json.NewEncoder(f)
enc.SetIndent("", "\t")
if err := enc.Encode(&db); err != nil {
return errors.Wrap(err, "decoding db")
}
if err := f.Close(); err != nil {
return errors.Wrap(err, "close db")
}
return nil
2018-03-02 23:23:04 -08:00
}