Merge "XenAPI: Always update apt sources"
diff --git a/functions-common b/functions-common
index 5b29fd3..333f31d 100644
--- a/functions-common
+++ b/functions-common
@@ -119,6 +119,33 @@
     [ -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 {
@@ -522,8 +549,7 @@
 # ``get_release_name_from_branch branch-name``
 function get_release_name_from_branch {
     local branch=$1
-
-    if [[ $branch =~ "stable/" ]]; then
+    if [[ $branch =~ "stable/" || $branch =~ "proposed/" ]]; then
         echo ${branch#*/}
     else
         echo "master"
diff --git a/lib/config b/lib/config
index b44e79a..a4d59a3 100644
--- a/lib/config
+++ b/lib/config
@@ -86,7 +86,11 @@
     # 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 @@
             # 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 50e8d7b..cd74cee 100755
--- a/tests/test_config.sh
+++ b/tests/test_config.sh
@@ -108,6 +108,27 @@
 [[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 @@
 # 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 @@
 # 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 @@
 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
diff --git a/tools/xen/install_os_domU.sh b/tools/xen/install_os_domU.sh
index 75d56a8..439db68 100755
--- a/tools/xen/install_os_domU.sh
+++ b/tools/xen/install_os_domU.sh
@@ -244,6 +244,11 @@
     vm_uuid=$(xe vm-install template="$TNAME" new-name-label="$GUEST_NAME")
 fi
 
+if [ -n "${EXIT_AFTER_JEOS_INSTALLATION:-}" ]; then
+    echo "User requested to quit after JEOS instalation"
+    exit 0
+fi
+
 #
 # Prepare VM for DevStack
 #
diff --git a/tools/xen/prepare_guest.sh b/tools/xen/prepare_guest.sh
index cd189db..7383c91 100755
--- a/tools/xen/prepare_guest.sh
+++ b/tools/xen/prepare_guest.sh
@@ -114,7 +114,6 @@
     if [ ! -e $1 ]; then
         # Simple but usable vimrc
         cat > $1 <<EOF
-syntax on
 se ts=4
 se expandtab
 se shiftwidth=4