Skip to content

Commit a915ba8

Browse files
committed
Add rule for constraint syntax in library.properties depends field
Arduino CLI and the Library Manager system have support for specifying version constraints in the library.properties `depends` field. This was previously validated as part of the general `depends` field data format check in LP047. The constraint system has recently been made much more capable through the addition of support for more syntax. The previous approach for validating the version constraint was a complex and lengthy regular expression in the library.properties JSON schema. Extending this to comprehensively validate the full range of constraint forms possible with the new syntax will not be feasible or maintainable. The new approach is to validate it using the same `go.bug.st/relaxed-semver` module used by Arduino CLI and `arduino/libraries-repository-engine` to handle the version constraints in this field.
1 parent 1db0941 commit a915ba8

File tree

7 files changed

+81
-0
lines changed

7 files changed

+81
-0
lines changed

Diff for: internal/rule/ruleconfiguration/ruleconfiguration.go

+17
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,23 @@ var configurations = []Type{
11131113
ErrorModes: nil,
11141114
RuleFunction: rulefunction.LibraryPropertiesDependsFieldNotInIndex,
11151115
},
1116+
{
1117+
ProjectType: projecttype.Library,
1118+
SuperprojectType: projecttype.All,
1119+
Category: "library.properties",
1120+
Subcategory: "depends field",
1121+
ID: "LP058",
1122+
Brief: "invalid depends constraint syntax",
1123+
Description: "The `depends` field in the library's `library.properties` metadata file uses invalid version constraint syntax.",
1124+
MessageTemplate: "library.properties depends field item(s) {{.}} have invalid constraint syntax.",
1125+
Reference: "https://arduino.github.io/arduino-cli/latest/library-specification/#libraryproperties-file-format",
1126+
DisableModes: nil,
1127+
EnableModes: []rulemode.Type{rulemode.Default},
1128+
InfoModes: nil,
1129+
WarningModes: nil,
1130+
ErrorModes: []rulemode.Type{rulemode.Default},
1131+
RuleFunction: rulefunction.LibraryPropertiesDependsFieldConstraintInvalid,
1132+
},
11161133
{
11171134
ProjectType: projecttype.Library,
11181135
SuperprojectType: projecttype.All,

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

+28
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,34 @@ func LibraryPropertiesDependsFieldNotInIndex() (result ruleresult.Type, output s
12391239
return ruleresult.Pass, ""
12401240
}
12411241

1242+
// LibraryPropertiesDependsFieldConstraintInvalid checks whether the syntax of the version constraints in the
1243+
// library.properties `depends` field is valid.
1244+
func LibraryPropertiesDependsFieldConstraintInvalid() (result ruleresult.Type, output string) {
1245+
if projectdata.LibraryPropertiesLoadError() != nil {
1246+
return ruleresult.NotRun, "Couldn't load library.properties"
1247+
}
1248+
1249+
depends, hasDepends := projectdata.LibraryProperties().GetOk("depends")
1250+
if !hasDepends {
1251+
return ruleresult.Skip, "Field not present"
1252+
}
1253+
1254+
dependencies := libDependencies(depends)
1255+
1256+
nonCompliant := []string{}
1257+
for _, dependency := range dependencies {
1258+
if dependency.parseConstraintErr != nil {
1259+
nonCompliant = append(nonCompliant, dependency.depend)
1260+
}
1261+
}
1262+
1263+
if len(nonCompliant) > 0 {
1264+
return ruleresult.Fail, strings.Join(nonCompliant, ", ")
1265+
}
1266+
1267+
return ruleresult.Pass, ""
1268+
}
1269+
12421270
// LibraryPropertiesDotALinkageFieldInvalid checks for invalid value in the library.properties "dot_a_linkage" field.
12431271
func LibraryPropertiesDotALinkageFieldInvalid() (result ruleresult.Type, output string) {
12441272
if projectdata.LibraryPropertiesLoadError() != nil {

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

+14
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,20 @@ func TestLibraryPropertiesDependsFieldNotInIndex(t *testing.T) {
846846
checkLibraryRuleFunction(LibraryPropertiesDependsFieldNotInIndex, testTables, t)
847847
}
848848

849+
func TestLibraryPropertiesDependsFieldConstraintInvalid(t *testing.T) {
850+
testTables := []libraryRuleFunctionTestTable{
851+
{"Unable to load", "InvalidLibraryProperties", ruleresult.NotRun, ""},
852+
{"Legacy", "Legacy", ruleresult.Skip, ""},
853+
{"No depends field", "NoDepends", ruleresult.Skip, ""},
854+
{"Depends field empty", "DependsEmpty", ruleresult.Pass, ""},
855+
{"Invalid depends field format", "DependsHasBadChars", ruleresult.Pass, ""},
856+
{"Invalid constraint syntax", "DependsConstraintInvalid", ruleresult.Fail, "^BarLib \\(nope\\), QuxLib \\(huh\\)$"},
857+
{"Valid constraint syntax", "DependsConstraintValid", ruleresult.Pass, ""},
858+
}
859+
860+
checkLibraryRuleFunction(LibraryPropertiesDependsFieldConstraintInvalid, testTables, t)
861+
}
862+
849863
func TestLibraryPropertiesDotALinkageFieldInvalid(t *testing.T) {
850864
testTables := []libraryRuleFunctionTestTable{
851865
{"Invalid", "InvalidLibraryProperties", ruleresult.NotRun, ""},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name=DependsConstraintInvalid
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=FooLib (=0.0.1),BarLib (nope),BazLib (=1.2.3),QuxLib (huh)
11+
includes=DependsConstraintInvalid.h

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

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name=DependsConstraintValid
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=LibA (=0.0.1),LibB (>1.0.0),LibC (>=1.0.0),LibD (<2.0.0),LibE (<=2.0.0),LibF (!=1.0.0),LibG (<1.0.0 || >2.0.0),LibH ((>0.1.0 && <2.0.0) || >2.1.0),LibI (),LibJ
11+
includes=DependsConstraintValid.h

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

Whitespace-only changes.

0 commit comments

Comments
 (0)