Add meta-config via local.conf

This defines a new local.conf file that is designed to take the place of all
of the 'pass-through'[1] configuration options that have been defined in DevStack.

* new local.conf file can contain multiple config file settings to be
  merged in to existing project config files
* localrc can be embedded into local.conf and will auto-extract if
  localrc does not exist
* Adds functions get_meta_section(), get_meta_section_files(),
  merge_config_file() and merge_config_group()
* Adds EXTRA_OPTS, EXTRA_BAREMETAL_OPTS, Q_DHCP_EXTRA_DEFAULT_OPTS and
  Q_SRV_EXTRA_DEFAULT_OPTS to the deprecated warning list at the end of stack.sh

[1] Pass-through options are those that do not configure or change DevStack's behaviour
but simply set a value in a project config file.  This includes most of the EXTRA_XXX_OPTS
configuration variables.

Change-Id: I367cadc86116621e9574ac203aafdab483d810d3
diff --git a/lib/config b/lib/config
new file mode 100644
index 0000000..6f686e9
--- /dev/null
+++ b/lib/config
@@ -0,0 +1,130 @@
+# lib/config - Configuration file manipulation functions
+
+# These functions have no external dependencies and the following side-effects:
+#
+# CONFIG_AWK_CMD is defined, default is ``awk``
+
+# Meta-config files contain multiple INI-style configuration files
+# using a specific new section header to delimit them:
+#
+#   [[group-name|file-name]]
+#
+# group-name refers to the group of configuration file changes to be processed
+# at a particular time.  These are called phases in ``stack.sh`` but 
+# group here as these functions are not DevStack-specific.
+#
+# file-name is the destination of the config file
+
+# Save trace setting
+C_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+
+# Allow the awk command to be overridden on legacy platforms
+CONFIG_AWK_CMD=${CONFIG_AWK_CMD:-awk}
+
+# Get the section for the specific group and config file
+# get_meta_section infile group configfile
+function get_meta_section() {
+    local file=$1
+    local matchgroup=$2
+    local configfile=$3
+
+    [[ -r $file ]] || return 0
+    [[ -z $configfile ]] && return 0
+
+    $CONFIG_AWK_CMD -v matchgroup=$matchgroup -v configfile=$configfile '
+        BEGIN { group = "" }
+        /^\[\[.+|.*\]\]/ {
+            if (group == "") {
+                gsub("[][]", "", $1);
+                split($1, a, "|");
+                if (a[1] == matchgroup && a[2] == configfile) {
+                    group=a[1]
+                }
+            } else {
+                group=""
+            }
+            next
+        }
+        {
+            if (group != "")
+                print $0
+        }
+    ' $file
+}
+
+
+# Get a list of config files for a specific group
+# get_meta_section_files infile group
+function get_meta_section_files() {
+    local file=$1
+    local matchgroup=$2
+
+    [[ -r $file ]] || return 0
+
+    $CONFIG_AWK_CMD -v matchgroup=$matchgroup '
+      /^\[\[.+\|.*\]\]/ {
+          gsub("[][]", "", $1);
+          split($1, a, "|");
+          if (a[1] == matchgroup)
+              print a[2]
+      }
+    ' $file
+}
+
+
+# Merge the contents of a meta-config file into its destination config file
+# If configfile does not exist it will be created.
+# merge_config_file infile group configfile
+function merge_config_file() {
+    local file=$1
+    local matchgroup=$2
+    local configfile=$3
+
+    [[ -r $configfile ]] || touch $configfile
+
+    get_meta_section $file $matchgroup $configfile | \
+    $CONFIG_AWK_CMD -v configfile=$configfile '
+        BEGIN { section = "" }
+        /^\[.+\]/ {
+            gsub("[][]", "", $1);
+            section=$1
+            next
+        }
+        /^ *\#/ {
+            next
+        }
+        /^.+/ {
+            split($0, d, " *= *")
+            print "iniset " configfile " " section " " d[1] " \"" d[2] "\""
+        }
+    ' | while read a; do eval "$a"; done
+
+}
+
+
+# Merge all of the files specified by group
+# merge_config_group infile group [group ...]
+function merge_config_group() {
+    local localfile=$1; shift
+    local matchgroups=$@
+
+    [[ -r $localfile ]] || return 0
+
+    for group in $matchgroups; do
+        for configfile in $(get_meta_section_files $localfile $group); do
+            if [[ -d $(dirname $configfile) ]]; then
+                merge_config_file $localfile $group $configfile
+            fi
+        done
+    done
+}
+
+
+# Restore xtrace
+$C_XTRACE
+
+# Local variables:
+# mode: shell-script
+# End: