forked from ungleich-public/cdist
		
	[type/__uci_section] Only generate UCI commands if state differs
This commit is contained in:
		
					parent
					
						
							
								9d40500570
							
						
					
				
			
			
				commit
				
					
						ade69729dd
					
				
			
		
					 4 changed files with 160 additions and 29 deletions
				
			
		| 
						 | 
					@ -25,4 +25,24 @@ section=$("${__type_explorer:?}/match")
 | 
				
			||||||
test -n "${section}" || exit 0
 | 
					test -n "${section}" || exit 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uci -s -N -d "${RS}" show "${section}" 2>/dev/null \
 | 
					uci -s -N -d "${RS}" show "${section}" 2>/dev/null \
 | 
				
			||||||
| grep -v -e "^${section}=" || true
 | 
					| awk -v VSEP="${RS}" '
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
						  # Strip off the config and section parts
 | 
				
			||||||
 | 
						  is_opt = sub(/^([^.]*\.){2}/, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  if (!is_opt) {
 | 
				
			||||||
 | 
							  # this line represents the section -> skip
 | 
				
			||||||
 | 
							  next
 | 
				
			||||||
 | 
						  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  if (index($0, VSEP)) {
 | 
				
			||||||
 | 
							  # Put values each on a line, like --option and --list parameters
 | 
				
			||||||
 | 
							  opt = substr($0, 1, index($0, "=") - 1)
 | 
				
			||||||
 | 
							  split(substr($0, length(opt) + 2), values, VSEP)
 | 
				
			||||||
 | 
							  for (i in values) {
 | 
				
			||||||
 | 
								  printf "%s=%s\n", opt, values[i]
 | 
				
			||||||
 | 
							  }
 | 
				
			||||||
 | 
						  } else {
 | 
				
			||||||
 | 
							  print
 | 
				
			||||||
 | 
						  }
 | 
				
			||||||
 | 
					  }'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,14 +6,6 @@ grep_line() {
 | 
				
			||||||
	{ shift; printf '%s\n' "$@"; } | grep -qxF "$1"
 | 
						{ shift; printf '%s\n' "$@"; } | grep -qxF "$1"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
prefix_lines() {
 | 
					 | 
				
			||||||
	while test $# -gt 0
 | 
					 | 
				
			||||||
	do
 | 
					 | 
				
			||||||
		echo "$2" | awk -v prefix="$1" '$0 { printf "%s %s\n", prefix, $0 }'
 | 
					 | 
				
			||||||
		shift; shift
 | 
					 | 
				
			||||||
	done
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
print_errors() {
 | 
					print_errors() {
 | 
				
			||||||
	awk -v prefix="${1:-Found errors:}" -v suffix="${2-}" '
 | 
						awk -v prefix="${1:-Found errors:}" -v suffix="${2-}" '
 | 
				
			||||||
		BEGIN {
 | 
							BEGIN {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										91
									
								
								cdist/conf/type/__uci_section/files/option_state.awk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								cdist/conf/type/__uci_section/files/option_state.awk
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,91 @@
 | 
				
			||||||
 | 
					# -*- mode: awk; indent-tabs-mode:t -*-
 | 
				
			||||||
 | 
					# Usage: awk -f option_state.awk option_type option_name
 | 
				
			||||||
 | 
					# e.g. awk -f option_state.awk option title
 | 
				
			||||||
 | 
					#      awk -f option_state.awk list entry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function unquote(s) {
 | 
				
			||||||
 | 
						# simplified dequoting of single quoted strings
 | 
				
			||||||
 | 
						if (s ~ /^'.*'$/) {
 | 
				
			||||||
 | 
							s = substr(s, 2, length(s) - 2)
 | 
				
			||||||
 | 
							sub(/'\\''/, "'", s)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function valueof(line) {
 | 
				
			||||||
 | 
						if (line !~ /^[[:alpha:]_]+=/) return 0
 | 
				
			||||||
 | 
						return unquote(substr(line, index(line, "=") + 1))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BEGIN {
 | 
				
			||||||
 | 
						__object = ENVIRON["__object"]
 | 
				
			||||||
 | 
						if (!__object) exit 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opttype = ARGV[1]
 | 
				
			||||||
 | 
						optname = ARGV[2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (opttype !~ /^(option|list)/ || !optname) {
 | 
				
			||||||
 | 
							print "invalid"
 | 
				
			||||||
 | 
							exit (e=1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ARGV[1] = __object "/parameter/" opttype
 | 
				
			||||||
 | 
						ARGV[2] = __object "/explorer/options"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						state = "present"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NR == FNR {
 | 
				
			||||||
 | 
						# memoize "should" state
 | 
				
			||||||
 | 
						if (index($0, optname "=") == 1) {
 | 
				
			||||||
 | 
							should[++should_count] = valueof($0)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# go to next line (important!)
 | 
				
			||||||
 | 
						next
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						# compare "is" state
 | 
				
			||||||
 | 
						if (index($0, optname "=") != 1)
 | 
				
			||||||
 | 
							next
 | 
				
			||||||
 | 
						++is_count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v = valueof($0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (v == should[is_count]) {
 | 
				
			||||||
 | 
							# looks good, but can't say definitely just from this line
 | 
				
			||||||
 | 
						} else if (is_count > should_count) {
 | 
				
			||||||
 | 
							# there are more "is" records than "should" -> definitely different
 | 
				
			||||||
 | 
							state = "different"
 | 
				
			||||||
 | 
							exit
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							# see if we can find the "is" value somewhere in "should"
 | 
				
			||||||
 | 
							for (i in should) {
 | 
				
			||||||
 | 
								if (v == should[i]) {
 | 
				
			||||||
 | 
									# value found -> could be rearranged
 | 
				
			||||||
 | 
									# FIXME: Duplicate values are not properly handled here. Do they matter?
 | 
				
			||||||
 | 
									state = "rearranged"
 | 
				
			||||||
 | 
									next
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# "is" value could not be found in "should" -> definitely different
 | 
				
			||||||
 | 
							state = "different"
 | 
				
			||||||
 | 
							exit
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					END {
 | 
				
			||||||
 | 
						if (e) exit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!is_count) {
 | 
				
			||||||
 | 
							# no "is" values -> absent
 | 
				
			||||||
 | 
							state = "absent"
 | 
				
			||||||
 | 
						} else if (is_count < should_count) {
 | 
				
			||||||
 | 
							# "is" was shorter than "should" -> different
 | 
				
			||||||
 | 
							state = "different"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						print state
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -70,7 +70,8 @@ in
 | 
				
			||||||
		fi
 | 
							fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Make sure the section itself is present
 | 
							# Make sure the section itself is present
 | 
				
			||||||
		if test "${state_is}" = absent
 | 
							if test "${state_is}" = absent \
 | 
				
			||||||
 | 
								|| test "${type_is}" != "${type_should#*.}"
 | 
				
			||||||
		then
 | 
							then
 | 
				
			||||||
			printf 'set %s\n' "${section}" >>"${__messages_out:?}"
 | 
								printf 'set %s\n' "${section}" >>"${__messages_out:?}"
 | 
				
			||||||
			# shellcheck disable=SC2140
 | 
								# shellcheck disable=SC2140
 | 
				
			||||||
| 
						 | 
					@ -78,7 +79,7 @@ in
 | 
				
			||||||
		fi
 | 
							fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Delete options/lists not in "should"
 | 
							# Delete options/lists not in "should"
 | 
				
			||||||
		sed -e 's/=.*$//;s/^.*\.//' "${__object:?}/explorer/options" \
 | 
							sed -e 's/=.*$//' "${__object:?}/explorer/options" \
 | 
				
			||||||
		| while read -r _optname
 | 
							| while read -r _optname
 | 
				
			||||||
		  do
 | 
							  do
 | 
				
			||||||
			  grep_line "${_optname}" "${listnames_should}" "${optnames_should}" || {
 | 
								  grep_line "${_optname}" "${listnames_should}" "${optnames_should}" || {
 | 
				
			||||||
| 
						 | 
					@ -87,18 +88,55 @@ in
 | 
				
			||||||
			  } </dev/null
 | 
								  } </dev/null
 | 
				
			||||||
		  done
 | 
							  done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Set "should" options
 | 
							opt_proc_error() {
 | 
				
			||||||
		prefix_lines option "${optnames_should}" list "${listnames_should}" \
 | 
								printf 'An error occurred during processing of option %s\n' "${1:?}" >&2
 | 
				
			||||||
		| while read -r _type _optname
 | 
								exit 1
 | 
				
			||||||
		  do
 | 
							}
 | 
				
			||||||
			  test -n "${_type}${_optname}" || continue  # ignore empty lines
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			  case $_type
 | 
							# Set "should" options
 | 
				
			||||||
 | 
							echo "${optnames_should}" \
 | 
				
			||||||
 | 
							| grep -e . \
 | 
				
			||||||
 | 
							| while read -r _optname
 | 
				
			||||||
 | 
							  do
 | 
				
			||||||
 | 
								  _opt_state=$(awk -f "${__type:?}/files/option_state.awk" option "${_optname}") \
 | 
				
			||||||
 | 
									  || opt_proc_error "${_optname}"
 | 
				
			||||||
 | 
								  case ${_opt_state}
 | 
				
			||||||
			  in
 | 
								  in
 | 
				
			||||||
				  (list)
 | 
									  (invalid)
 | 
				
			||||||
 | 
										  opt_proc_error "${_optname}"
 | 
				
			||||||
 | 
										  ;;
 | 
				
			||||||
 | 
									  (present)
 | 
				
			||||||
 | 
										  ;;
 | 
				
			||||||
 | 
									  (*)
 | 
				
			||||||
 | 
										  printf 'set %s\n' "${section}.${_optname}" >>"${__messages_out:?}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										  # shellcheck disable=SC2140
 | 
				
			||||||
 | 
										  uci_cmd set "${section}.${_optname}"="$(
 | 
				
			||||||
 | 
											  grep -e "^${_optname}=" "${__object:?}/parameter/option" \
 | 
				
			||||||
 | 
											  | sed -e 's/^.*=//' \
 | 
				
			||||||
 | 
											  | unquote_lines \
 | 
				
			||||||
 | 
											  | head -n 1)"
 | 
				
			||||||
 | 
										  ;;
 | 
				
			||||||
 | 
								  esac
 | 
				
			||||||
 | 
							  done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							echo "${listnames_should}" \
 | 
				
			||||||
 | 
							| grep -e . \
 | 
				
			||||||
 | 
							| while read -r _optname
 | 
				
			||||||
 | 
							  do
 | 
				
			||||||
 | 
								  _list_state=$(awk -f "${__type:?}/files/option_state.awk" list "${_optname}") \
 | 
				
			||||||
 | 
									  || opt_proc_error "${_optname}"
 | 
				
			||||||
 | 
								  case ${_list_state}
 | 
				
			||||||
 | 
								  in
 | 
				
			||||||
 | 
									  (invalid)
 | 
				
			||||||
 | 
										  opt_proc_error "${_optname}"
 | 
				
			||||||
 | 
										  ;;
 | 
				
			||||||
 | 
									  (present)
 | 
				
			||||||
 | 
										  ;;
 | 
				
			||||||
 | 
									  (*)
 | 
				
			||||||
					  printf 'set_list %s\n' "${section}.${_optname}" >>"${__messages_out:?}"
 | 
										  printf 'set_list %s\n' "${section}.${_optname}" >>"${__messages_out:?}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					  if grep -q -e "^${_optname}=" "${__object:?}/explorer/options"
 | 
										  if test "${_list_state}" != absent
 | 
				
			||||||
					  then
 | 
										  then
 | 
				
			||||||
						  uci_cmd delete "${section}.${_optname}"
 | 
											  uci_cmd delete "${section}.${_optname}"
 | 
				
			||||||
					  fi
 | 
										  fi
 | 
				
			||||||
| 
						 | 
					@ -112,16 +150,6 @@ in
 | 
				
			||||||
						    uci_cmd add_list "${section}.${_optname}"="${_value}"
 | 
											    uci_cmd add_list "${section}.${_optname}"="${_value}"
 | 
				
			||||||
					    done
 | 
										    done
 | 
				
			||||||
					  ;;
 | 
										  ;;
 | 
				
			||||||
				  (option)
 | 
					 | 
				
			||||||
					  printf 'set %s\n' "${section}.${_optname}" >>"${__messages_out:?}"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					  # shellcheck disable=SC2140
 | 
					 | 
				
			||||||
					  uci_cmd set "${section}.${_optname}"="$(
 | 
					 | 
				
			||||||
						  grep "^${_optname}=" "${__object:?}/parameter/option" \
 | 
					 | 
				
			||||||
						  | sed -e 's/^.*=//' \
 | 
					 | 
				
			||||||
						  | unquote_lines \
 | 
					 | 
				
			||||||
						  | head -n 1)"
 | 
					 | 
				
			||||||
					  ;;
 | 
					 | 
				
			||||||
			  esac
 | 
								  esac
 | 
				
			||||||
		  done
 | 
							  done
 | 
				
			||||||
		;;
 | 
							;;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue