diff --git a/properties.go b/properties.go index 2f330bd..c86c84c 100644 --- a/properties.go +++ b/properties.go @@ -507,3 +507,84 @@ func DeleteUnexpandedPropsFromString(str string) string { rxp := regexp.MustCompile("\\{.+?\\}") return rxp.ReplaceAllString(str, "") } + +// ExtractSubIndexSets works like SubTree but it considers also the numeric sub index in the form +// `root.N.xxx...` as separate subsets. +// For example the following Map: +// +// properties.Map{ +// "uno.upload_port.vid": "0x1000", +// "uno.upload_port.pid": "0x2000", +// "due.upload_port.0.vid": "0x1000", +// "due.upload_port.0.pid": "0x2000", +// "due.upload_port.1.vid": "0x1001", +// "due.upload_port.1.pid": "0x2001", +// "tre.upload_port.1.vid": "0x1001", +// "tre.upload_port.1.pid": "0x2001", +// "tre.upload_port.2.vid": "0x1002", +// "tre.upload_port.2.pid": "0x2002", +// } +// +// calling ExtractSubIndexSets("uno.upload_port") returns the array: +// +// [ properties.Map{ +// "vid": "0x1000", +// "pid": "0x2000", +// }, +// ] +// +// calling ExtractSubIndexSets("due.upload_port") returns the array: +// +// [ properties.Map{ +// "vid": "0x1000", +// "pid": "0x2000", +// }, +// properties.Map{ +// "vid": "0x1001", +// "pid": "0x2001", +// }, +// ] +// +// the sub-index may start with .1 too, so calling ExtractSubIndexSets("tre.upload_port") returns: +// +// [ properties.Map{ +// "vid": "0x1001", +// "pid": "0x2001", +// }, +// properties.Map{ +// "vid": "0x1002", +// "pid": "0x2002", +// }, +// ] +// +// Numeric subindex cannot be mixed with non-numeric, in that case only the numeric sub +// index sets will be returned. +func (m *Map) ExtractSubIndexSets(root string) []*Map { + res := []*Map{} + portIDPropsSet := m.SubTree(root) + if portIDPropsSet.Size() == 0 { + return res + } + + // First check the properties with numeric sub index "root.N.xxx" + idx := 0 + haveIndexedProperties := false + for { + idProps := portIDPropsSet.SubTree(fmt.Sprintf("%d", idx)) + idx++ + if idProps.Size() > 0 { + haveIndexedProperties = true + res = append(res, idProps) + } else if idx > 1 { + // Always check sub-id 0 and 1 (https://github.com/arduino/arduino-cli/issues/456) + break + } + } + + // if there are no subindexed then return the whole "roox.xxx" subtree + if !haveIndexedProperties { + res = append(res, portIDPropsSet) + } + + return res +} diff --git a/properties_test.go b/properties_test.go index f8d6c34..8042866 100644 --- a/properties_test.go +++ b/properties_test.go @@ -295,3 +295,51 @@ func TestEqualsAndContains(t *testing.T) { json.Unmarshal([]byte(data2), &prevOpts) require.False(t, opts.Equals(prevOpts)) } + +func TestExtractSubIndexSets(t *testing.T) { + data := map[string]string{ + "uno.upload_port.vid": "0x1000", + "uno.upload_port.pid": "0x2000", + "due.upload_port.0.vid": "0x1000", + "due.upload_port.0.pid": "0x2000", + "due.upload_port.1.vid": "0x1001", + "due.upload_port.1.pid": "0x2001", + "tre.upload_port.1.vid": "0x1001", + "tre.upload_port.1.pid": "0x2001", + "tre.upload_port.2.vid": "0x1002", + "tre.upload_port.2.pid": "0x2002", + "quattro.upload_port.vid": "0x1001", + "quattro.upload_port.pid": "0x2001", + "quattro.upload_port.1.vid": "0x1002", + "quattro.upload_port.1.pid": "0x2002", + "quattro.upload_port.2.vid": "0x1003", + "quattro.upload_port.2.pid": "0x2003", + } + m := NewFromHashmap(data) + + s1 := m.ExtractSubIndexSets("uno.upload_port") + require.Len(t, s1, 1) + require.Equal(t, s1[0].Get("vid"), "0x1000") + require.Equal(t, s1[0].Get("pid"), "0x2000") + + s2 := m.ExtractSubIndexSets("due.upload_port") + require.Len(t, s2, 2) + require.Equal(t, s2[0].Get("vid"), "0x1000") + require.Equal(t, s2[0].Get("pid"), "0x2000") + require.Equal(t, s2[1].Get("vid"), "0x1001") + require.Equal(t, s2[1].Get("pid"), "0x2001") + + s3 := m.ExtractSubIndexSets("tre.upload_port") + require.Len(t, s3, 2) + require.Equal(t, s3[0].Get("vid"), "0x1001") + require.Equal(t, s3[0].Get("pid"), "0x2001") + require.Equal(t, s3[1].Get("vid"), "0x1002") + require.Equal(t, s3[1].Get("pid"), "0x2002") + + s4 := m.ExtractSubIndexSets("quattro.upload_port") + require.Len(t, s4, 2) + require.Equal(t, s4[0].Get("vid"), "0x1002") + require.Equal(t, s4[0].Get("pid"), "0x2002") + require.Equal(t, s4[1].Get("vid"), "0x1003") + require.Equal(t, s4[1].Get("pid"), "0x2003") +}