diff --git a/etc/schemas/arduino-boards-txt-definitions-schema.json b/etc/schemas/arduino-boards-txt-definitions-schema.json index b765a908..86c0567d 100644 --- a/etc/schemas/arduino-boards-txt-definitions-schema.json +++ b/etc/schemas/arduino-boards-txt-definitions-schema.json @@ -137,6 +137,9 @@ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/permissive/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/permissive/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/permissive/object" }, @@ -165,9 +168,6 @@ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/permissive/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/permissive/object" } @@ -202,6 +202,9 @@ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/specification/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/specification/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/specification/object" }, @@ -230,9 +233,6 @@ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/specification/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/specification/object" } @@ -267,6 +267,9 @@ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/strict/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/strict/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/strict/object" }, @@ -295,9 +298,6 @@ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/strict/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/strict/object" } @@ -477,15 +477,130 @@ } } }, - "boardIDMenuMenuIDOptionID": { + "boardIDMenu": { "base": { "object": { "allOf": [ { - "type": "string" + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" }, { - "minLength": 1 + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/permissive/object" + } + } + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/specification/object" + } + } + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" + }, + { + "patternProperties": { + ".+": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/strict/object" + } + } + } + ] + } + } + }, + "boardIDMenuMenuID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/permissive/object" + } + } + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/specification/object" + } + } + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + ".+": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/strict/object" + } + } + } + ] + } + } + }, + "boardIDMenuMenuIDOptionID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" } ] } @@ -495,6 +610,50 @@ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/permissive/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/permissive/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/permissive/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/permissive/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/permissive/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/permissive/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/permissive/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/permissive/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/permissive/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/permissive/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/permissive/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/permissive/object" } ] } @@ -504,6 +663,50 @@ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/specification/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/specification/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/specification/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/specification/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/specification/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/specification/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/specification/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/specification/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/specification/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/specification/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/specification/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/specification/object" } ] } @@ -513,6 +716,50 @@ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/strict/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/strict/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/strict/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/strict/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/strict/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/strict/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/strict/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/strict/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/strict/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/strict/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/strict/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/strict/object" } ] } @@ -912,7 +1159,7 @@ "userExtraFlagsProperties": { "propertyNames": { "not": { - "pattern": "^compiler\\.((c)|(c\\.elf)|(S)|(cpp)|(ar)|(objcopy.eep)|(elf2hex))\\.extra_flags$" + "pattern": "^compiler\\.((c)|(c\\.elf)|(S)|(cpp)|(ar)|(objcopy\\.eep)|(elf2hex))\\.extra_flags$" } } } @@ -935,7 +1182,7 @@ "object": { "allOf": [ { - "required": ["name", "build.core", "upload.tool"] + "required": ["name"] } ] } @@ -963,9 +1210,6 @@ "allOf": [ { "$ref": "#/definitions/requiredObjects/boardID/base/object" - }, - { - "required": ["build.board", "upload.maximum_size", "upload.maximum_data_size"] } ] } diff --git a/internal/project/platform/boardstxt/boardstxt.go b/internal/project/platform/boardstxt/boardstxt.go index 5ee62e23..990ce87c 100644 --- a/internal/project/platform/boardstxt/boardstxt.go +++ b/internal/project/platform/boardstxt/boardstxt.go @@ -20,6 +20,8 @@ See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boards package boardstxt import ( + "strings" + "github.com/arduino/arduino-lint/internal/project/general" "github.com/arduino/arduino-lint/internal/rule/schema" "github.com/arduino/arduino-lint/internal/rule/schema/compliancelevel" @@ -51,7 +53,30 @@ func Validate(boardsTxt *properties.Map) map[compliancelevel.Type]schema.Validat } //Convert the boards.txt data from the native properties.Map type to the interface type required by the schema validation package. - boardsTxtInterface := general.PropertiesToMap(boardsTxt, 2) + boardsTxtInterface := make(map[string]interface{}) + keys := boardsTxt.FirstLevelKeys() + for _, key := range keys { + if key == "menu" { + // Menu title subproperties are flat. + boardsTxtInterface[key] = general.PropertiesToMap(boardsTxt.SubTree(key), 1) + } else { + boardIDInterface := make(map[string]interface{}) + boardIDProperties := boardsTxt.SubTree(key) + boardIDKeys := boardIDProperties.Keys() + + // Add the standard properties for the board. + for _, boardIDKey := range boardIDKeys { + if !strings.HasPrefix(boardIDKey, "menu.") { + boardIDInterface[boardIDKey] = boardIDProperties.Get(boardIDKey) + } + } + + // Add the custom board option properties for the board, nested down to OPTION_ID. + boardIDInterface["menu"] = general.PropertiesToMap(boardIDProperties.SubTree("menu"), 3) + + boardsTxtInterface[key] = boardIDInterface + } + } validationResults[compliancelevel.Permissive] = schema.Validate(boardsTxtInterface, schemaObject[compliancelevel.Permissive]) validationResults[compliancelevel.Specification] = schema.Validate(boardsTxtInterface, schemaObject[compliancelevel.Specification]) diff --git a/internal/project/platform/boardstxt/boardstxtschema_test.go b/internal/project/platform/boardstxt/boardstxtschema_test.go index ba389000..860e3d50 100644 --- a/internal/project/platform/boardstxt/boardstxtschema_test.go +++ b/internal/project/platform/boardstxt/boardstxtschema_test.go @@ -39,6 +39,7 @@ var validBoardsTxtRaw = []byte(` nano.build.board=AVR_NANO nano.build.core=arduino nano.menu.cpu.atmega328=ATmega328P + nano.menu.cpu.atmega328.upload.maximum_size=30720 `) func TestSchemaValid(t *testing.T) { @@ -71,17 +72,25 @@ func TestMinLength(t *testing.T) { {"foo.build.board", "foo/build\\.board", 1, compliancelevel.Specification}, {"foo.build.board", "foo/build\\.board", 1, compliancelevel.Strict}, + {"foo.menu.bar.baz.build.board", "foo/menu/bar/baz/build\\.board", 1, compliancelevel.Permissive}, + {"foo.menu.bar.baz.build.board", "foo/menu/bar/baz/build\\.board", 1, compliancelevel.Specification}, + {"foo.menu.bar.baz.build.board", "foo/menu/bar/baz/build\\.board", 1, compliancelevel.Strict}, + {"foo.build.core", "foo/build\\.core", 1, compliancelevel.Permissive}, {"foo.build.core", "foo/build\\.core", 1, compliancelevel.Specification}, {"foo.build.core", "foo/build\\.core", 1, compliancelevel.Strict}, - {"foo.menu.bar.baz", "foo/menu\\.bar\\.baz", 1, compliancelevel.Permissive}, - {"foo.menu.bar.baz", "foo/menu\\.bar\\.baz", 1, compliancelevel.Specification}, - {"foo.menu.bar.baz", "foo/menu\\.bar\\.baz", 1, compliancelevel.Strict}, + {"foo.menu.bar.baz.build.core", "foo/menu/bar/baz/build\\.core", 1, compliancelevel.Permissive}, + {"foo.menu.bar.baz.build.core", "foo/menu/bar/baz/build\\.core", 1, compliancelevel.Specification}, + {"foo.menu.bar.baz.build.core", "foo/menu/bar/baz/build\\.core", 1, compliancelevel.Strict}, {"foo.upload.tool", "foo/upload\\.tool", 1, compliancelevel.Permissive}, {"foo.upload.tool", "foo/upload\\.tool", 1, compliancelevel.Specification}, {"foo.upload.tool", "foo/upload\\.tool", 1, compliancelevel.Strict}, + + {"foo.menu.bar.baz.upload.tool", "foo/menu/bar/baz/upload\\.tool", 1, compliancelevel.Permissive}, + {"foo.menu.bar.baz.upload.tool", "foo/menu/bar/baz/upload\\.tool", 1, compliancelevel.Specification}, + {"foo.menu.bar.baz.upload.tool", "foo/menu/bar/baz/upload\\.tool", 1, compliancelevel.Strict}, } // Test schema validation results with value length < minimum. @@ -132,29 +141,9 @@ func TestRequired(t *testing.T) { {"nano.name", "nano/name", compliancelevel.Specification, assert.True}, {"nano.name", "nano/name", compliancelevel.Strict, assert.True}, - {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Permissive, assert.True}, - {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Specification, assert.True}, - {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Strict, assert.True}, - - {"nano.upload.maximum_size", "nano/upload\\.maximum_size", compliancelevel.Permissive, assert.False}, - {"nano.upload.maximum_size", "nano/upload\\.maximum_size", compliancelevel.Specification, assert.False}, - {"nano.upload.maximum_size", "nano/upload\\.maximum_size", compliancelevel.Strict, assert.True}, - - {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", compliancelevel.Permissive, assert.False}, - {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", compliancelevel.Specification, assert.False}, - {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", compliancelevel.Strict, assert.True}, - - {"nano.upload.protocol", "nano/upload\\.protocol", compliancelevel.Permissive, assert.False}, - {"nano.upload.protocol", "nano/upload\\.protocol", compliancelevel.Specification, assert.False}, - {"nano.upload.protocol", "nano/upload\\.protocol", compliancelevel.Strict, assert.False}, - - {"nano.build.board", "nano/build\\.board", compliancelevel.Permissive, assert.False}, - {"nano.build.board", "nano/build\\.board", compliancelevel.Specification, assert.False}, - {"nano.build.board", "nano/build\\.board", compliancelevel.Strict, assert.True}, - - {"nano.build.core", "nano/build\\.core", compliancelevel.Permissive, assert.True}, - {"nano.build.core", "nano/build\\.core", compliancelevel.Specification, assert.True}, - {"nano.build.core", "nano/build\\.core", compliancelevel.Strict, assert.True}, + {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Permissive, assert.False}, + {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Specification, assert.False}, + {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Strict, assert.False}, } for _, testTable := range testTables { @@ -197,6 +186,16 @@ func TestEnum(t *testing.T) { {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "foo", compliancelevel.Specification, assert.True}, {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "true", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "true", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "true", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "false", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "false", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "false", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "foo", compliancelevel.Strict, assert.True}, + {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "true", compliancelevel.Permissive, assert.False}, {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "true", compliancelevel.Specification, assert.False}, {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "true", compliancelevel.Strict, assert.False}, @@ -207,6 +206,16 @@ func TestEnum(t *testing.T) { {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "foo", compliancelevel.Specification, assert.True}, {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "true", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "true", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "true", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "false", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "false", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "false", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "foo", compliancelevel.Strict, assert.True}, + {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "true", compliancelevel.Permissive, assert.False}, {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "true", compliancelevel.Specification, assert.False}, {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "true", compliancelevel.Strict, assert.False}, @@ -217,6 +226,16 @@ func TestEnum(t *testing.T) { {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "foo", compliancelevel.Specification, assert.True}, {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "true", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "true", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "true", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "false", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "false", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "false", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "foo", compliancelevel.Strict, assert.True}, + {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "true", compliancelevel.Permissive, assert.False}, {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "true", compliancelevel.Specification, assert.False}, {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "true", compliancelevel.Strict, assert.False}, @@ -226,6 +245,16 @@ func TestEnum(t *testing.T) { {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "foo", compliancelevel.Permissive, assert.True}, {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "foo", compliancelevel.Specification, assert.True}, {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "foo", compliancelevel.Strict, assert.True}, + + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "true", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "true", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "true", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "false", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "false", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "false", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "foo", compliancelevel.Strict, assert.True}, } for _, testTable := range testTables { @@ -256,6 +285,13 @@ func TestPattern(t *testing.T) { {"nano.upload.maximum_size", "nano/upload\\.maximum_size", "foo", compliancelevel.Specification, assert.True}, {"nano.upload.maximum_size", "nano/upload\\.maximum_size", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "123", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "123", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "123", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "foo", compliancelevel.Strict, assert.True}, + {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", "123", compliancelevel.Permissive, assert.False}, {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", "123", compliancelevel.Specification, assert.False}, {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", "123", compliancelevel.Strict, assert.False}, @@ -263,6 +299,13 @@ func TestPattern(t *testing.T) { {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", "foo", compliancelevel.Specification, assert.True}, {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "123", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "123", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "123", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "foo", compliancelevel.Strict, assert.True}, + {"nano.vid.0", "nano/vid\\.0", "0xABCD", compliancelevel.Permissive, assert.False}, {"nano.vid.0", "nano/vid\\.0", "0xABCD", compliancelevel.Specification, assert.False}, {"nano.vid.0", "nano/vid\\.0", "0xABCD", compliancelevel.Strict, assert.False}, @@ -270,12 +313,26 @@ func TestPattern(t *testing.T) { {"nano.vid.0", "nano/vid\\.0", "foo", compliancelevel.Specification, assert.True}, {"nano.vid.0", "nano/vid\\.0", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "0xABCD", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "0xABCD", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "0xABCD", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "foo", compliancelevel.Strict, assert.True}, + {"nano.pid.0", "nano/pid\\.0", "0xABCD", compliancelevel.Permissive, assert.False}, {"nano.pid.0", "nano/pid\\.0", "0xABCD", compliancelevel.Specification, assert.False}, {"nano.pid.0", "nano/pid\\.0", "0xABCD", compliancelevel.Strict, assert.False}, {"nano.pid.0", "nano/pid\\.0", "foo", compliancelevel.Permissive, assert.True}, {"nano.pid.0", "nano/pid\\.0", "foo", compliancelevel.Specification, assert.True}, {"nano.pid.0", "nano/pid\\.0", "foo", compliancelevel.Strict, assert.True}, + + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "0xABCD", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "0xABCD", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "0xABCD", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "foo", compliancelevel.Strict, assert.True}, } for _, testTable := range testTables { @@ -325,6 +382,10 @@ func TestPropertyNames(t *testing.T) { {"nano.compiler.elf2hex.extra_flags", "nano/compiler\\.elf2hex\\.extra_flags", compliancelevel.Permissive, assert.False}, {"nano.compiler.elf2hex.extra_flags", "nano/compiler\\.elf2hex\\.extra_flags", compliancelevel.Specification, assert.False}, {"nano.compiler.elf2hex.extra_flags", "nano/compiler\\.elf2hex\\.extra_flags", compliancelevel.Strict, assert.True}, + + {"nano.menu.foo.bar.compiler.c.extra_flags", "nano/menu/foo/bar/compiler\\.c\\.extra_flags", compliancelevel.Permissive, assert.False}, + {"nano.menu.foo.bar.compiler.c.extra_flags", "nano/menu/foo/bar/compiler\\.c\\.extra_flags", compliancelevel.Specification, assert.False}, + {"nano.menu.foo.bar.compiler.c.extra_flags", "nano/menu/foo/bar/compiler\\.c\\.extra_flags", compliancelevel.Strict, assert.True}, } for _, testTable := range testTables { diff --git a/internal/rule/ruleconfiguration/ruleconfiguration.go b/internal/rule/ruleconfiguration/ruleconfiguration.go index eb8afb33..604dcc3c 100644 --- a/internal/rule/ruleconfiguration/ruleconfiguration.go +++ b/internal/rule/ruleconfiguration/ruleconfiguration.go @@ -1609,22 +1609,6 @@ var configurations = []Type{ ErrorModes: []rulemode.Type{rulemode.Default}, RuleFunction: rulefunction.BoardsTxtMenuMenuIDLTMinLength, }, - { - ProjectType: projecttype.Platform, - SuperprojectType: projecttype.All, - Category: "configuration files", - Subcategory: "boards.txt", - ID: "PF013", - Brief: "board option < min length", - Description: "", - MessageTemplate: "Custom board option value for board ID(s) {{.}} is less than the minimum length. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#custom-board-options", - DisableModes: nil, - EnableModes: []rulemode.Type{rulemode.Default}, - InfoModes: nil, - WarningModes: nil, - ErrorModes: []rulemode.Type{rulemode.Default}, - RuleFunction: rulefunction.BoardsTxtBoardIDMenuMenuIDOptionIDLTMinLength, - }, { ProjectType: projecttype.Platform, SuperprojectType: projecttype.All, diff --git a/internal/rule/rulefunction/platform.go b/internal/rule/rulefunction/platform.go index 8cc61a52..c3d4d2bb 100644 --- a/internal/rule/rulefunction/platform.go +++ b/internal/rule/rulefunction/platform.go @@ -22,6 +22,7 @@ import ( "github.com/arduino/arduino-lint/internal/rule/ruleresult" "github.com/arduino/arduino-lint/internal/rule/schema" "github.com/arduino/arduino-lint/internal/rule/schema/compliancelevel" + "github.com/sirupsen/logrus" ) // The rule functions for platforms. @@ -83,7 +84,7 @@ func BoardsTxtBoardIDNameLTMinLength() (result ruleresult.Type, output string) { return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "name", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "name", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -102,7 +103,7 @@ func BoardsTxtBoardIDBuildBoardMissing() (result ruleresult.Type, output string) return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDMissingRequiredProperty(projectdata.BoardsTxtBoardIds(), "build\\.board", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Strict]) + nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtBoardIds(), "build.board") if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -121,7 +122,7 @@ func BoardsTxtBoardIDBuildBoardLTMinLength() (result ruleresult.Type, output str return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "build\\.board", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "build\\.board", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -140,7 +141,7 @@ func BoardsTxtBoardIDBuildCoreMissing() (result ruleresult.Type, output string) return ruleresult.Skip, "boards.txt has no visible boards" } - nonCompliantBoardIDs := iDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "build\\.core", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "build.core") if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -159,7 +160,7 @@ func BoardsTxtBoardIDBuildCoreLTMinLength() (result ruleresult.Type, output stri return ruleresult.Skip, "boards.txt has no visible boards" } - nonCompliantBoardIDs := iDValueLTMinLength(projectdata.BoardsTxtVisibleBoardIds(), "build\\.core", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueLTMinLength(projectdata.BoardsTxtVisibleBoardIds(), "build\\.core", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -202,7 +203,7 @@ func BoardsTxtBoardIDHideInvalid() (result ruleresult.Type, output string) { return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "hide", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "hide", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -235,25 +236,6 @@ func BoardsTxtMenuMenuIDLTMinLength() (result ruleresult.Type, output string) { return ruleresult.Pass, "" } -// BoardsTxtBoardIDMenuMenuIDOptionIDLTMinLength checks if any of the board menu.MENU_ID.OPTION_ID values are less than the minimum length. -func BoardsTxtBoardIDMenuMenuIDOptionIDLTMinLength() (result ruleresult.Type, output string) { - if projectdata.BoardsTxtLoadError() != nil { - return ruleresult.NotRun, "Couldn't load boards.txt" - } - - if len(projectdata.BoardsTxtBoardIds()) == 0 { - return ruleresult.Skip, "boards.txt has no boards" - } - - nonCompliantBoardIDs := iDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "menu\\.[^.]+\\.[^.]+", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Strict]) - - if len(nonCompliantBoardIDs) > 0 { - return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") - } - - return ruleresult.Pass, "" -} - // BoardsTxtBoardIDSerialDisableDTRInvalid checks if any of the board serial.disableDTR values are invalid. func BoardsTxtBoardIDSerialDisableDTRInvalid() (result ruleresult.Type, output string) { if projectdata.BoardsTxtLoadError() != nil { @@ -264,7 +246,7 @@ func BoardsTxtBoardIDSerialDisableDTRInvalid() (result ruleresult.Type, output s return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "serial\\.disableDTR", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "serial\\.disableDTR", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -283,7 +265,7 @@ func BoardsTxtBoardIDSerialDisableRTSInvalid() (result ruleresult.Type, output s return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "serial\\.disableRTS", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "serial\\.disableRTS", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -302,7 +284,7 @@ func BoardsTxtBoardIDUploadToolMissing() (result ruleresult.Type, output string) return ruleresult.Skip, "boards.txt has no visible boards" } - nonCompliantBoardIDs := iDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload\\.tool", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.tool") if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -321,7 +303,7 @@ func BoardsTxtBoardIDUploadToolLTMinLength() (result ruleresult.Type, output str return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "upload\\.tool", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "upload\\.tool", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -340,7 +322,7 @@ func BoardsTxtBoardIDUploadMaximumSizeMissing() (result ruleresult.Type, output return ruleresult.Skip, "boards.txt has no visible boards" } - nonCompliantBoardIDs := iDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload\\.maximum_size", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Strict]) + nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.maximum_size") if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -359,7 +341,7 @@ func BoardsTxtBoardIDUploadMaximumSizeInvalid() (result ruleresult.Type, output return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.maximum_size", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.maximum_size", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -378,7 +360,7 @@ func BoardsTxtBoardIDUploadMaximumDataSizeMissing() (result ruleresult.Type, out return ruleresult.Skip, "boards.txt has no visible boards" } - nonCompliantBoardIDs := iDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload\\.maximum_data_size", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Strict]) + nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.maximum_data_size") if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -397,7 +379,7 @@ func BoardsTxtBoardIDUploadMaximumDataSizeInvalid() (result ruleresult.Type, out return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.maximum_data_size", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.maximum_data_size", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -416,7 +398,7 @@ func BoardsTxtBoardIDUploadUse1200bpsTouchInvalid() (result ruleresult.Type, out return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.use_1200bps_touch", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.use_1200bps_touch", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -435,7 +417,7 @@ func BoardsTxtBoardIDUploadWaitForUploadPortInvalid() (result ruleresult.Type, o return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.wait_for_upload_port", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.wait_for_upload_port", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -454,7 +436,7 @@ func BoardsTxtBoardIDVidNInvalid() (result ruleresult.Type, output string) { return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "vid\\.[0-9]+", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "vid\\.[0-9]+", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -473,7 +455,7 @@ func BoardsTxtBoardIDPidNInvalid() (result ruleresult.Type, output string) { return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "pid\\.[0-9]+", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "pid\\.[0-9]+", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -1760,6 +1742,77 @@ func PlatformTxtBootloaderPatternMissing() (result ruleresult.Type, output strin return ruleresult.Pass, "" } +/* +boardIDMissingRequiredProperty returns the list of board IDs missing the given property. +Unlike iDMissingRequiredProperty(), this function does a direct check on the properties, rather than using the JSON schema validation. +This is necessary because JSON schema does not have the capability to account for the custom board options system. +This function should not be used in cases where the JSON schema does cover a required property. +*/ +func boardIDMissingRequiredProperty(boardIDs []string, propertyName string) []string { + nonCompliantBoardIDs := []string{} + for _, boardID := range boardIDs { + logrus.Tracef("Board ID: %s", boardID) + boardIDHasProperty := func(boardID string, propertyName string) bool { + if projectdata.BoardsTxt().ContainsKey(boardID + "." + propertyName) { + logrus.Trace("Property defined at top level\n") + return true // The board has a first level definition of the property. No need to check custom board options. + + } + + // There is no first level definition of the property, so check if it is provided by the custom board options. + menuProvidesProperty := false + boardMenuProperties := projectdata.BoardsTxt().SubTree(boardID + ".menu") + boardMenuIDs := boardMenuProperties.FirstLevelKeys() + for _, boardMenuID := range boardMenuIDs { + logrus.Tracef("Menu ID: %s\n", boardMenuID) + menuProvidesProperty = true + + boardOptionProperties := boardMenuProperties.SubTree(boardMenuID) + boardOptionIDs := boardOptionProperties.FirstLevelKeys() + for _, boardOptionID := range boardOptionIDs { + if !boardOptionProperties.ContainsKey(boardOptionID + "." + propertyName) { + logrus.Tracef("Option ID %s doesn't provide property\n", boardOptionID) + menuProvidesProperty = false // Every option associated with the menuID must define the property. + break + } + } + + if menuProvidesProperty { + // The menu provided the property so no need to continue. + logrus.Trace("Menu provides property\n") + return true + } + } + + return false // None of the menus provided the property. + } + + if !boardIDHasProperty(boardID, propertyName) { + nonCompliantBoardIDs = append(nonCompliantBoardIDs, boardID) + } + } + + return nonCompliantBoardIDs +} + +// boardIDValueLTMinLength returns the list of board IDs with value of the given property less than the minimum length. +func boardIDValueLTMinLength(boardIDs []string, propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + nonCompliantBoardIDs := iDValueLTMinLength(boardIDs, propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel]) + return append(nonCompliantBoardIDs, iDValueLTMinLength(boardIDs, "menu/[^.]+/[^.]+/"+propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel])...) +} + +// boardIDValueEnumMismatch returns the list of board IDs with value of the given property less than the minimum length. +func boardIDValueEnumMismatch(boardIDs []string, propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + nonCompliantBoardIDs := iDValueEnumMismatch(boardIDs, propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel]) + return append(nonCompliantBoardIDs, iDValueEnumMismatch(boardIDs, "menu/[^.]+/[^.]+/"+propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel])...) +} + +// boardIDValuePatternMismatch returns the list of board IDs with value of the given property less than the minimum length. +func boardIDValuePatternMismatch(boardIDs []string, propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + nonCompliantBoardIDs := iDValuePatternMismatch(boardIDs, propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel]) + return append(nonCompliantBoardIDs, iDValuePatternMismatch(boardIDs, "menu/[^.]+/[^.]+/"+propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel])...) +} + // programmerIDMissingRequiredProperty returns the list of programmer IDs missing the given required property. func programmerIDMissingRequiredProperty(propertyNameQuery string, complianceLevel compliancelevel.Type) []string { return iDMissingRequiredProperty(projectdata.ProgrammersTxtProgrammerIds(), propertyNameQuery, projectdata.ProgrammersTxtSchemaValidationResult()[complianceLevel]) diff --git a/internal/rule/rulefunction/platform_test.go b/internal/rule/rulefunction/platform_test.go index aa83ec0f..0679f715 100644 --- a/internal/rule/rulefunction/platform_test.go +++ b/internal/rule/rulefunction/platform_test.go @@ -87,7 +87,7 @@ func TestBoardsTxtBoardIDNameMissing(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property missing", "boardID-name-missing-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property missing", "boardID-name-missing-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -123,7 +123,7 @@ func TestBoardsTxtBoardIDBuildBoardLTMinLength(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property LT min", "boardID-build-board-LT-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property LT min", "boardID-build-board-LT-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -147,7 +147,7 @@ func TestBoardsTxtBoardIDBuildCoreLTMinLength(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property LT min", "boardID-build-core-LT-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property LT min", "boardID-build-core-LT-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -159,7 +159,7 @@ func TestBoardsTxtUserExtraFlagsUsage(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Use of user extra flags", "boardID-compiler-x-extra_flags-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Use of user extra flags", "boardID-compiler-x-extra_flags-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -190,24 +190,12 @@ func TestBoardsTxtMenuMenuIDLTMinLength(t *testing.T) { checkPlatformRuleFunction(BoardsTxtMenuMenuIDLTMinLength, testTables, t) } -func TestBoardsTxtBoardIDMenuMenuIDOptionIDLTMinLength(t *testing.T) { - testTables := []platformRuleFunctionTestTable{ - {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, - {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, - {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property LT min", "boardID-menu-menuID-LT-boards.txt", ruleresult.Fail, "buno, funo"}, - {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, - } - - checkPlatformRuleFunction(BoardsTxtBoardIDMenuMenuIDOptionIDLTMinLength, testTables, t) -} - func TestBoardsTxtBoardIDSerialDisableDTRInvalid(t *testing.T) { testTables := []platformRuleFunctionTestTable{ {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-serial-disableDTR-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-serial-disableDTR-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -219,7 +207,7 @@ func TestBoardsTxtBoardIDSerialDisableRTSInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-serial-disableRTS-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-serial-disableRTS-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -243,7 +231,7 @@ func TestBoardsTxtBoardIDUploadToolLTMinLength(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property LT min", "boardID-upload-tool-LT-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property LT min", "boardID-upload-tool-LT-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -267,7 +255,7 @@ func TestBoardsTxtBoardIDUploadMaximumSizeInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-upload-maximum_size-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-upload-maximum_size-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -291,7 +279,7 @@ func TestBoardsTxtBoardIDUploadMaximumDataSizeInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-upload-maximum_data_size-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-upload-maximum_data_size-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -303,7 +291,7 @@ func TestBoardsTxtBoardIDUploadUse1200bpsTouchInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-upload-use_1200bps_touch-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-upload-use_1200bps_touch-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -315,7 +303,7 @@ func TestBoardsTxtBoardIDUploadWaitForUploadPortInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-upload-wait_for_upload_port-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-upload-wait_for_upload_port-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -327,7 +315,7 @@ func TestBoardsTxtBoardIDVidNInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-vid-n-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-vid-n-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -339,7 +327,7 @@ func TestBoardsTxtBoardIDPidNInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-pid-n-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-pid-n-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-build-board-LT-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-build-board-LT-boards.txt/boards.txt index f0cd6bd1..78036f25 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-build-board-LT-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-board-LT-boards.txt/boards.txt @@ -21,3 +21,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.build.board= diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-build-board-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-build-board-missing-boards.txt/boards.txt index 9da39ca0..56352639 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-build-board-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-board-missing-boards.txt/boards.txt @@ -19,3 +19,13 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.build.board=ZUNO +zuno.menu.foo.baz.asdf=ZUNO +#zuno.menu.foo.bar.build.board=ZUNO diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-build-core-LT-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-build-core-LT-boards.txt/boards.txt index 02ec763f..511d4e43 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-build-core-LT-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-core-LT-boards.txt/boards.txt @@ -21,3 +21,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.build.core= diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-build-core-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-build-core-missing-boards.txt/boards.txt index 96a3e3e7..5a0a051f 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-build-core-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-core-missing-boards.txt/boards.txt @@ -19,3 +19,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.build.core=arduino diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-compiler-x-extra_flags-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-compiler-x-extra_flags-boards.txt/boards.txt index e3399fa0..6b1d7f07 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-compiler-x-extra_flags-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-compiler-x-extra_flags-boards.txt/boards.txt @@ -23,3 +23,12 @@ funo.compiler.objcopy.eep.extra_flags=foo funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.compiler.cpp.extra_flags=bar diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-hide-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-hide-invalid-boards.txt/boards.txt index 9a28652c..14678f13 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-hide-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-hide-invalid-boards.txt/boards.txt @@ -24,3 +24,12 @@ funo.hide=false funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.hide=foo diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-name-LT-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-name-LT-boards.txt/boards.txt index 6e26f427..1ecdb79e 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-name-LT-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-name-LT-boards.txt/boards.txt @@ -21,3 +21,12 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.name= diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-name-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-name-missing-boards.txt/boards.txt index 5287f67e..26e45663 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-name-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-name-missing-boards.txt/boards.txt @@ -19,3 +19,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.name=zuno diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-pid-n-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-pid-n-invalid-boards.txt/boards.txt index 5896bfb5..b27b144f 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-pid-n-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-pid-n-invalid-boards.txt/boards.txt @@ -27,3 +27,13 @@ funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 funo.vid.0=0xABCD funo.pid.0=foo + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.vid.0=0xABCD +zuno.menu.foo.bar.pid.0=foo diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableDTR-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableDTR-invalid-boards.txt/boards.txt index ec066e92..3c2bdb15 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableDTR-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableDTR-invalid-boards.txt/boards.txt @@ -24,3 +24,12 @@ funo.serial.disableDTR=foo funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.serial.disableDTR=baz diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableRTS-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableRTS-invalid-boards.txt/boards.txt index b6aca5d0..8b240560 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableRTS-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableRTS-invalid-boards.txt/boards.txt @@ -24,3 +24,12 @@ funo.serial.disableRTS=foo funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.serial.disableRTS=baz diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-invalid-boards.txt/boards.txt index 8670c7cf..4cc0c147 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-invalid-boards.txt/boards.txt @@ -21,3 +21,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=fpp + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.menu.foo.bar.upload.maximum_data_size=baz diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-missing-boards.txt/boards.txt index 737e0e81..31496046 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-missing-boards.txt/boards.txt @@ -19,3 +19,11 @@ funo.build.core=arduino funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.menu.foo.bar.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-invalid-boards.txt/boards.txt index 3dd41ae0..40ac46f9 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-invalid-boards.txt/boards.txt @@ -21,3 +21,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=foo funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.maximum_size=baz diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-missing-boards.txt/boards.txt index 43cb6eb9..1bd680a7 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-missing-boards.txt/boards.txt @@ -19,3 +19,11 @@ funo.build.core=arduino funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.maximum_size=32256 diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-LT-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-LT-boards.txt/boards.txt index 43228283..098c8075 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-LT-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-LT-boards.txt/boards.txt @@ -21,3 +21,11 @@ funo.build.variant=standard funo.upload.tool= funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.tool= diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-missing-boards.txt/boards.txt index 8ac786b2..7116593b 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-missing-boards.txt/boards.txt @@ -19,3 +19,11 @@ funo.build.core=arduino funo.build.variant=standard funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.tool=avrdude diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-use_1200bps_touch-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-use_1200bps_touch-invalid-boards.txt/boards.txt index ab8afe81..27b68f20 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-use_1200bps_touch-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-use_1200bps_touch-invalid-boards.txt/boards.txt @@ -24,3 +24,12 @@ funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 funo.upload.use_1200bps_touch=foo + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.use_1200bps_touch=foo diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-wait_for_upload_port-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-wait_for_upload_port-invalid-boards.txt/boards.txt index fc75822b..1100a9c8 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-wait_for_upload_port-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-wait_for_upload_port-invalid-boards.txt/boards.txt @@ -24,3 +24,12 @@ funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 funo.upload.wait_for_upload_port=foo + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.wait_for_upload_port=foo diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-vid-n-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-vid-n-invalid-boards.txt/boards.txt index 0bf43958..5fb03f66 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-vid-n-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-vid-n-invalid-boards.txt/boards.txt @@ -27,3 +27,13 @@ funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 funo.vid.0=foo funo.pid.0=0xABCD + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.vid.0=foo +zuno.menu.foo.bar.pid.0=0xABCD diff --git a/internal/rule/schema/schemadata/bindata.go b/internal/rule/schema/schemadata/bindata.go index 2d5f1ada..9ae12045 100644 --- a/internal/rule/schema/schemadata/bindata.go +++ b/internal/rule/schema/schemadata/bindata.go @@ -209,6 +209,9 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/permissive/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/permissive/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/permissive/object" }, @@ -237,9 +240,6 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/permissive/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/permissive/object" } @@ -274,6 +274,9 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/specification/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/specification/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/specification/object" }, @@ -302,9 +305,6 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/specification/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/specification/object" } @@ -339,6 +339,9 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/strict/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/strict/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/strict/object" }, @@ -367,9 +370,6 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/strict/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/strict/object" } @@ -549,15 +549,130 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ } } }, - "boardIDMenuMenuIDOptionID": { + "boardIDMenu": { "base": { "object": { "allOf": [ { - "type": "string" + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" }, { - "minLength": 1 + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/permissive/object" + } + } + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/specification/object" + } + } + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" + }, + { + "patternProperties": { + ".+": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/strict/object" + } + } + } + ] + } + } + }, + "boardIDMenuMenuID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/permissive/object" + } + } + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/specification/object" + } + } + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + ".+": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/strict/object" + } + } + } + ] + } + } + }, + "boardIDMenuMenuIDOptionID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" } ] } @@ -567,6 +682,50 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/permissive/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/permissive/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/permissive/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/permissive/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/permissive/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/permissive/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/permissive/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/permissive/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/permissive/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/permissive/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/permissive/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/permissive/object" } ] } @@ -576,6 +735,50 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/specification/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/specification/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/specification/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/specification/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/specification/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/specification/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/specification/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/specification/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/specification/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/specification/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/specification/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/specification/object" } ] } @@ -585,6 +788,50 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/strict/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/strict/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/strict/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/strict/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/strict/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/strict/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/strict/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/strict/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/strict/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/strict/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/strict/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/strict/object" } ] } @@ -984,7 +1231,7 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "userExtraFlagsProperties": { "propertyNames": { "not": { - "pattern": "^compiler\\.((c)|(c\\.elf)|(S)|(cpp)|(ar)|(objcopy.eep)|(elf2hex))\\.extra_flags$" + "pattern": "^compiler\\.((c)|(c\\.elf)|(S)|(cpp)|(ar)|(objcopy\\.eep)|(elf2hex))\\.extra_flags$" } } } @@ -1007,7 +1254,7 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "object": { "allOf": [ { - "required": ["name", "build.core", "upload.tool"] + "required": ["name"] } ] } @@ -1035,9 +1282,6 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "allOf": [ { "$ref": "#/definitions/requiredObjects/boardID/base/object" - }, - { - "required": ["build.board", "upload.maximum_size", "upload.maximum_data_size"] } ] }