Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
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.
  • Loading branch information
per1234 committed Jun 3, 2021
commit 4674bc7e58ba4fc619d035274a54a570c35aa0cd
54 changes: 45 additions & 9 deletions internal/rule/rulefunction/library.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import (
"net/http"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/arduino/arduino-cli/arduino/libraries"
"github.com/arduino/arduino-cli/arduino/libraries/librariesindex"
"github.com/arduino/arduino-cli/arduino/utils"
"github.com/arduino/arduino-lint/internal/project/library"
"github.com/arduino/arduino-lint/internal/project/projectdata"
Expand Down Expand Up @@ -1187,21 +1189,55 @@ func LibraryPropertiesDependsFieldNotInIndex() (result ruleresult.Type, output s
return ruleresult.Skip, "Field not present"
}

dependencies := commaSeparatedToList(depends)
dependsList := commaSeparatedToList(depends)

dependenciesNotInIndex := []string{}
for _, dependency := range dependencies {
if dependency == "" {
var dependencyRegexp = regexp.MustCompile("^([^()]+?) *(?:\\((.+)\\))?$")
dependsNotInIndex := []string{}
for _, depend := range dependsList {
// Process raw depend string into a dependency object
if depend == "" {
// This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat()
continue
}
logrus.Tracef("Checking if dependency %s is in index.", dependency)
if !nameInLibraryManagerIndex(dependency) {
dependenciesNotInIndex = append(dependenciesNotInIndex, dependency)
dependencyData := dependencyRegexp.FindAllStringSubmatch(depend, -1)
if dependencyData == nil {
// This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat()
continue
}
dependencyConstraint, err := semver.ParseConstraint(dependencyData[0][2])
if err != nil {
// This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat()
continue
}
var dependency semver.Dependency = &librariesindex.Dependency{
Name: dependencyData[0][1],
VersionConstraint: dependencyConstraint,
}

logrus.Tracef("Checking if dependency %s is in index.", depend)
// Get all releases of the dependency
library := projectdata.LibraryManagerIndex().Index.FindIndexedLibrary(&libraries.Library{Name: dependency.GetName()})
if library == nil {
logrus.Tracef("Dependency is not in the index.")
dependsNotInIndex = append(dependsNotInIndex, depend)
continue
}
// Convert the dependency's libraries.Library object to a semver.Releases object
var releases semver.Releases
for _, release := range library.Releases {
releases = append(releases, release)
}
// Filter the dependency's releases according to the dependency's constraint
dependencyReleases := releases.FilterBy(dependency)
if len(dependencyReleases) == 0 {
logrus.Tracef("No releases match dependency's constraint.")
dependsNotInIndex = append(dependsNotInIndex, depend)
continue
}
}

if len(dependenciesNotInIndex) > 0 {
return ruleresult.Fail, strings.Join(dependenciesNotInIndex, ", ")
if len(dependsNotInIndex) > 0 {
return ruleresult.Fail, strings.Join(dependsNotInIndex, ", ")
}

return ruleresult.Pass, ""
Expand Down
5 changes: 4 additions & 1 deletion internal/rule/rulefunction/library_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -808,8 +808,11 @@ func TestLibraryPropertiesDependsFieldInvalidFormat(t *testing.T) {
func TestLibraryPropertiesDependsFieldNotInIndex(t *testing.T) {
testTables := []libraryRuleFunctionTestTable{
{"Unable to load", "InvalidLibraryProperties", ruleresult.NotRun, ""},
{"Legacy", "Legacy", ruleresult.Skip, ""},
{"No depends field", "MissingFields", ruleresult.Skip, ""},
{"Dependency not in index", "DependsNotIndexed", ruleresult.Fail, "^NotIndexed$"},
{"Dependency in index", "DependsIndexed", ruleresult.Pass, ""},
{"Dependency constraint not in index", "DependsConstraintNotIndexed", ruleresult.Fail, "^Servo \\(=0\\.0\\.1\\)$"},
{"Dependencies in index", "DependsIndexed", ruleresult.Pass, ""},
{"Depends field empty", "DependsEmpty", ruleresult.Pass, ""},
{"No depends", "NoDepends", ruleresult.Skip, ""},
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name=DependsConstraintNotIndexed
version=1.0.0
author=Cristian Maglie <[email protected]>, Pippo Pluto <[email protected]>
maintainer=Cristian Maglie <[email protected]>
sentence=A library that makes coding a web server a breeze.
paragraph=Supports HTTP1.1 and you can do GET and POST.
category=Communication
url=http://example.com/
architectures=avr
depends=Servo (=0.0.1)
includes=DependsConstraintNotIndexed.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ paragraph=Supports HTTP1.1 and you can do GET and POST.
category=Communication
url=http://example.com/
architectures=avr
depends=Servo, , Adafruit NeoPixel
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)