Browse code

Allow multi-line config items in meta-section of local.conf

It would behave such as the contents from each meta-section in
local.conf is copied to the destination files. One exception is the multiline
options not grouped together. In that case, the contents will be grouped
together in its destination config file.

Check tests/test_config.sh for examples.

This was originally committed in https://review.openstack.org/128805.
But the original change used AWK syntax that is not supported in AWK
3.1.8, and caused syntax error on servers with that AWK version. This
patch makes the necessary change so that it's compatible with AWK
3.1.8.

Change-Id: Id1e1fe01f05bd0f19ea6e89c4f4c0f8be695dfce
Partial-Bug: #1374118

Robert Li authored on 2014/10/16 10:40:53
Showing 3 changed files
... ...
@@ -119,6 +119,33 @@ function ini_has_option {
119 119
     [ -n "$line" ]
120 120
 }
121 121
 
122
+# Add another config line for a multi-line option.
123
+# It's normally called after iniset of the same option and assumes
124
+# that the section already exists.
125
+#
126
+# Note that iniset_multiline requires all the 'lines' to be supplied
127
+# in the argument list. Doing that will cause incorrect configuration
128
+# if spaces are used in the config values.
129
+#
130
+# iniadd_literal config-file section option value
131
+function iniadd_literal {
132
+    local xtrace=$(set +o | grep xtrace)
133
+    set +o xtrace
134
+    local file=$1
135
+    local section=$2
136
+    local option=$3
137
+    local value=$4
138
+
139
+    [[ -z $section || -z $option ]] && return
140
+
141
+    # Add it
142
+    sed -i -e "/^\[$section\]/ a\\
143
+$option = $value
144
+" "$file"
145
+
146
+    $xtrace
147
+}
148
+
122 149
 # Set an option in an INI file
123 150
 # iniset config-file section option value
