Sean Dague | e263c82 | 2014-12-05 14:25:28 -0500 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | # |
Dean Troyer | bf2ad70 | 2015-03-09 15:16:10 -0500 | [diff] [blame] | 3 | # **lib/meta-config** - Configuration file manipulation functions |
| 4 | # |
| 5 | # Support for DevStack's local.conf meta-config sections |
| 6 | # |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 7 | # These functions have no external dependencies and the following side-effects: |
| 8 | # |
| 9 | # CONFIG_AWK_CMD is defined, default is ``awk`` |
| 10 | |
| 11 | # Meta-config files contain multiple INI-style configuration files |
| 12 | # using a specific new section header to delimit them: |
| 13 | # |
| 14 | # [[group-name|file-name]] |
| 15 | # |
| 16 | # group-name refers to the group of configuration file changes to be processed |
Sean Dague | 537d402 | 2013-10-22 07:43:22 -0400 | [diff] [blame] | 17 | # at a particular time. These are called phases in ``stack.sh`` but |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 18 | # group here as these functions are not DevStack-specific. |
| 19 | # |
| 20 | # file-name is the destination of the config file |
| 21 | |
| 22 | # Save trace setting |
Dean Troyer | bf2ad70 | 2015-03-09 15:16:10 -0500 | [diff] [blame] | 23 | INC_META_XTRACE=$(set +o | grep xtrace) |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 24 | set +o xtrace |
| 25 | |
| 26 | |
| 27 | # Allow the awk command to be overridden on legacy platforms |
| 28 | CONFIG_AWK_CMD=${CONFIG_AWK_CMD:-awk} |
| 29 | |
| 30 | # Get the section for the specific group and config file |
| 31 | # get_meta_section infile group configfile |
Ian Wienand | aee18c7 | 2014-02-21 15:35:08 +1100 | [diff] [blame] | 32 | function get_meta_section { |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 33 | local file=$1 |
| 34 | local matchgroup=$2 |
| 35 | local configfile=$3 |
| 36 | |
| 37 | [[ -r $file ]] || return 0 |
| 38 | [[ -z $configfile ]] && return 0 |
| 39 | |
| 40 | $CONFIG_AWK_CMD -v matchgroup=$matchgroup -v configfile=$configfile ' |
| 41 | BEGIN { group = "" } |
Isaku Yamahata | bff0014 | 2013-12-20 11:55:08 +0900 | [diff] [blame] | 42 | /^\[\[.+\|.*\]\]/ { |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 43 | if (group == "") { |
| 44 | gsub("[][]", "", $1); |
| 45 | split($1, a, "|"); |
| 46 | if (a[1] == matchgroup && a[2] == configfile) { |
| 47 | group=a[1] |
| 48 | } |
| 49 | } else { |
| 50 | group="" |
| 51 | } |
| 52 | next |
| 53 | } |
| 54 | { |
| 55 | if (group != "") |
| 56 | print $0 |
| 57 | } |
| 58 | ' $file |
| 59 | } |
| 60 | |
| 61 | |
| 62 | # Get a list of config files for a specific group |
| 63 | # get_meta_section_files infile group |
Ian Wienand | aee18c7 | 2014-02-21 15:35:08 +1100 | [diff] [blame] | 64 | function get_meta_section_files { |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 65 | local file=$1 |
| 66 | local matchgroup=$2 |
| 67 | |
| 68 | [[ -r $file ]] || return 0 |
| 69 | |
| 70 | $CONFIG_AWK_CMD -v matchgroup=$matchgroup ' |
Sean Dague | 537d402 | 2013-10-22 07:43:22 -0400 | [diff] [blame] | 71 | /^\[\[.+\|.*\]\]/ { |
| 72 | gsub("[][]", "", $1); |
| 73 | split($1, a, "|"); |
| 74 | if (a[1] == matchgroup) |
| 75 | print a[2] |
| 76 | } |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 77 | ' $file |
| 78 | } |
| 79 | |
| 80 | |
| 81 | # Merge the contents of a meta-config file into its destination config file |
| 82 | # If configfile does not exist it will be created. |
| 83 | # merge_config_file infile group configfile |
Ian Wienand | aee18c7 | 2014-02-21 15:35:08 +1100 | [diff] [blame] | 84 | function merge_config_file { |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 85 | local file=$1 |
| 86 | local matchgroup=$2 |
| 87 | local configfile=$3 |
| 88 | |
Ian Wienand | fa3e841 | 2015-04-17 11:53:40 +1000 | [diff] [blame^] | 89 | # note, configfile might be a variable (note the iniset, etc |
| 90 | # created in the mega-awk below is "eval"ed too, so we just leave |
| 91 | # it alone. |
| 92 | local real_configfile=$(eval echo $configfile) |
| 93 | if [ ! -f $real_configfile ]; then |
| 94 | touch $real_configfile |
| 95 | fi |
| 96 | |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 97 | get_meta_section $file $matchgroup $configfile | \ |
| 98 | $CONFIG_AWK_CMD -v configfile=$configfile ' |
Robert Li | 751ad1a | 2014-10-15 21:40:53 -0400 | [diff] [blame] | 99 | BEGIN { |
| 100 | section = "" |
| 101 | last_section = "" |
| 102 | section_count = 0 |
| 103 | } |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 104 | /^\[.+\]/ { |
| 105 | gsub("[][]", "", $1); |
| 106 | section=$1 |
| 107 | next |
| 108 | } |
| 109 | /^ *\#/ { |
| 110 | next |
| 111 | } |
Dean Troyer | 2ac8b3f | 2013-12-04 17:20:28 -0600 | [diff] [blame] | 112 | /^[^ \t]+/ { |
Fergal Mc Carthy | cc87c28 | 2014-10-09 16:16:42 -0400 | [diff] [blame] | 113 | # get offset of first '=' in $0 |
| 114 | eq_idx = index($0, "=") |
| 115 | # extract attr & value from $0 |
| 116 | attr = substr($0, 1, eq_idx - 1) |
| 117 | value = substr($0, eq_idx + 1) |
| 118 | # only need to strip trailing whitespace from attr |
| 119 | sub(/[ \t]*$/, "", attr) |
| 120 | # need to strip leading & trailing whitespace from value |
| 121 | sub(/^[ \t]*/, "", value) |
| 122 | sub(/[ \t]*$/, "", value) |
Robert Li | 751ad1a | 2014-10-15 21:40:53 -0400 | [diff] [blame] | 123 | |
| 124 | # cfg_attr_count: number of config lines per [section, attr] |
| 125 | # cfg_attr: three dimensional array to keep all the config lines per [section, attr] |
| 126 | # cfg_section: keep the section names in the same order as they appear in local.conf |
| 127 | # cfg_sec_attr_name: keep the attr names in the same order as they appear in local.conf |
| 128 | if (! (section, attr) in cfg_attr_count) { |
| 129 | if (section != last_section) { |
| 130 | cfg_section[section_count++] = section |
| 131 | last_section = section |
| 132 | } |
| 133 | attr_count = cfg_sec_attr_count[section_count - 1]++ |
| 134 | cfg_sec_attr_name[section_count - 1, attr_count] = attr |
| 135 | |
| 136 | cfg_attr[section, attr, 0] = value |
| 137 | cfg_attr_count[section, attr] = 1 |
| 138 | } else { |
| 139 | lno = cfg_attr_count[section, attr]++ |
| 140 | cfg_attr[section, attr, lno] = value |
| 141 | } |
| 142 | } |
| 143 | END { |
| 144 | # Process each section in order |
| 145 | for (sno = 0; sno < section_count; sno++) { |
| 146 | section = cfg_section[sno] |
| 147 | # The ini routines simply append a config item immediately |
| 148 | # after the section header. To keep the same order as defined |
| 149 | # in local.conf, invoke the ini routines in the reverse order |
| 150 | for (attr_no = cfg_sec_attr_count[sno] - 1; attr_no >=0; attr_no--) { |
| 151 | attr = cfg_sec_attr_name[sno, attr_no] |
| 152 | if (cfg_attr_count[section, attr] == 1) |
Ian Wienand | f3bf8b6 | 2014-10-29 21:53:56 +1100 | [diff] [blame] | 153 | print "iniset " configfile " " section " " attr " \"" cfg_attr[section, attr, 0] "\"" |
Robert Li | 751ad1a | 2014-10-15 21:40:53 -0400 | [diff] [blame] | 154 | else { |
| 155 | # For multiline, invoke the ini routines in the reverse order |
| 156 | count = cfg_attr_count[section, attr] |
Doug Wiegley | 1f65fd6 | 2014-12-13 11:56:16 -0700 | [diff] [blame] | 157 | print "inidelete " configfile " " section " " attr |
Ian Wienand | f3bf8b6 | 2014-10-29 21:53:56 +1100 | [diff] [blame] | 158 | print "iniset " configfile " " section " " attr " \"" cfg_attr[section, attr, count - 1] "\"" |
Robert Li | 751ad1a | 2014-10-15 21:40:53 -0400 | [diff] [blame] | 159 | for (l = count -2; l >= 0; l--) |
Ian Wienand | f3bf8b6 | 2014-10-29 21:53:56 +1100 | [diff] [blame] | 160 | print "iniadd_literal " configfile " " section " " attr " \"" cfg_attr[section, attr, l] "\"" |
Robert Li | 751ad1a | 2014-10-15 21:40:53 -0400 | [diff] [blame] | 161 | } |
| 162 | } |
| 163 | } |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 164 | } |
| 165 | ' | while read a; do eval "$a"; done |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | |
| 169 | # Merge all of the files specified by group |
| 170 | # merge_config_group infile group [group ...] |
Ian Wienand | aee18c7 | 2014-02-21 15:35:08 +1100 | [diff] [blame] | 171 | function merge_config_group { |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 172 | local localfile=$1; shift |
| 173 | local matchgroups=$@ |
| 174 | |
| 175 | [[ -r $localfile ]] || return 0 |
| 176 | |
Dean Troyer | b1e3d0f | 2014-07-25 14:57:54 -0500 | [diff] [blame] | 177 | local configfile group |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 178 | for group in $matchgroups; do |
| 179 | for configfile in $(get_meta_section_files $localfile $group); do |
Ryota MIBU | 410f5c0 | 2014-04-04 02:00:31 +0900 | [diff] [blame] | 180 | if [[ -d $(dirname $(eval "echo $configfile")) ]]; then |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 181 | merge_config_file $localfile $group $configfile |
| 182 | fi |
| 183 | done |
| 184 | done |
| 185 | } |
| 186 | |
| 187 | |
| 188 | # Restore xtrace |
Dean Troyer | bf2ad70 | 2015-03-09 15:16:10 -0500 | [diff] [blame] | 189 | $INC_META_XTRACE |
Dean Troyer | 893e663 | 2013-09-13 15:05:51 -0500 | [diff] [blame] | 190 | |
| 191 | # Local variables: |
| 192 | # mode: shell-script |
| 193 | # End: |