diff --git a/cdist/conf/type/__uci_section/files/functions.sh b/cdist/conf/type/__uci_section/files/functions.sh index 9f510958..17c64bbc 100644 --- a/cdist/conf/type/__uci_section/files/functions.sh +++ b/cdist/conf/type/__uci_section/files/functions.sh @@ -1,13 +1,6 @@ # -*- mode: sh; indent-tabs-mode: t -*- -append_values() { - while read -r _value - do - set -- "$@" --value "${_value}" - done - unset _value - "$@" &2 } +quote() { + for _arg + do + shift + if test -n "$(printf %s "${_arg}" | tr -d -c '\t\n \042-\047\050-\052\073-\077\133\\`|~' | tr -c '' '.')" + then + # needs quoting + set -- "$@" "$(printf "'%s'" "$(printf %s "${_arg}" | sed -e "s/'/'\\\\''/g")")" + else + set -- "$@" "${_arg}" + fi + done + unset _arg + printf '%s' "$*" +} + +uci_cmd() { + # Usage: uci_cmd [UCI ARGUMENTS]... + mkdir -p "${__object:?}/files" + printf '%s\n' "$(quote "$@")" >>"${__object:?}/files/uci_batch.txt" +} + uci_validate_name() { # like util.c uci_validate_name() test -n "$*" && test -z "$(printf %s "$*" | tr -d '[:alnum:]_' | tr -c '' .)" diff --git a/cdist/conf/type/__uci_section/files/uci_apply.sh b/cdist/conf/type/__uci_section/files/uci_apply.sh new file mode 120000 index 00000000..4209151f --- /dev/null +++ b/cdist/conf/type/__uci_section/files/uci_apply.sh @@ -0,0 +1 @@ +../../__uci/files/uci_apply.sh \ No newline at end of file diff --git a/cdist/conf/type/__uci_section/gencode-remote b/cdist/conf/type/__uci_section/gencode-remote new file mode 100755 index 00000000..05bca0a7 --- /dev/null +++ b/cdist/conf/type/__uci_section/gencode-remote @@ -0,0 +1,146 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# shellcheck source=files/functions.sh +. "${__type:?}/files/functions.sh" + + +section=$(cat "${__object:?}/explorer/match") + +state_is=$(test -s "${__object:?}/explorer/type" && echo present || echo absent) +state_should=$(cat "${__object:?}/parameter/state") + +case $state_should +in + (present) + test -f "${__object:?}/parameter/type" || { + echo 'Parameter --type is required.' >&2 + exit 1 + } + + type_is=$(cat "${__object:?}/explorer/type") + type_should=$(cat "${__object:?}/parameter/type") + + if test -n "${type_is}" + then + sect_type=${type_is} + else + sect_type=${type_should##*.} + fi + + if test -z "${section}" + then + # No section exists and --match was used. + # So we generate a new section identifier from $__object_id. + case ${__object_id:?} + in + (*.*) section=${__object_id:?} ;; + (*) section="${type_should%%.*}.${__object_id:?}" ;; + esac + fi + + # Collect option names + if test -f "${__object:?}/parameter/list" + then + listnames_should=$( + sed -e 's/=.*$//' "${__object:?}/parameter/list" | sort -u) + fi + + if test -f "${__object:?}/parameter/option" + then + optnames_should=$( + sed -e 's/=.*$//' "${__object:?}/parameter/option" | sort -u) + fi + + # Make sure the section itself is present + if test "${state_is}" = absent + then + printf 'set %s\n' "${section}" >>"${__messages_out:?}" + # shellcheck disable=SC2140 + uci_cmd set "${section}"="${sect_type}" + fi + + # Delete options/lists not in "should" + sed -e 's/=.*$//;s/^.*\.//' "${__object:?}/explorer/options" \ + | while read -r _optname + do + grep_line "${_optname}" "${listnames_should}" "${optnames_should}" || { + printf 'delete %s\n' "${section}.${_optname}" >>"${__messages_out:?}" + uci_cmd delete "${section}.${_optname}" + } >"${__messages_out:?}" + + if grep -q -e "^${_optname}=" "${__object:?}/explorer/options" + then + uci_cmd delete "${section}.${_optname}" + fi + + grep "^${_optname}=" "${__object:?}/parameter/list" \ + | sed -e 's/^.*=//' \ + | unquote_lines \ + | while read -r _value + do + # shellcheck disable=SC2140 + uci_cmd add_list "${section}.${_optname}"="${_value}" + 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 + done + ;; + (absent) + if test "${state_is}" = absent + then + # if explorer found no section there is nothing to delete + exit 0 + fi + + printf 'delete %s\n' "${section}" >>"${__messages_out:?}" + uci_cmd delete "${section}" + ;; +esac + +if test -s "${__object:?}/files/uci_batch.txt" +then + cat "${__type:?}/files/uci_apply.sh" + printf "uci_apply <<'EOF'\n" + cat "${__object:?}/files/uci_batch.txt" + printf '\nEOF\n' +fi diff --git a/cdist/conf/type/__uci_section/manifest b/cdist/conf/type/__uci_section/manifest index 41e30a07..7e23e443 100755 --- a/cdist/conf/type/__uci_section/manifest +++ b/cdist/conf/type/__uci_section/manifest @@ -43,8 +43,6 @@ in ;; esac -section=$(cat "${__object:?}/explorer/match") - state_should=$(cat "${__object:?}/parameter/state") case $state_should @@ -57,85 +55,31 @@ in type_is=$(cat "${__object:?}/explorer/type") type_should=$(cat "${__object:?}/parameter/type") - if test -n "${type_is}" + if test -n "${type_is}" && test "${type_is}" != "${type_should##*.}" then - if test "${type_is}" != "${type_should##*.}" - then - # Check if section type matches (section exists and --type provided) - printf 'Section type "%s" does not match --type "%s".\n' \ - "${type_is}" "${type_should}" >&2 - exit 1 - fi - sect_type=${type_is} - else - sect_type=${type_should##*.} - fi - - if test -z "${section}" - then - # No section exists and --match was used. - # So we generate a new section identifier from $__object_id. - case ${__object_id:?} - in - (*.*) section=${__object_id:?} ;; - (*) section="${type_should%%.*}.${__object_id:?}" ;; - esac + # Check if section type matches (section exists and --type provided) + printf 'Section type "%s" does not match --type "%s".\n' \ + "${type_is}" "${type_should}" >&2 + exit 1 fi # Check options for syntax errors validate_options "${__object:?}/parameter/list" "${__object:?}/parameter/object" \ | print_errors 'Found erroneous options in arguments:' - # Collect option names - if test -f "${__object:?}/parameter/list" + # Check for duplicate option names + if test -s "${__object:?}/parameter/option" then - listnames_should=$( - sed -e 's/=.*$//' "${__object:?}/parameter/list" | sort -u) - fi - - if test -f "${__object:?}/parameter/option" - then - optnames_should=$(sed -e 's/=.*$//' "${__object:?}/parameter/option" | sort) - - echo "${optnames_should}" \ + sed -e 's/=.*$//' "${__object:?}/parameter/option" \ + | sort \ | uniq -d \ | print_errors \ 'Found duplicate --options:' \ "$(printf '\nUse --list for lists, instead.')" fi - - # Make sure the section itself is present - __uci "${section}" --state present --value "${sect_type}" - export require=__uci/"${section}" - - # Delete options/lists not in "should" - sed -e 's/=.*$//;s/^.*\.//' "${__object:?}/explorer/options" \ - | while read -r optname - do - grep_line "${optname}" "${listnames_should}" "${optnames_should}" || { - __uci "${section}.${optname}" --state absent - } &2 diff --git a/cdist/conf/type/__uci_section/nonparallel b/cdist/conf/type/__uci_section/nonparallel new file mode 100644 index 00000000..e69de29b