From 020a374c70128bd514fff3360205dcabe8414a5a Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 15 Jan 2019 19:27:03 +0100 Subject: [PATCH 1/2] Use lexicographic distance as last chance to spot the right library Should solve most "overload" cases in Create. Eg: Library ZZ_Sensor contains ZZ_Sensor.h but the name in library.properties is "ZZ Unified Sensor" A sketch includes ZZ_Sensor.h and the resolve function fails every test (since the library name is not contained in any variation of the "include" string), so it uses another clashing library randomly. Lexicographic distance should help avoiding any library with "very different" name (unless explicitely requested, of course). --- resolve_library.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/resolve_library.go b/resolve_library.go index dd96ab75..849940be 100644 --- a/resolve_library.go +++ b/resolve_library.go @@ -36,6 +36,7 @@ import ( "github.com/arduino/arduino-builder/constants" "github.com/arduino/arduino-builder/types" "github.com/arduino/arduino-builder/utils" + "github.com/schollz/closestmatch" ) func ResolveLibrary(ctx *types.Context, header string) *types.Library { @@ -211,6 +212,10 @@ func findBestLibraryWithHeader(header string, libraries []*types.Library) *types if library != nil { return library } + library = findLibWithNameBestDistance(headerName, libraries) + if library != nil { + return library + } } return nil @@ -252,6 +257,28 @@ func findLibWithNameContaining(name string, libraries []*types.Library) *types.L return nil } +func findLibWithNameBestDistance(name string, libraries []*types.Library) *types.Library { + // create closestmatch DB + var wordsToTest []string + + for _, library := range libraries { + wordsToTest = append(wordsToTest, simplifyName(library.Name)) + } + // Choose a set of bag sizes, more is more accurate but slower + bagSizes := []int{2} + // Create a closestmatch object + cm := closestmatch.New(wordsToTest, bagSizes) + closest_name := cm.Closest(name) + + for _, library := range libraries { + if (closest_name == simplifyName(library.Name)) { + return library + } + } + + return nil +} + func simplifyName(name string) string { return strings.ToLower(strings.Replace(name, "_", " ", -1)) } From eff1eeb3dd0f856ca8e0fa39f502150ea11ac073 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 16 Jan 2019 10:34:30 +0100 Subject: [PATCH 2/2] Add test for partially matching lib name --- resolve_library_test.go | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/resolve_library_test.go b/resolve_library_test.go index 5d421216..1eff3c53 100644 --- a/resolve_library_test.go +++ b/resolve_library_test.go @@ -43,29 +43,38 @@ func TestFindBestLibraryWithHeader(t *testing.T) { l3 := &types.Library{Name: "Calculus Lib Improved"} l4 := &types.Library{Name: "Another Calculus Lib"} l5 := &types.Library{Name: "Yet Another Calculus Lib Improved"} - l6 := &types.Library{Name: "AnotherLib"} + l6 := &types.Library{Name: "Calculus Unified Lib"} + l7 := &types.Library{Name: "AnotherLib"} // Test exact name matching - res := findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l6, l5, l4, l3, l2, l1}) + res := findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l7, l6, l5, l4, l3, l2, l1}) require.Equal(t, l1.Name, res.Name) // Test exact name with "-master" postfix matching - res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l6, l5, l4, l3, l2}) + res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l7, l6, l5, l4, l3, l2}) require.Equal(t, l2.Name, res.Name) // Test prefix matching - res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l6, l5, l4, l3}) + res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l7, l6, l5, l4, l3}) require.Equal(t, l3.Name, res.Name) // Test postfix matching - res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l6, l5, l4}) + res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l7, l6, l5, l4}) require.Equal(t, l4.Name, res.Name) // Test "contains"" matching - res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l6, l5}) + res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l7, l6, l5}) require.Equal(t, l5.Name, res.Name) + // Test lexicographic similarity matching + res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l7, l6}) + require.Equal(t, l6.Name, res.Name) + + // Test lexicographic similarity matching (2) + res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l6, l7}) + require.Equal(t, l6.Name, res.Name) + // Test none matching - res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l6}) - require.Nil(t, res) + res = findBestLibraryWithHeader("calculus_lib.h", []*types.Library{l7}) + require.Equal(t, l7.Name, res.Name) }