From 74d360f6d7c50fd9a312b666f8fcfb3df99f4803 Mon Sep 17 00:00:00 2001 From: stephen mcquay Date: Fri, 2 Mar 2018 23:23:11 -0800 Subject: [PATCH] Adds pm pull --- available.go | 12 ++++++++++ available_test.go | 10 ++++++++ meta.go | 7 +++++- remote/pull.go | 59 +++++++++++++++++++++++++++++++++++++++++++++-- remote/remote.go | 10 ++++---- 5 files changed, 90 insertions(+), 8 deletions(-) diff --git a/available.go b/available.go index fc2d0a2..89e0b51 100644 --- a/available.go +++ b/available.go @@ -1,6 +1,8 @@ package pm import ( + "net/url" + "github.com/pkg/errors" ) @@ -38,3 +40,13 @@ func (a Available) Update(o Available) error { } return nil } + +func (a Available) SetRemote(u url.URL) { + for n, vers := range a { + for v, _ := range vers { + m := a[n][v] + m.Remote = u + a[n][v] = m + } + } +} diff --git a/available_test.go b/available_test.go index 18f466c..4c87420 100644 --- a/available_test.go +++ b/available_test.go @@ -2,6 +2,7 @@ package pm import ( "errors" + "net/url" "testing" ) @@ -92,4 +93,13 @@ func TestAvailableUpdate(t *testing.T) { if got, want := a["a"]["v1.0.0"].Description, "test last in"; got != want { t.Fatalf("last in didn't override") } + + u, err := url.Parse("https://pm.mcquay.me/darwin/amd64") + if err != nil { + t.Fatalf("parsing url: %v", err) + } + a.SetRemote(*u) + if got, want := a["a"]["v1.0.0"].Remote, *u; got != want { + t.Fatalf("last in didn't override") + } } diff --git a/meta.go b/meta.go index f6ff091..fade179 100644 --- a/meta.go +++ b/meta.go @@ -1,6 +1,9 @@ package pm -import "errors" +import ( + "errors" + "net/url" +) // Meta tracks metadata for a package type Meta struct { @@ -8,6 +11,8 @@ type Meta struct { Version Version `json:"version"` Description string `json:"description"` Namespace string `json:"namespace"` + + Remote url.URL `json:"remote"` } // Valid validates the contents of a Meta for requires fields. diff --git a/remote/pull.go b/remote/pull.go index 5204052..add328f 100644 --- a/remote/pull.go +++ b/remote/pull.go @@ -1,8 +1,63 @@ package remote -import "github.com/pkg/errors" +import ( + "encoding/json" + "net/http" + "os" + "path/filepath" + + "github.com/pkg/errors" + "mcquay.me/pm" +) + +const an = "var/lib/pm/available.json" // Pull updates the available package database. func Pull(root string) error { - return errors.New("NYI") + 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 { + return errors.Wrap(err, "decode remote available") + } + a.SetRemote(u) + o.Update(a) + } + if err := saveAvailable(root, o); err != nil { + return errors.Wrap(err, "saving available db") + } + return nil +} + +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 } diff --git a/remote/remote.go b/remote/remote.go index 8e438ff..93b9247 100644 --- a/remote/remote.go +++ b/remote/remote.go @@ -15,7 +15,7 @@ import ( // DB is a slice of available URI type DB []url.URL -const fn = "var/lib/pm/available.json" +const rn = "var/lib/pm/remotes.json" // Add appends the provided uri to the list of configured remotes. func Add(root string, uris []string) error { @@ -93,13 +93,13 @@ func List(root string, w io.Writer) error { func load(root string) (DB, error) { r := DB{} - dbn := filepath.Join(root, fn) + dbn := filepath.Join(root, rn) if !fs.Exists(dbn) { return r, nil } - f, err := os.Open(filepath.Join(root, fn)) + f, err := os.Open(filepath.Join(root, rn)) if err != nil { return r, errors.Wrap(err, "open") } @@ -112,7 +112,7 @@ func load(root string) (DB, error) { } func save(root string, db DB) error { - f, err := os.Create(filepath.Join(root, fn)) + f, err := os.Create(filepath.Join(root, rn)) if err != nil { return errors.Wrap(err, "create") } @@ -140,7 +140,7 @@ func strip(u url.URL) url.URL { } func mkdirs(root string) error { - d, _ := filepath.Split(filepath.Join(root, fn)) + d, _ := filepath.Split(filepath.Join(root, rn)) if !fs.Exists(d) { if err := os.MkdirAll(d, 0700); err != nil { return errors.Wrap(err, "mk pm dir")