diff --git a/advisor/backend.go b/advisor/backend.go index bde83db3538..917bc99ea0b 100644 --- a/advisor/backend.go +++ b/advisor/backend.go @@ -20,8 +20,8 @@ package advisor import ( + "encoding/json" "os" - "strings" "time" "github.com/snapcore/bolt" @@ -45,7 +45,7 @@ type writer struct { type CommandDB interface { // AddSnap adds the entries for commands pointing to the given // snap name to the commands database. - AddSnap(snapName, summary string, commands []string) error + AddSnap(snapName, version, summary string, commands []string) error // Commit persist the changes, and closes the database. If the // database has already been committed/rollbacked, does nothing. Commit() error @@ -98,23 +98,38 @@ func Create() (CommandDB, error) { return t, nil } -func (t *writer) AddSnap(snapName, summary string, commands []string) error { - bname := []byte(snapName) - +func (t *writer) AddSnap(snapName, version, summary string, commands []string) error { for _, cmd := range commands { + var sil []Package + bcmd := []byte(cmd) row := t.cmdBucket.Get(bcmd) - if row == nil { - row = bname - } else { - row = append(append(row, ','), bname...) + if row != nil { + if err := json.Unmarshal(row, &sil); err != nil { + return err + } + } + // For the mapping of command->snap we do not need the summary, nothing is using that. + sil = append(sil, Package{Snap: snapName, Version: version}) + row, err := json.Marshal(sil) + if err != nil { + return err } if err := t.cmdBucket.Put(bcmd, row); err != nil { return err } } - if err := t.pkgBucket.Put([]byte(snapName), []byte(summary)); err != nil { + // TODO: use json here as well and put the version information here + bj, err := json.Marshal(Package{ + Snap: snapName, + Version: version, + Summary: summary, + }) + if err != nil { + return err + } + if err := t.pkgBucket.Put([]byte(snapName), bj); err != nil { return err } @@ -154,7 +169,7 @@ func (t *writer) done(commit bool) error { // DumpCommands returns the whole database as a map. For use in // testing and debugging. -func DumpCommands() (map[string][]string, error) { +func DumpCommands() (map[string]string, error) { db, err := bolt.Open(dirs.SnapCommandsDB, 0644, &bolt.Options{ ReadOnly: true, Timeout: 1 * time.Second, @@ -175,10 +190,10 @@ func DumpCommands() (map[string][]string, error) { return nil, nil } - m := map[string][]string{} + m := map[string]string{} c := b.Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { - m[string(k)] = strings.Split(string(v), ",") + m[string(k)] = string(v) } return m, nil @@ -224,12 +239,15 @@ func (f *boltFinder) FindCommand(command string) ([]Command, error) { if buf == nil { return nil, nil } - - snaps := strings.Split(string(buf), ",") - cmds := make([]Command, len(snaps)) - for i, snap := range snaps { + var sil []Package + if err := json.Unmarshal(buf, &sil); err != nil { + return nil, err + } + cmds := make([]Command, len(sil)) + for i, si := range sil { cmds[i] = Command{ - Snap: snap, + Snap: si.Snap, + Version: si.Version, Command: command, } } @@ -249,10 +267,15 @@ func (f *boltFinder) FindPackage(pkgName string) (*Package, error) { return nil, nil } - bsummary := b.Get([]byte(pkgName)) - if bsummary == nil { + bj := b.Get([]byte(pkgName)) + if bj == nil { return nil, nil } + var si Package + err = json.Unmarshal(bj, &si) + if err != nil { + return nil, err + } - return &Package{Snap: pkgName, Summary: string(bsummary)}, nil + return &Package{Snap: pkgName, Version: si.Version, Summary: si.Summary}, nil } diff --git a/advisor/cmdfinder.go b/advisor/cmdfinder.go index 1c103e5e64e..7cfadb5c681 100644 --- a/advisor/cmdfinder.go +++ b/advisor/cmdfinder.go @@ -25,6 +25,7 @@ import ( type Command struct { Snap string + Version string `json:"Version,omitempty"` Command string } diff --git a/advisor/cmdfinder_test.go b/advisor/cmdfinder_test.go index 6a30849eff8..5a83e5409c4 100644 --- a/advisor/cmdfinder_test.go +++ b/advisor/cmdfinder_test.go @@ -44,8 +44,8 @@ func (s *cmdfinderSuite) SetUpTest(c *C) { db, err := advisor.Create() c.Assert(err, IsNil) - c.Assert(db.AddSnap("foo", "foo summary", []string{"foo", "meh"}), IsNil) - c.Assert(db.AddSnap("bar", "bar summary", []string{"bar", "meh"}), IsNil) + c.Assert(db.AddSnap("foo", "1.0", "foo summary", []string{"foo", "meh"}), IsNil) + c.Assert(db.AddSnap("bar", "2.0", "bar summary", []string{"bar", "meh"}), IsNil) c.Assert(db.Commit(), IsNil) } @@ -99,8 +99,8 @@ func (s *cmdfinderSuite) TestFindCommandHit(c *C) { cmds, err := advisor.FindCommand("meh") c.Assert(err, IsNil) c.Check(cmds, DeepEquals, []advisor.Command{ - {Snap: "foo", Command: "meh"}, - {Snap: "bar", Command: "meh"}, + {Snap: "foo", Version: "1.0", Command: "meh"}, + {Snap: "bar", Version: "2.0", Command: "meh"}, }) } @@ -114,8 +114,8 @@ func (s *cmdfinderSuite) TestFindMisspelledCommandHit(c *C) { cmds, err := advisor.FindMisspelledCommand("moh") c.Assert(err, IsNil) c.Check(cmds, DeepEquals, []advisor.Command{ - {Snap: "foo", Command: "meh"}, - {Snap: "bar", Command: "meh"}, + {Snap: "foo", Version: "1.0", Command: "meh"}, + {Snap: "bar", Version: "2.0", Command: "meh"}, }) } @@ -128,10 +128,10 @@ func (s *cmdfinderSuite) TestFindMisspelledCommandMiss(c *C) { func (s *cmdfinderSuite) TestDumpCommands(c *C) { cmds, err := advisor.DumpCommands() c.Assert(err, IsNil) - c.Check(cmds, DeepEquals, map[string][]string{ - "foo": {"foo"}, - "bar": {"bar"}, - "meh": {"foo", "bar"}, + c.Check(cmds, DeepEquals, map[string]string{ + "foo": `[{"snap":"foo","version":"1.0"}]`, + "bar": `[{"snap":"bar","version":"2.0"}]`, + "meh": `[{"snap":"foo","version":"1.0"},{"snap":"bar","version":"2.0"}]`, }) } diff --git a/advisor/pkgfinder.go b/advisor/pkgfinder.go index a210d2c145e..bae4f820e57 100644 --- a/advisor/pkgfinder.go +++ b/advisor/pkgfinder.go @@ -24,8 +24,9 @@ import ( ) type Package struct { - Snap string - Summary string + Snap string `json:"snap"` + Version string `json:"version"` + Summary string `json:"summary,omitempty"` } func FindPackage(pkgName string) (*Package, error) { diff --git a/advisor/pkgfinder_test.go b/advisor/pkgfinder_test.go new file mode 100644 index 00000000000..fd08017bf8f --- /dev/null +++ b/advisor/pkgfinder_test.go @@ -0,0 +1,40 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2018 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package advisor_test + +import ( + . "gopkg.in/check.v1" + + "github.com/snapcore/snapd/advisor" +) + +func (s *cmdfinderSuite) TestFindPackageHit(c *C) { + pkg, err := advisor.FindPackage("foo") + c.Assert(err, IsNil) + c.Check(pkg, DeepEquals, &advisor.Package{ + Snap: "foo", Version: "1.0", Summary: "foo summary", + }) +} + +func (s *cmdfinderSuite) TestFindPackageMiss(c *C) { + pkg, err := advisor.FindPackage("moh") + c.Assert(err, IsNil) + c.Check(pkg, IsNil) +} diff --git a/overlord/snapstate/catalogrefresh_test.go b/overlord/snapstate/catalogrefresh_test.go index 474521c2da9..7180f823f6b 100644 --- a/overlord/snapstate/catalogrefresh_test.go +++ b/overlord/snapstate/catalogrefresh_test.go @@ -1,7 +1,7 @@ // -*- Mode: Go; indent-tabs-mode: t -*- /* - * Copyright (C) 2017 Canonical Ltd + * Copyright (C) 2017-2018 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -50,8 +50,8 @@ func (r *catalogStore) WriteCatalogs(ctx context.Context, w io.Writer, a store.S } r.ops = append(r.ops, "write-catalog") w.Write([]byte("pkg1\npkg2")) - a.AddSnap("foo", "foo summary", []string{"foo", "meh"}) - a.AddSnap("bar", "bar summray", []string{"bar", "meh"}) + a.AddSnap("foo", "1.0", "foo summary", []string{"foo", "meh"}) + a.AddSnap("bar", "2.0", "bar summray", []string{"bar", "meh"}) return nil } @@ -105,10 +105,10 @@ func (s *catalogRefreshTestSuite) TestCatalogRefresh(c *C) { c.Check(osutil.FileExists(dirs.SnapCommandsDB), Equals, true) dump, err := advisor.DumpCommands() c.Assert(err, IsNil) - c.Check(dump, DeepEquals, map[string][]string{ - "foo": {"foo"}, - "bar": {"bar"}, - "meh": {"foo", "bar"}, + c.Check(dump, DeepEquals, map[string]string{ + "foo": `[{"snap":"foo","version":"1.0"}]`, + "bar": `[{"snap":"bar","version":"2.0"}]`, + "meh": `[{"snap":"foo","version":"1.0"},{"snap":"bar","version":"2.0"}]`, }) } diff --git a/store/store.go b/store/store.go index b43482af9c5..d3cca618408 100644 --- a/store/store.go +++ b/store/store.go @@ -675,13 +675,14 @@ type alias struct { type catalogItem struct { Name string `json:"package_name"` + Version string `json:"version"` Summary string `json:"summary"` Aliases []alias `json:"aliases"` Apps []string `json:"apps"` } type SnapAdder interface { - AddSnap(snapName, summary string, commands []string) error + AddSnap(snapName, version, summary string, commands []string) error } func decodeCatalog(resp *http.Response, names io.Writer, db SnapAdder) error { @@ -722,7 +723,7 @@ func decodeCatalog(resp *http.Response, names io.Writer, db SnapAdder) error { commands = append(commands, snap.JoinSnapApp(v.Name, app)) } - if err := db.AddSnap(v.Name, v.Summary, commands); err != nil { + if err := db.AddSnap(v.Name, v.Version, v.Summary, commands); err != nil { return err } } diff --git a/store/store_test.go b/store/store_test.go index c0d4cec2d75..39e32fc3f83 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -2855,12 +2855,14 @@ const mockNamesJSON = ` "apps": ["baz"], "title": "a title", "summary": "oneary plus twoary", - "package_name": "bar" + "package_name": "bar", + "version": "2.0" }, { "aliases": [{"name": "meh", "target": "foo"}], "apps": ["foo"], - "package_name": "foo" + "package_name": "foo", + "version": "1.0" } ] } @@ -2921,11 +2923,11 @@ func (s *storeTestSuite) testSnapCommands(c *C, onClassic bool) { dump, err := advisor.DumpCommands() c.Assert(err, IsNil) - c.Check(dump, DeepEquals, map[string][]string{ - "foo": {"foo"}, - "bar.baz": {"bar"}, - "potato": {"bar"}, - "meh": {"bar", "foo"}, + c.Check(dump, DeepEquals, map[string]string{ + "foo": `[{"snap":"foo","version":"1.0"}]`, + "bar.baz": `[{"snap":"bar","version":"2.0"}]`, + "potato": `[{"snap":"bar","version":"2.0"}]`, + "meh": `[{"snap":"bar","version":"2.0"},{"snap":"foo","version":"1.0"}]`, }) }