This is an automated email from the ASF dual-hosted git repository.

sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git

commit c7c97849edc383388c3a56bdc64f58531383e6b4
Author: Szymon Janc <[email protected]>
AuthorDate: Wed Oct 21 02:06:50 2026 +0200

    newt/ycfg: Evaluate conditional values in deterministic order
    
    Conditional children of a key (e.g. pkg.cflags.SETTING) were evaluated
    in map iteration order. Resulting values were returned in random order,
    which e.g. changes order of "-include" flags from several conditions
    in compiler command line. Also if more than one overwriting condition
    was true, randomly selected one was used.
    
    Evaluate children sorted by name.
    
    Assisted-by: Claude:claude-opus-5-5
---
 newt/ycfg/ycfg.go      | 12 +++++++++-
 newt/ycfg/ycfg_test.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/newt/ycfg/ycfg.go b/newt/ycfg/ycfg.go
index b588b235..66882707 100644
--- a/newt/ycfg/ycfg.go
+++ b/newt/ycfg/ycfg.go
@@ -23,6 +23,7 @@ import (
        "fmt"
        "mynewt.apache.org/newt/newt/cfgv"
        "reflect"
+       "sort"
        "strings"
 
        "github.com/spf13/cast"
@@ -292,8 +293,17 @@ func (yc *YCfg) Get(key string,
                entries = append(entries, entry)
        }
 
+       // Evaluate children in sorted order so that result does not depend on
+       // map iteration order.
+       names := make([]string, 0, len(node.Children))
+       for name := range node.Children {
+               names = append(names, name)
+       }
+       sort.Strings(names)
+
        var errLines []string
-       for _, child := range node.Children {
+       for _, name := range names {
+               child := node.Children[name]
                expr, err := parse.LexAndParse(child.Name)
                if err != nil {
                        errLines = append(errLines,
diff --git a/newt/ycfg/ycfg_test.go b/newt/ycfg/ycfg_test.go
new file mode 100644
index 00000000..2ac782d6
--- /dev/null
+++ b/newt/ycfg/ycfg_test.go
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package ycfg
+
+import (
+       "fmt"
+       "testing"
+
+       "mynewt.apache.org/newt/newt/cfgv"
+)
+
+// Conditional children must be evaluated in the same (sorted) order on
+// every call, e.g. so that "-include" flags from several conditions are
+// always emitted in the same order.
+func TestGetChildrenOrder(t *testing.T) {
+       yc := NewYCfg("test")
+       settings := cfgv.NewSettings(nil)
+
+       expected := []string{}
+       for i := 0; i < 10; i++ {
+               name := fmt.Sprintf("SETTING_%d", i)
+               val := fmt.Sprintf("-include %d.h", i)
+
+               if err := yc.Replace("pkg.cflags."+name, val); err != nil {
+                       t.Fatalf("Replace failed: %s", err.Error())
+               }
+               settings.Set(name, "1")
+               expected = append(expected, val)
+       }
+
+       for n := 0; n < 20; n++ {
+               entries, err := yc.Get("pkg.cflags", settings)
+               if err != nil {
+                       t.Fatalf("Get failed: %s", err.Error())
+               }
+               if len(entries) != len(expected) {
+                       t.Fatalf("expected %d entries, got %d", len(expected),
+                               len(entries))
+               }
+               for i, e := range entries {
+                       if e.Value != expected[i] {
+                               t.Fatalf("entry %d: expected %q, got %q", i, 
expected[i],
+                                       e.Value)
+                       }
+               }
+       }
+}

Reply via email to