Skip to content

Commit d274953

Browse files
committed
Add parent check capability to required boards.txt property helper function
Due to the complexity introduced to the data format via the custom board options system, I was not able to find any way to define some of the boards.txt rules via the JSON schema. These were implemented in pure Go code. The requirement has emerged to check whether a required property exists either as a terminal property or as a parent property (e.g., `uno.upload.tool` or `uno.upload.tool.serial`). A helper function is already present with the logic for handling the check of whether the property exists either directly based on the board ID or as a custom board option property, but it didn't have the parent property support, which is added here.
1 parent ce7a60f commit d274953

File tree

1 file changed

+24
-9
lines changed

1 file changed

+24
-9
lines changed

internal/rule/rulefunction/platform.go

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/arduino/arduino-lint/internal/rule/ruleresult"
2424
"github.com/arduino/arduino-lint/internal/rule/schema"
2525
"github.com/arduino/arduino-lint/internal/rule/schema/compliancelevel"
26+
"github.com/arduino/go-properties-orderedmap"
2627
"github.com/sirupsen/logrus"
2728
)
2829

@@ -104,7 +105,7 @@ func BoardsTxtBoardIDBuildBoardMissing() (result ruleresult.Type, output string)
104105
return ruleresult.Skip, "boards.txt has no boards"
105106
}
106107

107-
nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtBoardIds(), "build.board")
108+
nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtBoardIds(), "build.board", false)
108109

109110
if len(nonCompliantBoardIDs) > 0 {
110111
return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ")
@@ -142,7 +143,7 @@ func BoardsTxtBoardIDBuildCoreMissing() (result ruleresult.Type, output string)
142143
return ruleresult.Skip, "boards.txt has no visible boards"
143144
}
144145

145-
nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "build.core")
146+
nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "build.core", false)
146147

147148
if len(nonCompliantBoardIDs) > 0 {
148149
return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ")
@@ -285,7 +286,7 @@ func BoardsTxtBoardIDUploadToolMissing() (result ruleresult.Type, output string)
285286
return ruleresult.Skip, "boards.txt has no visible boards"
286287
}
287288

288-
nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.tool")
289+
nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.tool", false)
289290

290291
if len(nonCompliantBoardIDs) > 0 {
291292
return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ")
@@ -323,7 +324,7 @@ func BoardsTxtBoardIDUploadMaximumSizeMissing() (result ruleresult.Type, output
323324
return ruleresult.Skip, "boards.txt has no visible boards"
324325
}
325326

326-
nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.maximum_size")
327+
nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.maximum_size", false)
327328

328329
if len(nonCompliantBoardIDs) > 0 {
329330
return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ")
@@ -361,7 +362,7 @@ func BoardsTxtBoardIDUploadMaximumDataSizeMissing() (result ruleresult.Type, out
361362
return ruleresult.Skip, "boards.txt has no visible boards"
362363
}
363364

364-
nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.maximum_data_size")
365+
nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.maximum_data_size", false)
365366

366367
if len(nonCompliantBoardIDs) > 0 {
367368
return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ")
@@ -1691,7 +1692,7 @@ func PlatformTxtPluggableDiscoveryRequiredInvalid() (result ruleresult.Type, out
16911692
return ruleresult.NotRun, "Couldn't load platform.txt"
16921693
}
16931694

1694-
if !projectdata.PlatformTxt().ContainsKey("pluggable_discovery.required") && projectdata.PlatformTxt().SubTree("pluggable_discovery.required").Size() == 0 {
1695+
if !containsKeyOrParent(projectdata.PlatformTxt(), "pluggable_discovery.required") {
16951696
return ruleresult.Skip, "Property not present"
16961697
}
16971698

@@ -1970,12 +1971,20 @@ Unlike iDMissingRequiredProperty(), this function does a direct check on the pro
19701971
This is necessary because JSON schema does not have the capability to account for the custom board options system.
19711972
This function should not be used in cases where the JSON schema does cover a required property.
19721973
*/
1973-
func boardIDMissingRequiredProperty(boardIDs []string, propertyName string) []string {
1974+
func boardIDMissingRequiredProperty(boardIDs []string, propertyName string, parentOK bool) []string {
1975+
containsKey := func(key string) bool {
1976+
if parentOK {
1977+
return containsKeyOrParent(projectdata.BoardsTxt(), key)
1978+
}
1979+
1980+
return projectdata.BoardsTxt().ContainsKey(key)
1981+
}
1982+
19741983
nonCompliantBoardIDs := []string{}
19751984
for _, boardID := range boardIDs {
19761985
logrus.Tracef("Board ID: %s", boardID)
19771986
boardIDHasProperty := func(boardID string, propertyName string) bool {
1978-
if projectdata.BoardsTxt().ContainsKey(boardID + "." + propertyName) {
1987+
if containsKey(boardID + "." + propertyName) {
19791988
logrus.Trace("Property defined at top level\n")
19801989
return true // The board has a first level definition of the property. No need to check custom board options.
19811990

@@ -1992,7 +2001,7 @@ func boardIDMissingRequiredProperty(boardIDs []string, propertyName string) []st
19922001
boardOptionProperties := boardMenuProperties.SubTree(boardMenuID)
19932002
boardOptionIDs := boardOptionProperties.FirstLevelKeys()
19942003
for _, boardOptionID := range boardOptionIDs {
1995-
if !boardOptionProperties.ContainsKey(boardOptionID + "." + propertyName) {
2004+
if !containsKey(boardOptionID + "." + propertyName) {
19962005
logrus.Tracef("Option ID %s doesn't provide property\n", boardOptionID)
19972006
menuProvidesProperty = false // Every option associated with the menuID must define the property.
19982007
break
@@ -2067,6 +2076,12 @@ func toolNameMissingRequiredProperty(propertyNameQuery string, complianceLevel c
20672076
return nonCompliantTools
20682077
}
20692078

2079+
// containsKeyOrParent returns whether the given properties contain a key of the given name, or whether the given key is
2080+
// a first level of a key in the properties.
2081+
func containsKeyOrParent(propertiesMap *properties.Map, key string) bool {
2082+
return propertiesMap.ContainsKey(key) || propertiesMap.SubTree(key).Size() > 0
2083+
}
2084+
20702085
// iDMissingRequiredProperty returns the list of first level keys missing the given required property.
20712086
func iDMissingRequiredProperty(iDs []string, propertyNameQuery string, validationResult schema.ValidationResult) []string {
20722087
nonCompliantIDs := []string{}

0 commit comments

Comments
 (0)