Skip to content

Commit cfefa1a

Browse files
committed
Add support for version constraints in depends field
Arduino CLI and the Library Manager indexer has some provisional support for specifying version constraints in the library.properties depends field. Although undocumented, this syntax is fully supported by the other tools, so Arduino Lint's previous treatment of libraries using this feature as invalid is incorrect.
1 parent 455001d commit cfefa1a

File tree

8 files changed

+70
-34
lines changed

8 files changed

+70
-34
lines changed

Diff for: etc/schemas/arduino-library-properties-definitions-schema.json

+2-13
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,7 @@
2121
"allowedCharacters": {
2222
"allOf": [
2323
{
24-
"$ref": "#/definitions/propertiesObjects/depends/base/definitions/patternObject"
25-
},
26-
{
27-
"not": {
28-
"$comment": "The depends property is a comma separated list of names, so a valid name pattern is a valid depends pattern with the comma excluded",
29-
"pattern": "^.*,.*$"
30-
}
24+
"pattern": "^(([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))*$"
3125
}
3226
]
3327
}
@@ -494,18 +488,13 @@
494488
},
495489
"depends": {
496490
"base": {
497-
"definitions": {
498-
"patternObject": {
499-
"pattern": "^(([a-zA-Z][a-zA-Z0-9 _\\.\\-,]*)|([0-9][a-zA-Z0-9 _\\.\\-]*[a-zA-Z][a-zA-Z0-9 _\\.\\-,]*))*$"
500-
}
501-
},
502491
"object": {
503492
"allOf": [
504493
{
505494
"type": "string"
506495
},
507496
{
508-
"$ref": "#/definitions/propertiesObjects/depends/base/definitions/patternObject"
497+
"pattern": "^((((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?), *)*((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?))?$"
509498
}
510499
]
511500
}

Diff for: internal/project/library/libraryproperties/librarypropertiesschemas_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -330,13 +330,60 @@ func TestPropertiesUrlFormat(t *testing.T) {
330330

331331
func TestPropertiesDependsPattern(t *testing.T) {
332332
testTables := []propertyValueTestTable{
333+
{"Valid name", "foo", compliancelevel.Permissive, assert.False},
334+
{"Valid name", "foo", compliancelevel.Specification, assert.False},
335+
{"Valid name", "foo", compliancelevel.Strict, assert.False},
336+
337+
{"Valid names", "foo,bar", compliancelevel.Permissive, assert.False},
338+
{"Valid names", "foo,bar", compliancelevel.Specification, assert.False},
339+
{"Valid names", "foo,bar", compliancelevel.Strict, assert.False},
340+
341+
{"Trailing comma", "foo,", compliancelevel.Permissive, assert.True},
342+
{"Trailing comma", "foo,", compliancelevel.Specification, assert.True},
343+
{"Trailing comma", "foo,", compliancelevel.Strict, assert.True},
344+
333345
{"Invalid characters", "-foo", compliancelevel.Permissive, assert.True},
334346
{"Invalid characters", "-foo", compliancelevel.Specification, assert.True},
335347
{"Invalid characters", "-foo", compliancelevel.Strict, assert.True},
336348

337349
{"Empty", "", compliancelevel.Permissive, assert.False},
338350
{"Empty", "", compliancelevel.Specification, assert.False},
339351
{"Empty", "", compliancelevel.Strict, assert.False},
352+
353+
{"<version", "foo (<1.2.3)", compliancelevel.Permissive, assert.False},
354+
{"<version", "foo (<1.2.3)", compliancelevel.Specification, assert.False},
355+
{"<version", "foo (<1.2.3)", compliancelevel.Strict, assert.False},
356+
{"<=version", "foo (<=1.2.3)", compliancelevel.Permissive, assert.False},
357+
{"<=version", "foo (<=1.2.3)", compliancelevel.Specification, assert.False},
358+
{"<=version", "foo (<=1.2.3)", compliancelevel.Strict, assert.False},
359+
{"=version", "foo (=1.2.3)", compliancelevel.Permissive, assert.False},
360+
{"=version", "foo (=1.2.3)", compliancelevel.Specification, assert.False},
361+
{"=version", "foo (=1.2.3)", compliancelevel.Strict, assert.False},
362+
{">=version", "foo (>=1.2.3)", compliancelevel.Permissive, assert.False},
363+
{">=version", "foo (>=1.2.3)", compliancelevel.Specification, assert.False},
364+
{">=version", "foo (>=1.2.3)", compliancelevel.Strict, assert.False},
365+
{">version", "foo (>1.2.3)", compliancelevel.Permissive, assert.False},
366+
{">version", "foo (>1.2.3)", compliancelevel.Specification, assert.False},
367+
{">version", "foo (>1.2.3)", compliancelevel.Strict, assert.False},
368+
369+
{"Relaxed version", "foo (=1.2)", compliancelevel.Permissive, assert.False},
370+
{"Relaxed version", "foo (=1.2)", compliancelevel.Specification, assert.False},
371+
{"Relaxed version", "foo (=1.2)", compliancelevel.Strict, assert.False},
372+
{"Pre-release version", "foo (=1.2.3-rc1)", compliancelevel.Permissive, assert.False},
373+
{"Pre-release version", "foo (=1.2.3-rc1)", compliancelevel.Specification, assert.False},
374+
{"Pre-release version", "foo (=1.2.3-rc1)", compliancelevel.Strict, assert.False},
375+
376+
{"Invalid version", "foo (bar)", compliancelevel.Permissive, assert.True},
377+
{"Invalid version", "foo (bar)", compliancelevel.Specification, assert.True},
378+
{"Invalid version", "foo (bar)", compliancelevel.Strict, assert.True},
379+
380+
{"Version w/o space", "foo(>1.2.3)", compliancelevel.Permissive, assert.True},
381+
{"Version w/o space", "foo(>1.2.3)", compliancelevel.Specification, assert.True},
382+
{"Version w/o space", "foo(>1.2.3)", compliancelevel.Strict, assert.True},
383+
384+
{"Names w/ version", "foo (<=1.2.3),bar", compliancelevel.Permissive, assert.False},
385+
{"Names w/ version", "foo (<=1.2.3),bar", compliancelevel.Specification, assert.False},
386+
{"Names w/ version", "foo (<=1.2.3),bar", compliancelevel.Strict, assert.False},
340387
}
341388

342389
checkPropertyPatternMismatch("depends", testTables, t)

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -1007,15 +1007,15 @@ var configurations = []Type{
10071007
Category: "library.properties",
10081008
Subcategory: "depends field",
10091009
ID: "LP047",
1010-
Brief: "prohibited character in depends",
1010+
Brief: "invalid depends format",
10111011
Description: "",
1012-
MessageTemplate: "Prohibited character(s) in library.properties depends field {{.}}. See: https://arduino.github.io/arduino-cli/latest/library-specification/#libraryproperties-file-format",
1012+
MessageTemplate: "Invalid format of library.properties depends field {{.}}. See: https://arduino.github.io/arduino-cli/latest/library-specification/#libraryproperties-file-format",
10131013
DisableModes: nil,
10141014
EnableModes: []rulemode.Type{rulemode.Default},
10151015
InfoModes: nil,
10161016
WarningModes: nil,
10171017
ErrorModes: []rulemode.Type{rulemode.Default},
1018-
RuleFunction: rulefunction.LibraryPropertiesDependsFieldDisallowedCharacters,
1018+
RuleFunction: rulefunction.LibraryPropertiesDependsFieldInvalidFormat,
10191019
},
10201020
{
10211021
ProjectType: projecttype.Library,

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1158,8 +1158,8 @@ func LibraryPropertiesArchitecturesFieldValueCase() (result ruleresult.Type, out
11581158
return ruleresult.Pass, ""
11591159
}
11601160

1161-
// LibraryPropertiesDependsFieldDisallowedCharacters checks for disallowed characters in the library.properties "depends" field.
1162-
func LibraryPropertiesDependsFieldDisallowedCharacters() (result ruleresult.Type, output string) {
1161+
// LibraryPropertiesDependsFieldInvalidFormat checks for disallowed characters in the library.properties "depends" field.
1162+
func LibraryPropertiesDependsFieldInvalidFormat() (result ruleresult.Type, output string) {
11631163
if projectdata.LibraryPropertiesLoadError() != nil {
11641164
return ruleresult.NotRun, "Couldn't load library.properties"
11651165
}

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -794,15 +794,15 @@ func TestLibraryPropertiesArchitecturesFieldValueCase(t *testing.T) {
794794
checkLibraryRuleFunction(LibraryPropertiesArchitecturesFieldValueCase, testTables, t)
795795
}
796796

797-
func TestLibraryPropertiesDependsFieldDisallowedCharacters(t *testing.T) {
797+
func TestLibraryPropertiesDependsFieldInvalidFormat(t *testing.T) {
798798
testTables := []libraryRuleFunctionTestTable{
799799
{"Invalid", "InvalidLibraryProperties", ruleresult.NotRun, ""},
800800
{"Legacy", "Legacy", ruleresult.Skip, ""},
801801
{"Depends field has disallowed characters", "DependsHasBadChars", ruleresult.Fail, ""},
802-
{"Valid", "DependsIndexed", ruleresult.Pass, ""},
802+
{"Valid", "DependsValid", ruleresult.Pass, ""},
803803
}
804804

805-
checkLibraryRuleFunction(LibraryPropertiesDependsFieldDisallowedCharacters, testTables, t)
805+
checkLibraryRuleFunction(LibraryPropertiesDependsFieldInvalidFormat, testTables, t)
806806
}
807807

808808
func TestLibraryPropertiesDependsFieldNotInIndex(t *testing.T) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name=DependsValid
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 , Adafruit NeoPixel,Stepper (<1.1.3) , Mouse (<=1.0.0),Keyboard (=1.2.3-beta),Ethernet (>=2.0),WiFiNINA (>0.0.8)
11+
includes=DependsValid.h

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

Whitespace-only changes.

Diff for: internal/rule/schema/schemadata/bindata.go

+2-13
Original file line numberDiff line numberDiff line change
@@ -1440,13 +1440,7 @@ var _arduinoLibraryPropertiesDefinitionsSchemaJson = []byte(`{
14401440
"allowedCharacters": {
14411441
"allOf": [
14421442
{
1443-
"$ref": "#/definitions/propertiesObjects/depends/base/definitions/patternObject"
1444-
},
1445-
{
1446-
"not": {
1447-
"$comment": "The depends property is a comma separated list of names, so a valid name pattern is a valid depends pattern with the comma excluded",
1448-
"pattern": "^.*,.*$"
1449-
}
1443+
"pattern": "^(([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))*$"
14501444
}
14511445
]
14521446
}
@@ -1913,18 +1907,13 @@ var _arduinoLibraryPropertiesDefinitionsSchemaJson = []byte(`{
19131907
},
19141908
"depends": {
19151909
"base": {
1916-
"definitions": {
1917-
"patternObject": {
1918-
"pattern": "^(([a-zA-Z][a-zA-Z0-9 _\\.\\-,]*)|([0-9][a-zA-Z0-9 _\\.\\-]*[a-zA-Z][a-zA-Z0-9 _\\.\\-,]*))*$"
1919-
}
1920-
},
19211910
"object": {
19221911
"allOf": [
19231912
{
19241913
"type": "string"
19251914
},
19261915
{
1927-
"$ref": "#/definitions/propertiesObjects/depends/base/definitions/patternObject"
1916+
"pattern": "^((((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?), *)*((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?))?$"
19281917
}
19291918
]
19301919
}

0 commit comments

Comments
 (0)