From 225d5224d4b0a2b416562c52f935fcdf209604f0 Mon Sep 17 00:00:00 2001 From: Nick Anderson Date: Thu, 16 Apr 2026 11:40:48 -0500 Subject: [PATCH 1/2] Added workaround for set_variable_values_ini with missing sections Modified set_variable_values_ini() to check if the section exists before attempting to use select_region. When the section doesn't exist yet, lines are inserted after the section header instead of using select_region. This prevents 'could not select an edit region' errors when the section is being created by the same bundle in an earlier promise. The fix: - Detects if section exists using regline() - For existing sections: uses select_region (original behavior) - For new sections: inserts after section header using location => after() - Adds unique handles to distinguish the two insertion paths Ticket: CFE-3866 Changelog: Title (cherry picked from commit 7a010faa3c97e7f929c8a32501924dec615bcaa9) --- lib/files.cf | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/files.cf b/lib/files.cf index d7525bee37..e2853d5ce7 100644 --- a/lib/files.cf +++ b/lib/files.cf @@ -437,25 +437,33 @@ bundle edit_line set_variable_values_ini(tab, sectionName) # Be careful if the index string contains funny chars "cindex[$(index)]" string => canonify("$(index)"); + "_escaped_section" string => escape("$(sectionName)"); classes: "edit_$(cindex[$(index)])" not => strcmp("$($(tab)[$(sectionName)][$(index)])","dontchange"), comment => "Create conditions to make changes"; + "section_$(sectionName)_exists" + expression => regline("^\[$(_escaped_section)\]", "$(edit.filename)"), + if => fileexists("$(edit.filename)"), + comment => "Check if the section header already exists in the file"; + field_edits: # If the line is there, but commented out, first uncomment it "#+\s*$(index)\s*=.*" select_region => INI_section(escape("$(sectionName)")), edit_field => col("\s*=\s*","1","$(index)","set"), - if => "edit_$(cindex[$(index)])"; + if => and("edit_$(cindex[$(index)])", + canonify("section_$(sectionName)_exists")); # match a line starting like the key something "\s*$(index)\s*=.*" edit_field => col("\s*=\s*","2","$($(tab)[$(sectionName)][$(index)])","set"), select_region => INI_section(escape("$(sectionName)")), classes => results("bundle", "set_variable_values_ini_not_$(cindex[$(index)])"), - if => "edit_$(cindex[$(index)])"; + if => and("edit_$(cindex[$(index)])", + canonify("section_$(sectionName)_exists")); insert_lines: "[$(sectionName)]" @@ -464,7 +472,16 @@ bundle edit_line set_variable_values_ini(tab, sectionName) "$(index)=$($(tab)[$(sectionName)][$(index)])" select_region => INI_section(escape("$(sectionName)")), - if => "!(set_variable_values_ini_not_$(cindex[$(index)])_kept|set_variable_values_ini_not_$(cindex[$(index)])_repaired).edit_$(cindex[$(index)])"; + if => and("!(set_variable_values_ini_not_$(cindex[$(index)])_kept|set_variable_values_ini_not_$(cindex[$(index)])_repaired)", + "edit_$(cindex[$(index)])", + canonify("section_$(sectionName)_exists")), + handle => "insert_key_in_existing_section_$(sectionName)_$(cindex[$(index)])"; + + "$(index)=$($(tab)[$(sectionName)][$(index)])" + location => after("^\[$(_escaped_section)\]"), + if => and("edit_$(cindex[$(index)])", + not(canonify("section_$(sectionName)_exists"))), + handle => "insert_key_in_new_section_$(sectionName)_$(cindex[$(index)])"; } From 01e742e993058e1c8ecc5143da5af4104a127197 Mon Sep 17 00:00:00 2001 From: Nick Anderson Date: Thu, 16 Apr 2026 11:41:06 -0500 Subject: [PATCH 2/2] Added test for set_variable_values_ini with missing sections This test demonstrates the bug where set_variable_values_ini() emits 'could not select an edit region' errors when called on a file where the promised section doesn't exist yet. The test creates an empty file and uses set_variable_values_ini() to add sections with keys. Without the fix in the previous commit, this produces multiple errors even though the sections are created by the same bundle. Ticket: CFE-3866 Changelog: None (cherry picked from commit 39d13f694156d140025e18a412b6fc02f123ba2f) --- ...set_variable_values_ini_missing_section.cf | 67 +++++++++++++++++++ ...iable_values_ini_missing_section.cf.actual | 0 ...ble_values_ini_missing_section.cf.expected | 6 ++ 3 files changed, 73 insertions(+) create mode 100644 tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf create mode 100644 tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.actual create mode 100644 tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.expected diff --git a/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf b/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf new file mode 100644 index 0000000000..6671d8af72 --- /dev/null +++ b/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf @@ -0,0 +1,67 @@ +####################################################### +# +# Test that set_variable_values_ini does not error when section doesn't exist +# +####################################################### + +body common control +{ + inputs => { "../../default.cf.sub" }; + bundlesequence => { default("$(this.promise_filename)") }; + version => "1.0"; +} + +####################################################### + +bundle agent init +{ + files: + # The tested file "actual" is copied from our seeded starting position. + "$(G.testfile).actual" + copy_from => local_cp("$(this.promise_filename).actual"); + + # Next we place the file which we will compare the final result with. + "$(G.testfile).expected" + copy_from => local_cp("$(this.promise_filename).expected"); +} + +####################################################### + +bundle agent test +{ + meta: + "description" -> { "CFE-3866" } + string => "Test that set_variable_values_ini does not error when section doesn't exist"; + + vars: + "config[section1][key1]" string => "value1"; + "config[section1][key2]" string => "value2"; + "config[section2][key3]" string => "value3"; + "config[section2][key4]" string => "value4"; + + files: + "$(G.testfile).actual" + create => "true", + edit_line => set_variable_values_ini("test.config", "section1"); + + "$(G.testfile).actual" + edit_line => set_variable_values_ini("test.config", "section2"); +} + +####################################################### + +bundle agent check +{ + methods: + "check" + usebundle => dcs_if_diff("$(G.testfile).actual", "$(G.testfile).expected", + "pass", "_fail"); + + "fail" + usebundle => dcs_fail($(this.promise_filename)), + if => "_fail"; + + pass:: + "pass" + usebundle => dcs_pass($(this.promise_filename)); +} diff --git a/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.actual b/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.actual new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.expected b/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.expected new file mode 100644 index 0000000000..4adafa063c --- /dev/null +++ b/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.expected @@ -0,0 +1,6 @@ +[section2] +key3=value3 +key4=value4 +[section1] +key2=value2 +key1=value1