[type/__uci_section] Only generate UCI commands if state differs

This commit is contained in:
Dennis Camera 2020-10-31 18:18:15 +01:00
parent 9d40500570
commit ade69729dd
4 changed files with 160 additions and 29 deletions
cdist/conf/type/__uci_section

View file

@ -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
}
}'

View file

@ -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 {

View 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
}

View file

@ -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
;; ;;