Unverified Commit 38a80a62 authored by tuckerrrrrrrrrr's avatar tuckerrrrrrrrrr Committed by GitHub

Show similar library names in lib search (#598)

* Show similar library names in lib search

* make similarity threshold for lib search a package variable

* Add library search tests

* Redo name asserts in TestSearchLibrary

Just check that the library names have "Test" in them instead of
checking the names at each index, which won't always be the same
parent e8bb3278
...@@ -88,8 +88,8 @@ func (res result) Data() interface{} { ...@@ -88,8 +88,8 @@ func (res result) Data() interface{} {
names := []LibName{} names := []LibName{}
results := res.results.GetLibraries() results := res.results.GetLibraries()
for _, lsr := range results { for _, lib := range results {
names = append(names, LibName{lsr.Name}) names = append(names, LibName{lib.Name})
} }
return NamesOnly{ return NamesOnly{
...@@ -113,9 +113,18 @@ func (res result) String() string { ...@@ -113,9 +113,18 @@ func (res result) String() string {
var out strings.Builder var out strings.Builder
if res.results.GetStatus() == rpc.LibrarySearchStatus_failed {
out.WriteString("No libraries matching your search.\nDid you mean...\n")
}
for _, lib := range results { for _, lib := range results {
out.WriteString(fmt.Sprintf("Name: \"%s\"\n", lib.Name)) if res.results.GetStatus() == rpc.LibrarySearchStatus_success {
if res.namesOnly { out.WriteString(fmt.Sprintf("Name: \"%s\"\n", lib.Name))
if res.namesOnly {
continue
}
} else {
out.WriteString(fmt.Sprintf("%s\n", lib.Name))
continue continue
} }
......
...@@ -21,11 +21,15 @@ import ( ...@@ -21,11 +21,15 @@ import (
"strings" "strings"
"github.com/arduino/arduino-cli/arduino/libraries/librariesindex" "github.com/arduino/arduino-cli/arduino/libraries/librariesindex"
"github.com/arduino/arduino-cli/arduino/libraries/librariesmanager"
"github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/commands"
rpc "github.com/arduino/arduino-cli/rpc/commands" rpc "github.com/arduino/arduino-cli/rpc/commands"
"github.com/imjasonmiller/godice"
semver "go.bug.st/relaxed-semver" semver "go.bug.st/relaxed-semver"
) )
var similarityThreshold = 0.7
// LibrarySearch FIXMEDOC // LibrarySearch FIXMEDOC
func LibrarySearch(ctx context.Context, req *rpc.LibrarySearchReq) (*rpc.LibrarySearchResp, error) { func LibrarySearch(ctx context.Context, req *rpc.LibrarySearchReq) (*rpc.LibrarySearchResp, error) {
lm := commands.GetLibraryManager(req.GetInstance().GetId()) lm := commands.GetLibraryManager(req.GetInstance().GetId())
...@@ -33,7 +37,12 @@ func LibrarySearch(ctx context.Context, req *rpc.LibrarySearchReq) (*rpc.Library ...@@ -33,7 +37,12 @@ func LibrarySearch(ctx context.Context, req *rpc.LibrarySearchReq) (*rpc.Library
return nil, errors.New("invalid instance") return nil, errors.New("invalid instance")
} }
return searchLibrary(req, lm)
}
func searchLibrary(req *rpc.LibrarySearchReq, lm *librariesmanager.LibrariesManager) (*rpc.LibrarySearchResp, error) {
res := []*rpc.SearchedLibrary{} res := []*rpc.SearchedLibrary{}
status := rpc.LibrarySearchStatus_success
for _, lib := range lm.Index.Libraries { for _, lib := range lm.Index.Libraries {
qry := strings.ToLower(req.GetQuery()) qry := strings.ToLower(req.GetQuery())
...@@ -46,16 +55,27 @@ func LibrarySearch(ctx context.Context, req *rpc.LibrarySearchReq) (*rpc.Library ...@@ -46,16 +55,27 @@ func LibrarySearch(ctx context.Context, req *rpc.LibrarySearchReq) (*rpc.Library
} }
latest := GetLibraryParameters(lib.Latest) latest := GetLibraryParameters(lib.Latest)
searchedlib := &rpc.SearchedLibrary{ searchedLib := &rpc.SearchedLibrary{
Name: lib.Name, Name: lib.Name,
Releases: releases, Releases: releases,
Latest: latest, Latest: latest,
} }
res = append(res, searchedlib) res = append(res, searchedLib)
}
}
if len(res) == 0 {
status = rpc.LibrarySearchStatus_failed
for _, lib := range lm.Index.Libraries {
if godice.CompareString(req.GetQuery(), lib.Name) > similarityThreshold {
res = append(res, &rpc.SearchedLibrary{
Name: lib.Name,
})
}
} }
} }
return &rpc.LibrarySearchResp{Libraries: res}, nil return &rpc.LibrarySearchResp{Libraries: res, Status: status}, nil
} }
// GetLibraryParameters FIXMEDOC // GetLibraryParameters FIXMEDOC
......
package lib
import (
"strings"
"testing"
"github.com/arduino/arduino-cli/arduino/libraries/librariesmanager"
rpc "github.com/arduino/arduino-cli/rpc/commands"
paths "github.com/arduino/go-paths-helper"
"github.com/stretchr/testify/assert"
)
var customIndexPath = paths.New("testdata")
func TestSearchLibrary(t *testing.T) {
lm := librariesmanager.NewLibraryManager(customIndexPath, nil)
lm.LoadIndex()
req := &rpc.LibrarySearchReq{
Instance: &rpc.Instance{Id: 1},
Query: "test",
}
resp, err := searchLibrary(req, lm)
if err != nil {
t.Fatal(err)
}
assert := assert.New(t)
assert.Equal(resp.GetStatus(), rpc.LibrarySearchStatus_success)
assert.Equal(len(resp.GetLibraries()), 2)
assert.True(strings.Contains(resp.GetLibraries()[0].Name, "Test"))
assert.True(strings.Contains(resp.GetLibraries()[1].Name, "Test"))
}
func TestSearchLibrarySimilar(t *testing.T) {
lm := librariesmanager.NewLibraryManager(customIndexPath, nil)
lm.LoadIndex()
req := &rpc.LibrarySearchReq{
Instance: &rpc.Instance{Id: 1},
Query: "ardino",
}
resp, err := searchLibrary(req, lm)
if err != nil {
t.Fatal(err)
}
assert := assert.New(t)
assert.Equal(resp.GetStatus(), rpc.LibrarySearchStatus_failed)
assert.Equal(len(resp.GetLibraries()), 1)
assert.Equal(resp.GetLibraries()[0].Name, "Arduino")
}
{
"libraries": [
{
"name": "ArduinoTestPackage"
},
{
"name": "Arduino"
},
{
"name": "Test"
}
]
}
...@@ -19,6 +19,7 @@ require ( ...@@ -19,6 +19,7 @@ require (
github.com/gofrs/uuid v3.2.0+incompatible github.com/gofrs/uuid v3.2.0+incompatible
github.com/golang/protobuf v1.3.3 github.com/golang/protobuf v1.3.3
github.com/h2non/filetype v1.0.8 // indirect github.com/h2non/filetype v1.0.8 // indirect
github.com/imjasonmiller/godice v0.1.2
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 // indirect github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 // indirect
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 // indirect github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 // indirect
github.com/juju/testing v0.0.0-20190429233213-dfc56b8c09fc // indirect github.com/juju/testing v0.0.0-20190429233213-dfc56b8c09fc // indirect
......
...@@ -20,6 +20,31 @@ var _ = math.Inf ...@@ -20,6 +20,31 @@ var _ = math.Inf
// proto package needs to be updated. // proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type LibrarySearchStatus int32
const (
LibrarySearchStatus_failed LibrarySearchStatus = 0
LibrarySearchStatus_success LibrarySearchStatus = 1
)
var LibrarySearchStatus_name = map[int32]string{
0: "failed",
1: "success",
}
var LibrarySearchStatus_value = map[string]int32{
"failed": 0,
"success": 1,
}
func (x LibrarySearchStatus) String() string {
return proto.EnumName(LibrarySearchStatus_name, int32(x))
}
func (LibrarySearchStatus) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_9feed0d29806df6c, []int{0}
}
type LibraryLayout int32 type LibraryLayout int32
const ( const (
...@@ -42,7 +67,7 @@ func (x LibraryLayout) String() string { ...@@ -42,7 +67,7 @@ func (x LibraryLayout) String() string {
} }
func (LibraryLayout) EnumDescriptor() ([]byte, []int) { func (LibraryLayout) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_9feed0d29806df6c, []int{0} return fileDescriptor_9feed0d29806df6c, []int{1}
} }
type LibraryLocation int32 type LibraryLocation int32
...@@ -73,7 +98,7 @@ func (x LibraryLocation) String() string { ...@@ -73,7 +98,7 @@ func (x LibraryLocation) String() string {
} }
func (LibraryLocation) EnumDescriptor() ([]byte, []int) { func (LibraryLocation) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_9feed0d29806df6c, []int{1} return fileDescriptor_9feed0d29806df6c, []int{2}
} }
type LibraryDownloadReq struct { type LibraryDownloadReq struct {
...@@ -649,10 +674,11 @@ func (m *LibrarySearchReq) GetQuery() string { ...@@ -649,10 +674,11 @@ func (m *LibrarySearchReq) GetQuery() string {
} }
type LibrarySearchResp struct { type LibrarySearchResp struct {
Libraries []*SearchedLibrary `protobuf:"bytes,1,rep,name=libraries,proto3" json:"libraries,omitempty"` Libraries []*SearchedLibrary `protobuf:"bytes,1,rep,name=libraries,proto3" json:"libraries,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` Status LibrarySearchStatus `protobuf:"varint,2,opt,name=status,proto3,enum=cc.arduino.cli.commands.LibrarySearchStatus" json:"status,omitempty"`
XXX_unrecognized []byte `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *LibrarySearchResp) Reset() { *m = LibrarySearchResp{} } func (m *LibrarySearchResp) Reset() { *m = LibrarySearchResp{} }
...@@ -687,6 +713,13 @@ func (m *LibrarySearchResp) GetLibraries() []*SearchedLibrary { ...@@ -687,6 +713,13 @@ func (m *LibrarySearchResp) GetLibraries() []*SearchedLibrary {
return nil return nil
} }
func (m *LibrarySearchResp) GetStatus() LibrarySearchStatus {
if m != nil {
return m.Status
}
return LibrarySearchStatus_failed
}
type SearchedLibrary struct { type SearchedLibrary struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Releases map[string]*LibraryRelease `protobuf:"bytes,2,rep,name=releases,proto3" json:"releases,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Releases map[string]*LibraryRelease `protobuf:"bytes,2,rep,name=releases,proto3" json:"releases,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
...@@ -1352,6 +1385,7 @@ func (m *Library) GetLayout() LibraryLayout { ...@@ -1352,6 +1385,7 @@ func (m *Library) GetLayout() LibraryLayout {
} }
func init() { func init() {
proto.RegisterEnum("cc.arduino.cli.commands.LibrarySearchStatus", LibrarySearchStatus_name, LibrarySearchStatus_value)
proto.RegisterEnum("cc.arduino.cli.commands.LibraryLayout", LibraryLayout_name, LibraryLayout_value) proto.RegisterEnum("cc.arduino.cli.commands.LibraryLayout", LibraryLayout_name, LibraryLayout_value)
proto.RegisterEnum("cc.arduino.cli.commands.LibraryLocation", LibraryLocation_name, LibraryLocation_value) proto.RegisterEnum("cc.arduino.cli.commands.LibraryLocation", LibraryLocation_name, LibraryLocation_value)
proto.RegisterType((*LibraryDownloadReq)(nil), "cc.arduino.cli.commands.LibraryDownloadReq") proto.RegisterType((*LibraryDownloadReq)(nil), "cc.arduino.cli.commands.LibraryDownloadReq")
......
...@@ -82,8 +82,14 @@ message LibrarySearchReq { ...@@ -82,8 +82,14 @@ message LibrarySearchReq {
string query = 2; string query = 2;
} }
enum LibrarySearchStatus {
failed = 0;
success = 1;
}
message LibrarySearchResp { message LibrarySearchResp {
repeated SearchedLibrary libraries = 1; repeated SearchedLibrary libraries = 1;
LibrarySearchStatus status = 2;
} }
message SearchedLibrary { message SearchedLibrary {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment