Skip to content

Commit 3162bb9

Browse files
committed
Imported "closest match" library matcher from upstream arduino-builder
See arduino/arduino-builder#310
1 parent 7b8f7ff commit 3162bb9

File tree

3 files changed

+85
-16
lines changed

3 files changed

+85
-16
lines changed

Diff for: Gopkg.lock

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: arduino/libraries/librariesresolver/cpp.go

+47-9
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/arduino/arduino-cli/arduino/libraries"
2626
"github.com/arduino/arduino-cli/arduino/libraries/librariesmanager"
2727
"github.com/arduino/arduino-cli/arduino/utils"
28+
"github.com/schollz/closestmatch"
2829
"github.com/sirupsen/logrus"
2930
)
3031

@@ -77,31 +78,46 @@ func (resolver *Cpp) AlternativesFor(header string) libraries.List {
7778
// header and architecture. If no libraries provides the requested header, nil is returned
7879
func (resolver *Cpp) ResolveFor(header, architecture string) *libraries.Library {
7980
logrus.Infof("Resolving include %s for arch %s", header, architecture)
80-
var found *libraries.Library
81+
var found libraries.List
8182
var foundPriority int
8283
for _, lib := range resolver.headers[header] {
8384
libPriority := computePriority(lib, header, architecture)
8485
msg := " discarded"
8586
if found == nil || foundPriority < libPriority {
86-
found = lib
87+
found = libraries.List{}
88+
found.Add(lib)
8789
foundPriority = libPriority
8890
msg = " found better lib"
91+
} else if foundPriority == libPriority {
92+
found.Add(lib)
93+
msg = " found another lib with same priority"
8994
}
9095
logrus.
9196
WithField("lib", lib.Name).
9297
WithField("prio", fmt.Sprintf("%03X", libPriority)).
9398
Infof(msg)
9499
}
95-
return found
100+
if found == nil {
101+
return nil
102+
}
103+
if len(found) == 1 {
104+
return found[0]
105+
}
106+
107+
// If more than one library qualifies use the "closestmatch" algorithm to
108+
// find the best matching one (instead of choosing it randomly)
109+
winner := findLibraryWithNameBestDistance(header, found)
110+
logrus.WithField("lib", winner.Name).Info(" library with the best mathing name")
111+
return winner
96112
}
97113

98-
func computePriority(lib *libraries.Library, header, arch string) int {
99-
simplify := func(name string) string {
100-
name = utils.SanitizeName(name)
101-
name = strings.ToLower(name)
102-
return name
103-
}
114+
func simplify(name string) string {
115+
name = utils.SanitizeName(name)
116+
name = strings.ToLower(name)
117+
return name
118+
}
104119

120+
func computePriority(lib *libraries.Library, header, arch string) int {
105121
header = strings.TrimSuffix(header, filepath.Ext(header))
106122
header = simplify(header)
107123
name := simplify(lib.Name)
@@ -120,3 +136,25 @@ func computePriority(lib *libraries.Library, header, arch string) int {
120136
}
121137
return priority
122138
}
139+
140+
func findLibraryWithNameBestDistance(name string, libs libraries.List) *libraries.Library {
141+
// Create closestmatch DB
142+
var wordsToTest []string
143+
for _, lib := range libs {
144+
wordsToTest = append(wordsToTest, simplify(lib.Name))
145+
}
146+
// Choose a set of bag sizes, more is more accurate but slower
147+
bagSizes := []int{2}
148+
149+
// Create a closestmatch object and find the best matching name
150+
cm := closestmatch.New(wordsToTest, bagSizes)
151+
closestName := cm.Closest(name)
152+
153+
// Return the closest-matching lib
154+
for _, lib := range libs {
155+
if closestName == simplify(lib.Name) {
156+
return lib
157+
}
158+
}
159+
return nil
160+
}

Diff for: arduino/libraries/librariesresolver/cpp_test.go

+29-7
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,45 @@ import (
2424
"github.com/stretchr/testify/require"
2525
)
2626

27-
func TestCppHeaderPriority(t *testing.T) {
28-
l1 := &libraries.Library{Name: "Calculus Lib", Location: libraries.Sketchbook}
29-
l2 := &libraries.Library{Name: "Calculus Lib-master", Location: libraries.Sketchbook}
30-
l3 := &libraries.Library{Name: "Calculus Lib Improved", Location: libraries.Sketchbook}
31-
l4 := &libraries.Library{Name: "Another Calculus Lib", Location: libraries.Sketchbook}
32-
l5 := &libraries.Library{Name: "Yet Another Calculus Lib Improved", Location: libraries.Sketchbook}
33-
l6 := &libraries.Library{Name: "AnotherLib", Location: libraries.Sketchbook}
27+
var l1 = &libraries.Library{Name: "Calculus Lib", Location: libraries.Sketchbook}
28+
var l2 = &libraries.Library{Name: "Calculus Lib-master", Location: libraries.Sketchbook}
29+
var l3 = &libraries.Library{Name: "Calculus Lib Improved", Location: libraries.Sketchbook}
30+
var l4 = &libraries.Library{Name: "Another Calculus Lib", Location: libraries.Sketchbook}
31+
var l5 = &libraries.Library{Name: "Yet Another Calculus Lib Improved", Location: libraries.Sketchbook}
32+
var l6 = &libraries.Library{Name: "Calculus Unified Lib", Location: libraries.Sketchbook}
33+
var l7 = &libraries.Library{Name: "AnotherLib", Location: libraries.Sketchbook}
3434

35+
func TestCppHeaderPriority(t *testing.T) {
3536
r1 := computePriority(l1, "calculus_lib.h", "avr")
3637
r2 := computePriority(l2, "calculus_lib.h", "avr")
3738
r3 := computePriority(l3, "calculus_lib.h", "avr")
3839
r4 := computePriority(l4, "calculus_lib.h", "avr")
3940
r5 := computePriority(l5, "calculus_lib.h", "avr")
4041
r6 := computePriority(l6, "calculus_lib.h", "avr")
42+
r7 := computePriority(l7, "calculus_lib.h", "avr")
4143
require.True(t, r1 > r2)
4244
require.True(t, r2 > r3)
4345
require.True(t, r3 > r4)
4446
require.True(t, r4 > r5)
4547
require.True(t, r5 > r6)
48+
require.True(t, r6 == r7)
49+
}
50+
51+
func TestCppHeaderResolver(t *testing.T) {
52+
resolve := func(header string, libs ...*libraries.Library) string {
53+
resolver := NewCppResolver()
54+
librarylist := libraries.List{}
55+
for _, lib := range libs {
56+
librarylist.Add(lib)
57+
}
58+
resolver.headers[header] = librarylist
59+
return resolver.ResolveFor(header, "avr").Name
60+
}
61+
require.Equal(t, "Calculus Lib", resolve("calculus_lib.h", l1, l2, l3, l4, l5, l6, l7))
62+
require.Equal(t, "Calculus Lib-master", resolve("calculus_lib.h", l2, l3, l4, l5, l6, l7))
63+
require.Equal(t, "Calculus Lib Improved", resolve("calculus_lib.h", l3, l4, l5, l6, l7))
64+
require.Equal(t, "Another Calculus Lib", resolve("calculus_lib.h", l4, l5, l6, l7))
65+
require.Equal(t, "Yet Another Calculus Lib Improved", resolve("calculus_lib.h", l5, l6, l7))
66+
require.Equal(t, "Calculus Unified Lib", resolve("calculus_lib.h", l6, l7))
67+
require.Equal(t, "Calculus Unified Lib", resolve("calculus_lib.h", l7, l6))
4668
}

0 commit comments

Comments
 (0)