Skip to content

Commit 4674bc7

Browse files
committed
Add support for dependency constraints to LP048
The library.properties depends field is used to specify the library dependencies. Although currently undocumented, Arduino CLI and the Library Manager indexer both have provisional support for dependency version constraints. Previously, LP048 did not have any support for the constraint syntax, which caused a spurious failure when they were in use. This commit adds support for the constraint syntax and also causes the constraint information to be used when checking if the dependency is provided by the index.
1 parent 4961340 commit 4674bc7

File tree

5 files changed

+61
-11
lines changed

5 files changed

+61
-11
lines changed

Diff for: internal/rule/rulefunction/library.go

+45-9
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ import (
2222
"net/http"
2323
"os"
2424
"path/filepath"
25+
"regexp"
2526
"strings"
2627

2728
"github.com/arduino/arduino-cli/arduino/libraries"
29+
"github.com/arduino/arduino-cli/arduino/libraries/librariesindex"
2830
"github.com/arduino/arduino-cli/arduino/utils"
2931
"github.com/arduino/arduino-lint/internal/project/library"
3032
"github.com/arduino/arduino-lint/internal/project/projectdata"
@@ -1187,21 +1189,55 @@ func LibraryPropertiesDependsFieldNotInIndex() (result ruleresult.Type, output s
11871189
return ruleresult.Skip, "Field not present"
11881190
}
11891191

1190-
dependencies := commaSeparatedToList(depends)
1192+
dependsList := commaSeparatedToList(depends)
11911193

1192-
dependenciesNotInIndex := []string{}
1193-
for _, dependency := range dependencies {
1194-
if dependency == "" {
1194+
var dependencyRegexp = regexp.MustCompile("^([^()]+?) *(?:\\((.+)\\))?$")
1195+
dependsNotInIndex := []string{}
1196+
for _, depend := range dependsList {
1197+
// Process raw depend string into a dependency object
1198+
if depend == "" {
1199+
// This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat()
11951200
continue
11961201
}
1197-
logrus.Tracef("Checking if dependency %s is in index.", dependency)
1198-
if !nameInLibraryManagerIndex(dependency) {
1199-
dependenciesNotInIndex = append(dependenciesNotInIndex, dependency)
1202+
dependencyData := dependencyRegexp.FindAllStringSubmatch(depend, -1)
1203+
if dependencyData == nil {
1204+
// This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat()
1205+
continue
1206+
}
1207+
dependencyConstraint, err := semver.ParseConstraint(dependencyData[0][2])
1208+
if err != nil {
1209+
// This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat()
1210+
continue
1211+
}
1212+
var dependency semver.Dependency = &librariesindex.Dependency{
1213+
Name: dependencyData[0][1],
1214+
VersionConstraint: dependencyConstraint,
1215+
}
1216+
1217+
logrus.Tracef("Checking if dependency %s is in index.", depend)
1218+
// Get all releases of the dependency
1219+
library := projectdata.LibraryManagerIndex().Index.FindIndexedLibrary(&libraries.Library{Name: dependency.GetName()})
1220+
if library == nil {
1221+
logrus.Tracef("Dependency is not in the index.")
1222+
dependsNotInIndex = append(dependsNotInIndex, depend)
1223+
continue
1224+
}
1225+
// Convert the dependency's libraries.Library object to a semver.Releases object
1226+
var releases semver.Releases
1227+
for _, release := range library.Releases {
1228+
releases = append(releases, release)
1229+
}
1230+
// Filter the dependency's releases according to the dependency's constraint
1231+
dependencyReleases := releases.FilterBy(dependency)
1232+
if len(dependencyReleases) == 0 {
1233+
logrus.Tracef("No releases match dependency's constraint.")
1234+
dependsNotInIndex = append(dependsNotInIndex, depend)
1235+
continue
12001236
}
12011237
}
12021238

1203-
if len(dependenciesNotInIndex) > 0 {
1204-
return ruleresult.Fail, strings.Join(dependenciesNotInIndex, ", ")
1239+
if len(dependsNotInIndex) > 0 {
1240+
return ruleresult.Fail, strings.Join(dependsNotInIndex, ", ")
12051241
}
12061242

12071243
return ruleresult.Pass, ""

Diff for: internal/rule/rulefunction/library_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -808,8 +808,11 @@ func TestLibraryPropertiesDependsFieldInvalidFormat(t *testing.T) {
808808
func TestLibraryPropertiesDependsFieldNotInIndex(t *testing.T) {
809809
testTables := []libraryRuleFunctionTestTable{
810810
{"Unable to load", "InvalidLibraryProperties", ruleresult.NotRun, ""},
811+
{"Legacy", "Legacy", ruleresult.Skip, ""},
812+
{"No depends field", "MissingFields", ruleresult.Skip, ""},
811813
{"Dependency not in index", "DependsNotIndexed", ruleresult.Fail, "^NotIndexed$"},
812-
{"Dependency in index", "DependsIndexed", ruleresult.Pass, ""},
814+
{"Dependency constraint not in index", "DependsConstraintNotIndexed", ruleresult.Fail, "^Servo \\(=0\\.0\\.1\\)$"},
815+
{"Dependencies in index", "DependsIndexed", ruleresult.Pass, ""},
813816
{"Depends field empty", "DependsEmpty", ruleresult.Pass, ""},
814817
{"No depends", "NoDepends", ruleresult.Skip, ""},
815818
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name=DependsConstraintNotIndexed
2+
version=1.0.0
3+
author=Cristian Maglie <[email protected]>, Pippo Pluto <[email protected]>
4+
maintainer=Cristian Maglie <[email protected]>
5+
sentence=A library that makes coding a web server a breeze.
6+
paragraph=Supports HTTP1.1 and you can do GET and POST.
7+
category=Communication
8+
url=http://example.com/
9+
architectures=avr
10+
depends=Servo (=0.0.1)
11+
includes=DependsConstraintNotIndexed.h

Diff for: internal/rule/rulefunction/testdata/libraries/DependsConstraintNotIndexed/src/DependsConstraintNotIndexed.h

Whitespace-only changes.

Diff for: internal/rule/rulefunction/testdata/libraries/DependsIndexed/library.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ paragraph=Supports HTTP1.1 and you can do GET and POST.
77
category=Communication
88
url=http://example.com/
99
architectures=avr
10-
depends=Servo, , Adafruit NeoPixel
10+
depends=,(foo),foo (bar),Adafruit NeoPixel,Servo (<1.1.4),Stepper (<=1.1.3),Mouse (=1.0.0),Keyboard (>=1.0.1),WiFiNINA (>1.0.0)

0 commit comments

Comments
 (0)