From 751ad1aadf8447c2b6945b6ae4ab73bf71a244ca Mon Sep 17 00:00:00 2001 From: Robert Li Date: Wed, 15 Oct 2014 21:40:53 -0400 Subject: [PATCH] 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 --- functions-common | 27 ++++++++++++++++++++ lib/config | 48 +++++++++++++++++++++++++++++++--- tests/test_config.sh | 61 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 129 insertions(+), 7 deletions(-) diff --git a/functions-common b/functions-common index 9f4acfec1e..333f31da02 100644 --- a/functions-common +++ b/functions-common @@ -119,6 +119,33 @@ function ini_has_option { [ -n "$line" ] } +# Add another config line for a multi-line option. +# It's normally called after iniset of the same option and assumes +# that the section already exists. +# +# Note that iniset_multiline requires all the 'lines' to be supplied +# in the argument list. Doing that will cause incorrect configuration +# if spaces are used in the config values. +# +# iniadd_literal config-file section option value +function iniadd_literal { + local xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + local section=$2 + local option=$3 + local value=$4 + + [[ -z $section || -z $option ]] && return + + # Add it + sed -i -e "/^\[$section\]/ a\\ +$option = $value +" "$file" + + $xtrace +} + # Set an option in an INI file # iniset config-file section option value function iniset { diff --git a/lib/config b/lib/config index b44e79aa3d..a4d59a31c9 100644 --- a/lib/config +++ b/lib/config @@ -86,7 +86,11 @@ function merge_config_file { # having to do nasty quoting games get_meta_section $file $matchgroup $configfile | \ $CONFIG_AWK_CMD -v configfile=$configfile ' - BEGIN { section = "" } + BEGIN { + section = "" + last_section = "" + section_count = 0 + } /^\[.+\]/ { gsub("[][]", "", $1); section=$1 @@ -106,10 +110,48 @@ function merge_config_file { # need to strip leading & trailing whitespace from value sub(/^[ \t]*/, "", value) sub(/[ \t]*$/, "", value) - print "iniset " configfile " " section " " attr " \x27" value "\x27" + + # cfg_attr_count: number of config lines per [section, attr] + # cfg_attr: three dimensional array to keep all the config lines per [section, attr] + # cfg_section: keep the section names in the same order as they appear in local.conf + # cfg_sec_attr_name: keep the attr names in the same order as they appear in local.conf + if (! (section, attr) in cfg_attr_count) { + if (section != last_section) { + cfg_section[section_count++] = section + last_section = section + } + attr_count = cfg_sec_attr_count[section_count - 1]++ + cfg_sec_attr_name[section_count - 1, attr_count] = attr + + cfg_attr[section, attr, 0] = value + cfg_attr_count[section, attr] = 1 + } else { + lno = cfg_attr_count[section, attr]++ + cfg_attr[section, attr, lno] = value + } + } + END { + # Process each section in order + for (sno = 0; sno < section_count; sno++) { + section = cfg_section[sno] + # The ini routines simply append a config item immediately + # after the section header. To keep the same order as defined + # in local.conf, invoke the ini routines in the reverse order + for (attr_no = cfg_sec_attr_count[sno] - 1; attr_no >=0; attr_no--) { + attr = cfg_sec_attr_name[sno, attr_no] + if (cfg_attr_count[section, attr] == 1) + print "iniset " configfile " " section " " attr " \x27" cfg_attr[section, attr, 0] "\x27" + else { + # For multiline, invoke the ini routines in the reverse order + count = cfg_attr_count[section, attr] + print "iniset " configfile " " section " " attr " \x27" cfg_attr[section, attr, count - 1] "\x27" + for (l = count -2; l >= 0; l--) + print "iniadd_literal " configfile " " section " " attr " \x27" cfg_attr[section, attr, l] "\x27" + } + } + } } ' | while read a; do eval "$a"; done - } diff --git a/tests/test_config.sh b/tests/test_config.sh index 50e8d7b2e6..cd74cee6f0 100755 --- a/tests/test_config.sh +++ b/tests/test_config.sh @@ -108,6 +108,27 @@ attr = strip_trailing_space [[test7|test-colon.conf]] [DEFAULT] servers=10.11.12.13:80 + +[[test-multi-sections|test-multi-sections.conf]] +[sec-1] +cfg_item1 = abcd +cfg_item2 = efgh + +[sec-2] +cfg_item1 = abcd +cfg_item3 = /1/2/3/4:5 +cfg_item4 = end + +[sec-3] +cfg_item5 = 5555 +cfg_item6 = 6666 +cfg_item5 = 5555another + +[[test-multiline|test-multiline.conf]] +[multi] +cfg_item1 = "ab":"cd", "ef": "gh" +cfg_item1 = abcd +cfg_item2 = efgh EOF echo -n "get_meta_section_files: test0 doesn't exist: " @@ -189,8 +210,39 @@ VAL=$(cat test2a.conf) # iniset adds a blank line if it creates the file... EXPECT_VAL=" [ddd] -additional = true -type = new" +type = new +additional = true" +check_result "$VAL" "$EXPECT_VAL" + +echo -n "merge_config_file test-multi-sections: " +rm -f test-multi-sections.conf +merge_config_file test.conf test-multi-sections test-multi-sections.conf +VAL=$(cat test-multi-sections.conf) +EXPECT_VAL=' +[sec-1] +cfg_item1 = abcd +cfg_item2 = efgh + +[sec-2] +cfg_item1 = abcd +cfg_item3 = /1/2/3/4:5 +cfg_item4 = end + +[sec-3] +cfg_item5 = 5555 +cfg_item5 = 5555another +cfg_item6 = 6666' +check_result "$VAL" "$EXPECT_VAL" + +echo -n "merge_config_file test-multiline: " +rm -f test-multiline.conf +merge_config_file test.conf test-multiline test-multiline.conf +VAL=$(cat test-multiline.conf) +EXPECT_VAL=' +[multi] +cfg_item1 = "ab":"cd", "ef": "gh" +cfg_item1 = abcd +cfg_item2 = efgh' check_result "$VAL" "$EXPECT_VAL" echo -n "merge_config_group test2: " @@ -200,8 +252,8 @@ VAL=$(cat test2a.conf) # iniset adds a blank line if it creates the file... EXPECT_VAL=" [ddd] -additional = true -type = new" +type = new +additional = true" check_result "$VAL" "$EXPECT_VAL" echo -n "merge_config_group test2 no conf file: " @@ -281,4 +333,5 @@ servers = 10.11.12.13:80" check_result "$VAL" "$EXPECT_VAL" rm -f test.conf test1c.conf test2a.conf test-quote.conf test-space.conf test-equals.conf test-strip.conf test-colon.conf +rm -f test-multiline.conf test-multi-sections.conf rm -rf test-etc