124 151
 function iniset {
... ...
@@ -86,7 +86,11 @@ function merge_config_file {
86 86
     # having to do nasty quoting games
87 87
     get_meta_section $file $matchgroup $configfile | \
88 88
     $CONFIG_AWK_CMD -v configfile=$configfile '
89
-        BEGIN { section = "" }
89
+        BEGIN {
90
+            section = ""
91
+            last_section = ""
92
+            section_count = 0
93
+        }
90 94
         /^\[.+\]/ {
91 95
             gsub("[][]", "", $1);
92 96
             section=$1
... ...
@@ -106,10 +110,48 @@ function merge_config_file {
106 106
             # need to strip leading & trailing whitespace from value
107 107
             sub(/^[ \t]*/, "", value)
108 108
             sub(/[ \t]*$/, "", value)
109
-            print "iniset " configfile " " section " " attr " \x27" value "\x27"
109
+
110
+            # cfg_attr_count: number of config lines per [section, attr]
111
+            # cfg_attr: three dimensional array to keep all the config lines per [section, attr]
112
+            # cfg_section: keep the section names in the same order as they appear in local.conf
113
+            # cfg_sec_attr_name: keep the attr names in the same order as they appear in local.conf
114
+            if (! (section, attr) in cfg_attr_count) {
115
+                if (section != last_section) {
116
+                    cfg_section[section_count++] = section
117
+                    last_section = section
118
+                }
119
+                attr_count = cfg_sec_attr_count[section_count - 1]++
120
+                cfg_sec_attr_name[section_count - 1, attr_count] = attr
121
+
122
+                cfg_attr[section, attr, 0] = value
123
+                cfg_attr_count[section, attr] = 1
124
+            } else {
125
+                lno = cfg_attr_count[section, attr]++
126
+                cfg_attr[section, attr, lno] = value
127
+            }
128
+        }
129
+        END {
130
+            # Process each section in order
131
+            for (sno = 0; sno < section_count; sno++) {
132
+                section = cfg_section[sno]
133
+                # The ini routines simply append a config item immediately
134
+                # after the section header. To keep the same order as defined
135
+                # in local.conf, invoke the ini routines in the reverse order
136
+                for (attr_no = cfg_sec_attr_count[sno] - 1; attr_no >=0; attr_no--) {
137
+                    attr = cfg_sec_attr_name[sno, attr_no]
138
+                    if (cfg_attr_count[section, attr] == 1)
139
+                        print "iniset " configfile " " section " " attr " \x27" cfg_attr[section, attr, 0] "\x27"
140
+                    else {
141
+                        # For multiline, invoke the ini routines in the reverse order
142
+                        count = cfg_attr_count[section, attr]
143
+                        print "iniset " configfile " " section " " attr " \x27" cfg_attr[section, attr, count - 1] "\x27"
144
+                        for (l = count -2; l >= 0; l--)
145
+                            print "iniadd_literal " configfile " " section " " attr " \x27" cfg_attr[section, attr, l] "\x27"
146
+                    }
147
+                }
148
+            }
110 149
         }
111 150
     ' | while read a; do eval "$a"; done
112
-
113 151
 }
114 152
 
115 153
 
... ...
@@ -108,6 +108,27 @@ attr = strip_trailing_space
108 108
 [[test7|test-colon.conf]]
109 109
 [DEFAULT]
110 110
 servers=10.11.12.13:80
111
+
112
+[[test-multi-sections|test-multi-sections.conf]]
113
+[sec-1]
114
+cfg_item1 = abcd
115
+cfg_item2 = efgh
116
+
117
+[sec-2]
118
+cfg_item1 = abcd
119
+cfg_item3 = /1/2/3/4:5
120
+cfg_item4 = end
121
+
122
+[sec-3]
123
+cfg_item5 = 5555
124
+cfg_item6 = 6666
125
+cfg_item5 = 5555another
126
+
127
+[[test-multiline|test-multiline.conf]]
128
+[multi]
129
+cfg_item1 = "ab":"cd", "ef":   "gh"
130
+cfg_item1 = abcd
131
+cfg_item2 = efgh
111 132
 EOF
112 133
 
113 134
 echo -n "get_meta_section_files: test0 doesn't exist: "
... ...
@@ -189,8 +210,39 @@ VAL=$(cat test2a.conf)
189 189
 # iniset adds a blank line if it creates the file...
190 190
 EXPECT_VAL="
191 191
 [ddd]
192
-additional = true
193
-type = new"
192
+type = new
193
+additional = true"
194
+check_result "$VAL" "$EXPECT_VAL"
195
+
196
+echo -n "merge_config_file test-multi-sections: "
197
+rm -f test-multi-sections.conf
198
+merge_config_file test.conf test-multi-sections test-multi-sections.conf
199
+VAL=$(cat test-multi-sections.conf)
200
+EXPECT_VAL='
201
+[sec-1]
202
+cfg_item1 = abcd
203
+cfg_item2 = efgh
204
+
205
+[sec-2]
206
+cfg_item1 = abcd
207
+cfg_item3 = /1/2/3/4:5
208
+cfg_item4 = end
209
+
210
+[sec-3]
211
+cfg_item5 = 5555
212
+cfg_item5 = 5555another
213
+cfg_item6 = 6666'
214
+check_result "$VAL" "$EXPECT_VAL"
215
+
216
+echo -n "merge_config_file test-multiline: "
217
+rm -f test-multiline.conf
218
+merge_config_file test.conf test-multiline test-multiline.conf
219
+VAL=$(cat test-multiline.conf)
220
+EXPECT_VAL='
221
+[multi]
222
+cfg_item1 = "ab":"cd", "ef":   "gh"
223
+cfg_item1 = abcd
224
+cfg_item2 = efgh'
194 225
 check_result "$VAL" "$EXPECT_VAL"
195 226
 
196 227
 echo -n "merge_config_group test2: "
... ...
@@ -200,8 +252,8 @@ VAL=$(cat test2a.conf)
200 200
 # iniset adds a blank line if it creates the file...
201 201
 EXPECT_VAL="
202 202
 [ddd]
203
-additional = true
204
-type = new"
203
+type = new
204
+additional = true"
205 205
 check_result "$VAL" "$EXPECT_VAL"
206 206
 
207 207
 echo -n "merge_config_group test2 no conf file: "
... ...
@@ -281,4 +333,5 @@ servers = 10.11.12.13:80"
281 281
 check_result "$VAL" "$EXPECT_VAL"
282 282
 
283 283
 rm -f test.conf test1c.conf test2a.conf test-quote.conf test-space.conf test-equals.conf test-strip.conf test-colon.conf
284
+rm -f test-multiline.conf test-multi-sections.conf
284 285
 rm -rf test-etc