From 8c7a6906def0fcf0c5693c1cb5c4b30d5d880d51 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Fri, 5 Mar 2021 20:38:19 +0100 Subject: [PATCH 01/16] __ini_value: starting base parts Initial body of the __ini_value. It contains two awk-scripts: to detect the state that is important to trigger a code generation, and to change that line to the correct line. It might have problems which is not matured enoght. The most difficult points will be the comment detection, as this is a critical point as you don't know if the user want to have this touched. --- cdist/conf/type/__ini_value/explorer/state | 152 ++++++++++++++++++ cdist/conf/type/__ini_value/files/base.awk | 128 +++++++++++++++ cdist/conf/type/__ini_value/files/common.awk | 61 +++++++ cdist/conf/type/__ini_value/files/gen-awk.sh | 53 ++++++ .../__ini_value/files/parts/absent/found.awk | 3 + .../files/parts/commented/found.awk | 8 + .../files/parts/commented/insert.awk | 9 ++ .../__ini_value/files/parts/present/found.awk | 8 + .../files/parts/present/insert.awk | 9 ++ cdist/conf/type/__ini_value/gencode-remote | 26 +++ cdist/conf/type/__ini_value/parameter/boolean | 1 + .../parameter/default/comment-sign | 2 + .../__ini_value/parameter/default/indentation | 1 + .../type/__ini_value/parameter/default/state | 1 + .../conf/type/__ini_value/parameter/optional | 6 + .../__ini_value/parameter/optional_multiple | 1 + .../conf/type/__ini_value/parameter/required | 2 + 17 files changed, 471 insertions(+) create mode 100755 cdist/conf/type/__ini_value/explorer/state create mode 100644 cdist/conf/type/__ini_value/files/base.awk create mode 100644 cdist/conf/type/__ini_value/files/common.awk create mode 100755 cdist/conf/type/__ini_value/files/gen-awk.sh create mode 100644 cdist/conf/type/__ini_value/files/parts/absent/found.awk create mode 100644 cdist/conf/type/__ini_value/files/parts/commented/found.awk create mode 100644 cdist/conf/type/__ini_value/files/parts/commented/insert.awk create mode 100644 cdist/conf/type/__ini_value/files/parts/present/found.awk create mode 100644 cdist/conf/type/__ini_value/files/parts/present/insert.awk create mode 100755 cdist/conf/type/__ini_value/gencode-remote create mode 100644 cdist/conf/type/__ini_value/parameter/boolean create mode 100644 cdist/conf/type/__ini_value/parameter/default/comment-sign create mode 100644 cdist/conf/type/__ini_value/parameter/default/indentation create mode 100644 cdist/conf/type/__ini_value/parameter/default/state create mode 100644 cdist/conf/type/__ini_value/parameter/optional create mode 100644 cdist/conf/type/__ini_value/parameter/optional_multiple create mode 100644 cdist/conf/type/__ini_value/parameter/required diff --git a/cdist/conf/type/__ini_value/explorer/state b/cdist/conf/type/__ini_value/explorer/state new file mode 100755 index 00000000..1808d90e --- /dev/null +++ b/cdist/conf/type/__ini_value/explorer/state @@ -0,0 +1,152 @@ +#!/bin/sh -e +# __ini_value/explorer/state + +# Check the state of the key-value pair in the ini file +# +# There are following states: +# - present +# - wrongvalue +# - wrongformat +# - commented +# - absent +# - nosuchfile + +# Using ' \t' for matching spaces as char classes not implemented in mawk +# see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=65617#40 + +# Parameters +# (maybe multi-variable object id for this ..) +#state_should="$(cat "$__object/parameter/state")" +file="$(cat "$__object/parameter/file")" + +# abort if no file exist +if ! [ -f "$file" ]; then + echo nosuchfile + exit +fi + +# run awk +awk -f - "$file" <<'AWK' +function trim(var) { + sub(/^[ \t]*/, "", var) + sub(/[ \t]*$/, "", var) + return var +} +function check_spaces(var) { + return match(var, /^[ \t]*$/) == 1 +} +function state(val) { + print val + exit +} + +BEGIN { + _param = (ENVIRON["__object"] "/parameter/") + getline state_should < (_param "state") + getline section < (_param "section") + getline key < (_param "key") + getline delimiter < (_param "delimiter") + getline value < (_param "value") + getline indentation < (_param "indentation") + + do_normalization = (system("test -f " (_param "normalize")) == 0) + + i=0; _comm_param = (_param "comment-sign"); + while((getline tmp < _comm_param) > 0) { + comment_signs[i++] = tmp + } + + found=0 + curr_section="" + if(section == "") + found_section=1 + else + found_section=0 +} + +# catch sections +/^[ \t]*\[.*\][ \t]*$/ { + curr_section = trim($0) + if(found_section) + exit # game over, section ends + if(section == curr_section) + found_section=1 + next +} + +# only interesting if a delimiter was found +found_section { + line = $0 + + # index 1 cause of trimmed string + if((idel = index(line, delimiter)) && (ikey = index(line, key))) { + if(ikey > 1) { + # maybe comment character or only spaces + start_string = substr(line, 1, ikey - 1) + + # something inside rather than a space -> comment + if((icom = match(start_string, /[^ \t]+/)) > 0) { + # icom = RSTART + # only one free-standing char or directly before the key + if(RLENGTH == 1 || icom == ikey - 1) { + start_sign = substr(line, RSTART, 1) + is_com=0 + for(i in comment_signs) { + if(start_sign == comment_signs[i]) { + is_com = 1; break; + } + } + if(!is_com) next + else { + aftercom_length = ikey - icom - 1 + if(!check_spaces(substr(line, icom + 1, aftercom_length))) next + start_spaces = (icom - 1) + aftercom_length + } + } + else next + } + # must only contain spaces + else start_spaces = ikey - 1 + } + # start_spaces set or 0 + + idelspace_start = ikey + length(key) + idelspace_length = idel - (idelspace_start) + # check for delimiter is only preceded with spaces + if(idelspace_length == 0 || check_spaces(substr(line, idelspace_start, idelspace_length))) { + found = 1 + + # short-circuit on state absent to just delete + if(state_should == "absent") state("present"); + + + # extract the value + found_value = substr(line, idel + length(delimiter)) + is_value = trim(found_value) + + # check if value is incorrect + if(value != is_value) state("wrongvalue") + else { + # check if the format is important + if(do_normalization) { + # the format must exactly match, else it is incorrect + if(indentation != start_spaces || idelspace_length != 0 || found_value != is_value) + state("wrongformat") + } + + if(is_com) + state("commented") + else + state("present") + } + # this will never be reached + } + } +} + +# in the end, check if it is absent +END { + if(!found) + state("absent") +} +AWK diff --git a/cdist/conf/type/__ini_value/files/base.awk b/cdist/conf/type/__ini_value/files/base.awk new file mode 100644 index 00000000..16ff5808 --- /dev/null +++ b/cdist/conf/type/__ini_value/files/base.awk @@ -0,0 +1,128 @@ +BEGIN { + #bufindex = 0 + #maxbuflen = 2 + + # no section means the start to the first section + if(section == "") { + is_curr_section = 1 + found_section = 1 + } +} + +# legacy function +function flush_buffer() { + #while(bufindex > 0) { + # _pop_buffer() + #} + if(lastlinepopulated) { + print lastline + lastlinepopulated = 0 + } +} + +# excepts the first character is the sign to check (string is trimmed) +function is_comment(line) { + # get character and check + line_sign = substr(line, 1, 1) + for(i in comment_signs) + if(line_sign == comment_signs[i]) + return 1 + + # nothing found + return 0 +} +function was_comment(line, comment) { + line = trim(line) + if(is_comment(line)) { + return trim(substr(line, 2)) == comment + } +} + +# print everything if line found instead of processing it +# maybe just a function to loop through getline for lightest overhead +found {print; next} + +# main loop (til the line was found) +!found { + line = trim($0) + # short curcit on empty lines + if(line == "") { + # TODO code to function! + flush_buffer() + lastline = $0 + lastlinepopulated = 1 + next + } + + # write to linebuffer + #if(bufindex > maxbuflen) + # _pop_buffer() + #linebuffer[++bufindex] = $0 + + # check for a ini section + if(substr(line, 1, 1) == "[" && substr(line, length(line), 1) == "]") { + is_section = 1 + curr_section = line + + if(curr_section == section) { + found_section = 1 + is_curr_section = 1 + } + else { + # if nothing found, print it in the valid section before the next one + if(is_curr_section) { + if(!found) { + # set found as it is there now + found=1 + + # %codeblock_insert% + } + is_curr_section = 0 + } + } + } + else { + # only current session is interessting + if(is_curr_section) { + # check for a comment + is_com = is_comment(line) + if(is_com) { + line = trim(substr(line, 2)) + } + + # check for a delimiter and a key (must be at first position due to trimming) + if((idel = index(line, delimiter)) && (ikey = index(line, key)) == 1) { + # check there are only spaces between the delimiter + if(check_spaces(substr(line, ikey + length(key), idel - (length(key) + 1)))) { + found = 1 + + # %codeblock_found% + + next + } + } + } + } + + # TODO + # works cause no next statement from above *structual programming* + #print lastline + flush_buffer() + lastline = $0 + lastlinepopulated = 1 +} + +END { + # if not found, it's not already printed + if(!found) { + flush_buffer() + + # print with section if not found + if(!found_section) { + # TODO check via buffer if a empty line is necessary + print section + + # %codeblock_insert% + } + } +} diff --git a/cdist/conf/type/__ini_value/files/common.awk b/cdist/conf/type/__ini_value/files/common.awk new file mode 100644 index 00000000..8874f0b8 --- /dev/null +++ b/cdist/conf/type/__ini_value/files/common.awk @@ -0,0 +1,61 @@ +BEGIN { + # parameter variables + section = get_param_string("section") + key = get_param_string("key") + delimiter = get_param_string("delimiter") + value = get_param_string("value") + comment = get_param_string("comment") + indentation = get_param_string("indentation") + + get_param_array("comment-sign", comment_signs) + comment_sign = comment_signs[0] +} + +function trim(var) { + sub(/^[ \t]*/, "", var) + sub(/[ \t]*$/, "", var) + return var +} +function check_spaces(part) { + return match(part, /^[ \t]*$/) == 1 +} + +function get_param_string(name) { + _paramfile = (ENVIRON["__object"] "/parameter/" name) + if((getline tmp < _paramfile) > 0) { + close(_paramfile) + return tmp + } + else return "" +} +function get_param_array(name, arr) { + _paramfile = (ENVIRON["__object"] "/parameter/" name) + i=0 + split("", arr) # portable clear, like `delete arr` + while((getline tmp < _paramfile) > 0) { + arr[i++] = tmp + } + close(_paramfile) +} + +# print value +function v_print() { + spaces = "" + for(i = 0; i < indentation; i++) + spaces = (spaces " ") + printf "%s%s%s%s%s", spaces, key, delimiter, value, ORS +} +# print commented value +function v_print_commented() { + spaces = "" + for(i = 0; i < indentation; i++) + spaces = (spaces " ") + printf "%s%s%s%s%s%s", spaces, comment_sign, key, delimiter, value, ORS +} +# print comment +function c_print() { + spaces = "" + for(i = 0; i < indentation; i++) + spaces = (spaces " ") + printf "%s%s%s%s%s", spaces, comment_sign, " ", comment, ORS +} diff --git a/cdist/conf/type/__ini_value/files/gen-awk.sh b/cdist/conf/type/__ini_value/files/gen-awk.sh new file mode 100755 index 00000000..ba26672a --- /dev/null +++ b/cdist/conf/type/__ini_value/files/gen-awk.sh @@ -0,0 +1,53 @@ +#!/bin/sh -e +# __ini_value/files/gen-awk.sh + +# Generates the awk script that will modify the line +# +# Arguments: +# 1: the file to modify +# 2: the should_state + +strip_comments() { + grep -v '^[[:space:]]*\($\|#\)' +} + + +file="$1" +state="$2" + + +# Generate the basic awk struct +cat < "\$tmpfile" <<'AWK' +SHELL + + +# generate the awk script and strip unnecessary things +{ + # basic functions which everyone needs + cat "$__type/files/common.awk" + + # generate the script and strip + awk -v state="$state" ' + { + if(match($0, /^[ \t]*# %codeblock_([^%]+)%$/, result) > 0) { + file = (ENVIRON["__type"] "/files/parts/" state "/" result[1] ".awk") + while((getline line < file) > 0) + print line + close(file) + } + else print + }' "$__type/files/base.awk" +} | strip_comments + + +# end of here-doc +cat <&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__ini_value/parameter/boolean b/cdist/conf/type/__ini_value/parameter/boolean new file mode 100644 index 00000000..f9a8b6aa --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/boolean @@ -0,0 +1 @@ +normalize diff --git a/cdist/conf/type/__ini_value/parameter/default/comment-sign b/cdist/conf/type/__ini_value/parameter/default/comment-sign new file mode 100644 index 00000000..406ac1cc --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/default/comment-sign @@ -0,0 +1,2 @@ +; +# diff --git a/cdist/conf/type/__ini_value/parameter/default/indentation b/cdist/conf/type/__ini_value/parameter/default/indentation new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/default/indentation @@ -0,0 +1 @@ +0 diff --git a/cdist/conf/type/__ini_value/parameter/default/state b/cdist/conf/type/__ini_value/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__ini_value/parameter/optional b/cdist/conf/type/__ini_value/parameter/optional new file mode 100644 index 00000000..031c807b --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/optional @@ -0,0 +1,6 @@ +section +key +state +value +indentation +comment diff --git a/cdist/conf/type/__ini_value/parameter/optional_multiple b/cdist/conf/type/__ini_value/parameter/optional_multiple new file mode 100644 index 00000000..bac05165 --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/optional_multiple @@ -0,0 +1 @@ +comment-sign diff --git a/cdist/conf/type/__ini_value/parameter/required b/cdist/conf/type/__ini_value/parameter/required new file mode 100644 index 00000000..3ae10da3 --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/required @@ -0,0 +1,2 @@ +file +delimiter From 10427fde84d8563762020565230cde63ff031752 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Sat, 6 Mar 2021 17:06:32 +0100 Subject: [PATCH 02/16] __ini_value: implement multi-line buffer This buffer gives the ability to look a bit longer into the past than just a single line. This is helpfull to get a bigger context when fiddling around comments. This also erases the need of `lastlinepopulated` as there is something in the pipe or nothing. --- cdist/conf/type/__ini_value/files/base.awk | 53 ++++++++++--------- .../__ini_value/files/parts/absent/found.awk | 8 +-- .../files/parts/commented/found.awk | 2 +- .../files/parts/commented/insert.awk | 2 +- .../__ini_value/files/parts/present/found.awk | 2 +- .../files/parts/present/insert.awk | 2 +- 6 files changed, 38 insertions(+), 31 deletions(-) diff --git a/cdist/conf/type/__ini_value/files/base.awk b/cdist/conf/type/__ini_value/files/base.awk index 16ff5808..51c3ba99 100644 --- a/cdist/conf/type/__ini_value/files/base.awk +++ b/cdist/conf/type/__ini_value/files/base.awk @@ -1,6 +1,7 @@ BEGIN { - #bufindex = 0 - #maxbuflen = 2 + bufindex = -1 + buflen = 0 + maxbuflen = 2 # no section means the start to the first section if(section == "") { @@ -9,15 +10,31 @@ BEGIN { } } -# legacy function +# controls the line buffer function flush_buffer() { - #while(bufindex > 0) { - # _pop_buffer() - #} - if(lastlinepopulated) { - print lastline - lastlinepopulated = 0 - } + while(buflen > 0) + _pop_line() +} +function push_line() { + linebuf[++bufindex] = $0 + buflen++; + while(buflen > maxbuflen) _pop_line() +} +function revert_line() { + # no delete, because it will be overwritten by the next line if any .. + bufindex-- + buflen-- +} +function lastline() { + if(buflen > 0) return linebuf[bufindex] +} +function pop_line() { + if(buflen > 0) _pop_line() +} +function _pop_line() { + _index = bufindex - (--buflen) + print linebuf[_index] + delete linebuf[_index] } # excepts the first character is the sign to check (string is trimmed) @@ -47,18 +64,10 @@ found {print; next} line = trim($0) # short curcit on empty lines if(line == "") { - # TODO code to function! - flush_buffer() - lastline = $0 - lastlinepopulated = 1 + push_line() next } - # write to linebuffer - #if(bufindex > maxbuflen) - # _pop_buffer() - #linebuffer[++bufindex] = $0 - # check for a ini section if(substr(line, 1, 1) == "[" && substr(line, length(line), 1) == "]") { is_section = 1 @@ -104,12 +113,8 @@ found {print; next} } } - # TODO # works cause no next statement from above *structual programming* - #print lastline - flush_buffer() - lastline = $0 - lastlinepopulated = 1 + push_line() } END { diff --git a/cdist/conf/type/__ini_value/files/parts/absent/found.awk b/cdist/conf/type/__ini_value/files/parts/absent/found.awk index 10e7675b..0f907b54 100644 --- a/cdist/conf/type/__ini_value/files/parts/absent/found.awk +++ b/cdist/conf/type/__ini_value/files/parts/absent/found.awk @@ -1,3 +1,5 @@ -# flush last line if it was not the meant comment -if(!was_comment(lastline, comment)) flush_buffer() -else lastlinepopulated = 0 +# revert line if it was a comment +if(was_comment(lastline, comment)) revert_line() + +# value line was not pushed to the buffer yet +flush_buffer() diff --git a/cdist/conf/type/__ini_value/files/parts/commented/found.awk b/cdist/conf/type/__ini_value/files/parts/commented/found.awk index 9643f9ff..934e3cc7 100644 --- a/cdist/conf/type/__ini_value/files/parts/commented/found.awk +++ b/cdist/conf/type/__ini_value/files/parts/commented/found.awk @@ -1,5 +1,5 @@ # check if last line was the comment -was_com_there = was_comment(lastline, comment) +was_com_there = was_comment(lastline(), comment) # print + comment if not there flush_buffer() diff --git a/cdist/conf/type/__ini_value/files/parts/commented/insert.awk b/cdist/conf/type/__ini_value/files/parts/commented/insert.awk index 8003942d..3064ab81 100644 --- a/cdist/conf/type/__ini_value/files/parts/commented/insert.awk +++ b/cdist/conf/type/__ini_value/files/parts/commented/insert.awk @@ -1,4 +1,4 @@ -was_com_there = was_comment(lastline, comment) +was_com_there = was_comment(lastline(), comment) # print before and comment flush_buffer() diff --git a/cdist/conf/type/__ini_value/files/parts/present/found.awk b/cdist/conf/type/__ini_value/files/parts/present/found.awk index 9673dc23..7ea4248f 100644 --- a/cdist/conf/type/__ini_value/files/parts/present/found.awk +++ b/cdist/conf/type/__ini_value/files/parts/present/found.awk @@ -1,5 +1,5 @@ # check if last line was the comment -was_com_there = was_comment(lastline, comment) +was_com_there = was_comment(lastline(), comment) # print + comment if not there flush_buffer() diff --git a/cdist/conf/type/__ini_value/files/parts/present/insert.awk b/cdist/conf/type/__ini_value/files/parts/present/insert.awk index 48dbaea8..c48186d8 100644 --- a/cdist/conf/type/__ini_value/files/parts/present/insert.awk +++ b/cdist/conf/type/__ini_value/files/parts/present/insert.awk @@ -1,4 +1,4 @@ -was_com_there = was_comment(lastline, comment) +was_com_there = was_comment(lastline(), comment) # print before and comment flush_buffer() From 72c6306ba2751f6bd94482a9a0220a85c23b0411 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Sat, 6 Mar 2021 17:46:40 +0100 Subject: [PATCH 03/16] __ini_value: add man.rst --- cdist/conf/type/__ini_value/man.rst | 127 ++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 cdist/conf/type/__ini_value/man.rst diff --git a/cdist/conf/type/__ini_value/man.rst b/cdist/conf/type/__ini_value/man.rst new file mode 100644 index 00000000..c583d5ad --- /dev/null +++ b/cdist/conf/type/__ini_value/man.rst @@ -0,0 +1,127 @@ +cdist-type__ini_value(7) +======================== + +NAME +---- +cdist-type__ini_value - Handles ini- and conf-style configuration options + + +DESCRIPTION +----------- +This cdist type allow changes to more advanced key-value based configurations. +Most commonly this would be ini- or conf-style configurations. + +The type can have following states: + + present + The line exists with the correct value. + + commented + The key-value is outcommented. + + absent + The key-value line does not exist in the given section. + + +REQUIRED PARAMETERS +------------------- +file + The file to modify. + +delimiter + The delimiter which seperates each key-value pair. + + +OPTIONAL PARAMETERS +------------------- +state + One of the states defined in the above section. Defaults to `present`. + +section + The section where the value is located at. It always need to be surrounded + by square brackets as common for ini files. If not, the section will not be + found. If no section is specified, the block before any section is meant. + +key + The key to identify the key-value pair. Must be set if the state is not + absent. + +value + The value assigned to the key. Must be set if the state is not absent. + Else, an empty value is assigned to the given key. + +comment + The comment which should be placed above the configuration line. + +indentation + The indentation the key-value pair should have. Will be applied on inserts, + but also be enforced if ``--normalize`` is set. + +comment-sign + This declares the comment signs that are valid to use in the configuration + file. Each parameter must declare a single character only; multiple + parameters are possible. It uses the first specified sign as comment + character if this type needs to insert comments. + + +BOOLEAN PARAMETERS +------------------ +normalize + This parameter enforces that the parameter is always pretty in the + configuration file. Even if a key-value pair is correct as-is, it will + correct the line to be pretty and perfect. + + +MESSAGES +-------- +The type currently fails to give a correct information of what he did cause of +the following construct. It has two `awk` scripts which do the job: + +1. The explorer script which will outputs a single state of the given + key-value. Because the current state can contain much more states than the + state that should be, one state is returned like `wrongvalue` even if + `commented` is correct, too. Therefor, it vanishes the information that the + line is commented, too, even this could be a nice information that the + messaging system could emit. + +2. The `code-remote` script also goes through the whole file and print out the + same file except the line line that should be changed. This is done because + it can not be garanteed that an other type already modifed the file, which + may moved the key-value to an other position. Then, the script replaces the + line which a pretty-printed key-value pair. + +So the detected state is not important for the remote script, as it only needs +to know that it must be run cause of differences and what the state should be. +So if there are a state like `wrongvalue`, it triggers to correction of the +line, but it do not care if it was `wrongvalue`, `wrongformat` or `commented` +which trigged the run. Because of this need, the explorer retuns only an +easy-to-use value to detect if something needs to be changed. + +Therefor, it is unable to correctly emit messages with the current base. + + +EXAMPLES +-------- + +.. code-block:: sh + + # set a value in a configuration + __ini_value fancy-id --file /etc/foo/bar.ini --section '[welcome]' \ + --key hi --value baz --delimiter ' = ' + + # outcomment a value + __ini_value foo --file /etc/bar/foo.conf --state commented \ + --key noop --value true --delimiter ' = ' --comment 'not this time!' + + +AUTHORS +------- +Matthias Stecher + + +COPYING +------- +Copyright \(C) 2021 Matthias Stecher. 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. From 3e67cdbf9b39f291d7a49c9ca18695ff0e7081d7 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Sat, 6 Mar 2021 22:09:59 +0100 Subject: [PATCH 04/16] __ini_value: add space detection on insert This detection tires to somehow inteligent places the new entry at the end of the section, but tires to not infer with existing comments for the section etc. This detection is not perfect but will work in some cases. Hope it helps (if someone whats to look at these files after they got edited). This currently only applies to the `present` state, but not to the `commented` state. This will be changed somehow when both scripts will be unifed cause of there great similarities. --- cdist/conf/type/__ini_value/files/base.awk | 18 ++++-- .../files/parts/present/insert.awk | 59 +++++++++++++++++-- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/cdist/conf/type/__ini_value/files/base.awk b/cdist/conf/type/__ini_value/files/base.awk index 51c3ba99..57535964 100644 --- a/cdist/conf/type/__ini_value/files/base.awk +++ b/cdist/conf/type/__ini_value/files/base.awk @@ -1,7 +1,7 @@ BEGIN { bufindex = -1 buflen = 0 - maxbuflen = 2 + maxbuflen = 10 # no section means the start to the first section if(section == "") { @@ -15,9 +15,13 @@ function flush_buffer() { while(buflen > 0) _pop_line() } +function flush_lines(n) { + while(buflen > 0 && n-- > 0) + _pop_line() +} function push_line() { linebuf[++bufindex] = $0 - buflen++; + buflen++ while(buflen > maxbuflen) _pop_line() } function revert_line() { @@ -41,8 +45,8 @@ function _pop_line() { function is_comment(line) { # get character and check line_sign = substr(line, 1, 1) - for(i in comment_signs) - if(line_sign == comment_signs[i]) + for(c in comment_signs) + if(line_sign == comment_signs[c]) return 1 # nothing found @@ -85,6 +89,10 @@ found {print; next} found=1 # %codeblock_insert% + + # print line as it would else only be populated below + print + next } is_curr_section = 0 } @@ -101,7 +109,7 @@ found {print; next} # check for a delimiter and a key (must be at first position due to trimming) if((idel = index(line, delimiter)) && (ikey = index(line, key)) == 1) { - # check there are only spaces between the delimiter + # check there are only spaces between the key and delimiter if(check_spaces(substr(line, ikey + length(key), idel - (length(key) + 1)))) { found = 1 diff --git a/cdist/conf/type/__ini_value/files/parts/present/insert.awk b/cdist/conf/type/__ini_value/files/parts/present/insert.awk index c48186d8..eeaa7eb8 100644 --- a/cdist/conf/type/__ini_value/files/parts/present/insert.awk +++ b/cdist/conf/type/__ini_value/files/parts/present/insert.awk @@ -1,9 +1,56 @@ -was_com_there = was_comment(lastline(), comment) +# check if there is a comment block before the section +firstline_index = bufindex - (buflen - 1) +insertpoint = -1 # the insertpoint marks the point before the insert +lastfreespace = -1 +for(i = bufindex; i >= firstline_index; i--) { + _line = trim(linebuf[i]) + if(_line == "") { + lastfreespace = i + continue + } + if(comment && was_comment(_line, comment)) { + insertpoint = i + 1 + no_insert_comment = 1 + if(lastfreespace != insertpoint) + insert_line_after = 1 + break + } + if(!is_comment(_line) || index(_line, delimiter) > 0) { + insertpoint = i + 1 + + # only insert a line before if we do not have a space around + if(lastfreespace == insertpoint) + insertpoint++ + else + insert_line_before = 1 + # check for empty line after the insert point + # use absolute boundary cause the insertpoint can be changed + if(trim(linebuf[i + 2]) != "") + insert_line_after = 1 + break + } +} + +# insert into the last free space +if(insertpoint == -1) { + if(lastfreespace != -1) { + insertpoint = lastfreespace + insert_line_before = 1 + } + else { + insertpoint = firstline_index + insert_line_after = 1 + } +} + +# print lines before +flush_lines(insertpoint - firstline_index) + # print before and comment -flush_buffer() -if(comment && !was_com_there) c_print() - -# print value + seperator line at the end +if(insert_line_before) print "" +if(comment && !no_insert_comment) c_print() v_print() -print "" +if(insert_line_after) print "" + +flush_buffer() From ea7ac72f9add4879ee34a507c479a264d8593ab4 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Sat, 6 Mar 2021 23:12:25 +0100 Subject: [PATCH 05/16] __ini_value: unify `present` + `commented` state awk scripts Because the difference between the both states is just the comment sign before it, it was now merged into one folder + symlink to avoid redundancy. To acomplish the difference, a further parser step was introduced to execute different print function based on the state (it is a bit of hard-coded but ok). --- cdist/conf/type/__ini_value/files/gen-awk.sh | 18 +++++++++++++++--- .../type/__ini_value/files/parts/commented | 1 + .../files/parts/commented/found.awk | 8 -------- .../files/parts/commented/insert.awk | 9 --------- .../__ini_value/files/parts/present/found.awk | 2 +- .../__ini_value/files/parts/present/insert.awk | 2 +- 6 files changed, 18 insertions(+), 22 deletions(-) create mode 120000 cdist/conf/type/__ini_value/files/parts/commented delete mode 100644 cdist/conf/type/__ini_value/files/parts/commented/found.awk delete mode 100644 cdist/conf/type/__ini_value/files/parts/commented/insert.awk diff --git a/cdist/conf/type/__ini_value/files/gen-awk.sh b/cdist/conf/type/__ini_value/files/gen-awk.sh index ba26672a..a73a3f7b 100755 --- a/cdist/conf/type/__ini_value/files/gen-awk.sh +++ b/cdist/conf/type/__ini_value/files/gen-awk.sh @@ -34,11 +34,23 @@ SHELL # generate the script and strip awk -v state="$state" ' + function parse(line) { + if(match(line, /^[ \t]*# %code_print%$/) > 0) { + if(state == "present") + print "v_print()" + else if(state == "commented") + print "v_print_commented()" + else + print "print \"script compile error! cdist state " state " unkown!\" > /dev/stderr" + } + else print line + } { - if(match($0, /^[ \t]*# %codeblock_([^%]+)%$/, result) > 0) { - file = (ENVIRON["__type"] "/files/parts/" state "/" result[1] ".awk") + if(match($0, /^[ \t]*# %codeblock_([^%]+)%$/) > 0) { + split($2, result, "_"); type = substr(result[2], 1, length(result[2]) - 1) + file = (ENVIRON["__type"] "/files/parts/" state "/" type ".awk") while((getline line < file) > 0) - print line + parse(line) close(file) } else print diff --git a/cdist/conf/type/__ini_value/files/parts/commented b/cdist/conf/type/__ini_value/files/parts/commented new file mode 120000 index 00000000..568612b9 --- /dev/null +++ b/cdist/conf/type/__ini_value/files/parts/commented @@ -0,0 +1 @@ +present \ No newline at end of file diff --git a/cdist/conf/type/__ini_value/files/parts/commented/found.awk b/cdist/conf/type/__ini_value/files/parts/commented/found.awk deleted file mode 100644 index 934e3cc7..00000000 --- a/cdist/conf/type/__ini_value/files/parts/commented/found.awk +++ /dev/null @@ -1,8 +0,0 @@ -# check if last line was the comment -was_com_there = was_comment(lastline(), comment) - -# print + comment if not there -flush_buffer() -if(comment && !was_com_there) c_print() - -v_print_commented() diff --git a/cdist/conf/type/__ini_value/files/parts/commented/insert.awk b/cdist/conf/type/__ini_value/files/parts/commented/insert.awk deleted file mode 100644 index 3064ab81..00000000 --- a/cdist/conf/type/__ini_value/files/parts/commented/insert.awk +++ /dev/null @@ -1,9 +0,0 @@ -was_com_there = was_comment(lastline(), comment) - -# print before and comment -flush_buffer() -if(comment && !was_com_there) c_print() - -# print value + seperator line at the end -v_print_commented() -print "" diff --git a/cdist/conf/type/__ini_value/files/parts/present/found.awk b/cdist/conf/type/__ini_value/files/parts/present/found.awk index 7ea4248f..4e456bbb 100644 --- a/cdist/conf/type/__ini_value/files/parts/present/found.awk +++ b/cdist/conf/type/__ini_value/files/parts/present/found.awk @@ -5,4 +5,4 @@ was_com_there = was_comment(lastline(), comment) flush_buffer() if(comment && !was_com_there) c_print() -v_print() +# %code_print% diff --git a/cdist/conf/type/__ini_value/files/parts/present/insert.awk b/cdist/conf/type/__ini_value/files/parts/present/insert.awk index eeaa7eb8..9cb70327 100644 --- a/cdist/conf/type/__ini_value/files/parts/present/insert.awk +++ b/cdist/conf/type/__ini_value/files/parts/present/insert.awk @@ -50,7 +50,7 @@ flush_lines(insertpoint - firstline_index) # print before and comment if(insert_line_before) print "" if(comment && !no_insert_comment) c_print() -v_print() +# %code_print% if(insert_line_after) print "" flush_buffer() From 9006994023ec45c224ef8fff223abe31f87b41f1 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Tue, 9 Mar 2021 18:42:10 +0100 Subject: [PATCH 06/16] __ini_value: fix explorer detect value as commented Because the value was not reseted on a fase positive. --- cdist/conf/type/__ini_value/explorer/state | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__ini_value/explorer/state b/cdist/conf/type/__ini_value/explorer/state index 1808d90e..5f98f869 100755 --- a/cdist/conf/type/__ini_value/explorer/state +++ b/cdist/conf/type/__ini_value/explorer/state @@ -80,6 +80,7 @@ found_section { # index 1 cause of trimmed string if((idel = index(line, delimiter)) && (ikey = index(line, key))) { + is_com=0 if(ikey > 1) { # maybe comment character or only spaces start_string = substr(line, 1, ikey - 1) @@ -90,7 +91,6 @@ found_section { # only one free-standing char or directly before the key if(RLENGTH == 1 || icom == ikey - 1) { start_sign = substr(line, RSTART, 1) - is_com=0 for(i in comment_signs) { if(start_sign == comment_signs[i]) { is_com = 1; break; From b76d8485404b6f023cd6acf7022d95459e3c3704 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Thu, 11 Mar 2021 21:50:55 +0100 Subject: [PATCH 07/16] __ini_value: add delimiter space detection This adds spaces around the delimiter to provide some flexibility than just do it in the delimiter string directly. It can be set via the parameter `--delimiter-space`. --- cdist/conf/type/__ini_value/explorer/state | 14 +++++++--- cdist/conf/type/__ini_value/files/common.awk | 26 ++++++++++--------- cdist/conf/type/__ini_value/man.rst | 8 ++++++ .../conf/type/__ini_value/parameter/optional | 1 + 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/cdist/conf/type/__ini_value/explorer/state b/cdist/conf/type/__ini_value/explorer/state index 5f98f869..e387d104 100755 --- a/cdist/conf/type/__ini_value/explorer/state +++ b/cdist/conf/type/__ini_value/explorer/state @@ -48,6 +48,7 @@ BEGIN { getline delimiter < (_param "delimiter") getline value < (_param "value") getline indentation < (_param "indentation") + getline delimiter_space < (_param "delimiter-space") do_normalization = (system("test -f " (_param "normalize")) == 0) @@ -108,10 +109,9 @@ found_section { # must only contain spaces else start_spaces = ikey - 1 } - # start_spaces set or 0 idelspace_start = ikey + length(key) - idelspace_length = idel - (idelspace_start) + idelspace_length = idel - idelspace_start # check for delimiter is only preceded with spaces if(idelspace_length == 0 || check_spaces(substr(line, idelspace_start, idelspace_length))) { found = 1 @@ -129,8 +129,16 @@ found_section { else { # check if the format is important if(do_normalization) { + if(match(found_value, /^[ \t]+/) == 1) { + found_value = substr(found_value, 1 + RLENGTH) + del_val_spacelen = RLENGTH + } + else + del_val_spacelen = 0 + # the format must exactly match, else it is incorrect - if(indentation != start_spaces || idelspace_length != 0 || found_value != is_value) + if(start_spaces != indentation || found_value != is_value || + idelspace_length != delimiter_space || del_val_spacelen != delimiter_space) state("wrongformat") } diff --git a/cdist/conf/type/__ini_value/files/common.awk b/cdist/conf/type/__ini_value/files/common.awk index 8874f0b8..7611638c 100644 --- a/cdist/conf/type/__ini_value/files/common.awk +++ b/cdist/conf/type/__ini_value/files/common.awk @@ -6,9 +6,14 @@ BEGIN { value = get_param_string("value") comment = get_param_string("comment") indentation = get_param_string("indentation") + delimiter_space = get_param_string("delimiter-space") get_param_array("comment-sign", comment_signs) comment_sign = comment_signs[0] + + base_spaces = spaces(indentation) + delimiter_spaces = spaces(delimiter_space + delimiter_w_spaces = (delimiter_spaces delimiter delimiter_spaces) } function trim(var) { @@ -16,6 +21,12 @@ function trim(var) { sub(/[ \t]*$/, "", var) return var } +function spaces(a) { + rspaces = "" + for(b = 0; b < a; b++) + rspaces = (rspaces " ") + return rspaces +} function check_spaces(part) { return match(part, /^[ \t]*$/) == 1 } @@ -40,22 +51,13 @@ function get_param_array(name, arr) { # print value function v_print() { - spaces = "" - for(i = 0; i < indentation; i++) - spaces = (spaces " ") - printf "%s%s%s%s%s", spaces, key, delimiter, value, ORS + printf "%s%s%s%s%s", base_spaces, key, delimiter_w_spaces, value, ORS } # print commented value function v_print_commented() { - spaces = "" - for(i = 0; i < indentation; i++) - spaces = (spaces " ") - printf "%s%s%s%s%s%s", spaces, comment_sign, key, delimiter, value, ORS + printf "%s%s%s%s%s%s", base_spaces, comment_sign, key, delimiter_w_spaces, value, ORS } # print comment function c_print() { - spaces = "" - for(i = 0; i < indentation; i++) - spaces = (spaces " ") - printf "%s%s%s%s%s", spaces, comment_sign, " ", comment, ORS + printf "%s%s%s%s%s", base_spaces, comment_sign, " ", comment, ORS } diff --git a/cdist/conf/type/__ini_value/man.rst b/cdist/conf/type/__ini_value/man.rst index c583d5ad..0812d432 100644 --- a/cdist/conf/type/__ini_value/man.rst +++ b/cdist/conf/type/__ini_value/man.rst @@ -63,6 +63,14 @@ comment-sign parameters are possible. It uses the first specified sign as comment character if this type needs to insert comments. +delimiter-space + The number of spaces before and after the delimiter which should be free. + This number applies to each site of the delimiter separately, so one space + means one space to the left and right side of the delimiter. + + The delimiter will be matched independendtly of this parameter and will + only be corrected if ``--normalize`` is set. + BOOLEAN PARAMETERS ------------------ diff --git a/cdist/conf/type/__ini_value/parameter/optional b/cdist/conf/type/__ini_value/parameter/optional index 031c807b..6acbf8e5 100644 --- a/cdist/conf/type/__ini_value/parameter/optional +++ b/cdist/conf/type/__ini_value/parameter/optional @@ -4,3 +4,4 @@ state value indentation comment +delimiter-space From 7380fcaaf96b047e6358e6a183e76138c33d42df Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Sat, 13 Mar 2021 18:46:04 +0100 Subject: [PATCH 08/16] __ini_value: add missing bracket (oops) --- cdist/conf/type/__ini_value/files/common.awk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__ini_value/files/common.awk b/cdist/conf/type/__ini_value/files/common.awk index 7611638c..c8505b40 100644 --- a/cdist/conf/type/__ini_value/files/common.awk +++ b/cdist/conf/type/__ini_value/files/common.awk @@ -12,7 +12,7 @@ BEGIN { comment_sign = comment_signs[0] base_spaces = spaces(indentation) - delimiter_spaces = spaces(delimiter_space + delimiter_spaces = spaces(delimiter_space) delimiter_w_spaces = (delimiter_spaces delimiter delimiter_spaces) } From e3e4a91abe526d681e2c0d1abc67fdd3281eae36 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Sun, 14 Mar 2021 12:28:55 +0100 Subject: [PATCH 09/16] __ini_value: moved awk script generation to gencode-remote The script generation of the awk script was moved from `files/gen-awk.sh` to `gencode-remote` because the size not really matters. If the file does not exist, it will be created by a predefined template via an here-doc to avoid a big awk-script where it is not needed. --- cdist/conf/type/__ini_value/files/gen-awk.sh | 65 ----------- cdist/conf/type/__ini_value/gencode-remote | 110 ++++++++++++++++++- 2 files changed, 108 insertions(+), 67 deletions(-) delete mode 100755 cdist/conf/type/__ini_value/files/gen-awk.sh diff --git a/cdist/conf/type/__ini_value/files/gen-awk.sh b/cdist/conf/type/__ini_value/files/gen-awk.sh deleted file mode 100755 index a73a3f7b..00000000 --- a/cdist/conf/type/__ini_value/files/gen-awk.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/sh -e -# __ini_value/files/gen-awk.sh - -# Generates the awk script that will modify the line -# -# Arguments: -# 1: the file to modify -# 2: the should_state - -strip_comments() { - grep -v '^[[:space:]]*\($\|#\)' -} - - -file="$1" -state="$2" - - -# Generate the basic awk struct -cat < "\$tmpfile" <<'AWK' -SHELL - - -# generate the awk script and strip unnecessary things -{ - # basic functions which everyone needs - cat "$__type/files/common.awk" - - # generate the script and strip - awk -v state="$state" ' - function parse(line) { - if(match(line, /^[ \t]*# %code_print%$/) > 0) { - if(state == "present") - print "v_print()" - else if(state == "commented") - print "v_print_commented()" - else - print "print \"script compile error! cdist state " state " unkown!\" > /dev/stderr" - } - else print line - } - { - if(match($0, /^[ \t]*# %codeblock_([^%]+)%$/) > 0) { - split($2, result, "_"); type = substr(result[2], 1, length(result[2]) - 1) - file = (ENVIRON["__type"] "/files/parts/" state "/" type ".awk") - while((getline line < file) > 0) - parse(line) - close(file) - } - else print - }' "$__type/files/base.awk" -} | strip_comments - - -# end of here-doc -cat < "\$tmpfile" <<'AWK' +SHELL + + # generate the awk script and strip unnecessary things + { + # basic functions which everyone needs + cat "$__type/files/common.awk" + + # generate the script + awk -v state="$state_should" ' + function parse(line) { + if(match(line, /^[ \t]*# %code_print%$/) > 0) { + if(state == "present") + print "v_print()" + else if(state == "commented") + print "v_print_commented()" + else + print "print \"script compile error! cdist state " state " unkown!\" > /dev/stderr" + } + else print line + } + { + if(match($0, /^[ \t]*# %codeblock_([^%]+)%$/) > 0) { + split($2, result, "_"); type = substr(result[2], 1, length(result[2]) - 1) + file = (ENVIRON["__type"] "/files/parts/" state "/" type ".awk") + while((getline line < file) > 0) + parse(line) + close(file) + } + else print + }' "$__type/files/base.awk" + } | strip_comments + + # end of here-doc + cat < '%s'\n" "$file" + printf "%s cdist-generated file by %s/%s\n" "$comment_sign" \ + "${__type##*/}" "$__object_id" + echo + + # print values if available + section="$__object/parameter/section" + if [ -f "$section" ]; then + cat "$section" + echo + fi + comment="$__object/parameter/comment" + if [ -f "$comment" ]; then + printf "%s%s " "$i_indent" "$comment_sign" + cat "$comment" + fi + + # print the value + printf "%s%s%s%s%s%s%s\n" \ + "$i_indent" \ + "$(if [ "$state_should" = "commented" ]; then + printf "%s" "$comment_sign"; + fi)" \ + "$key" "$i_del_space" "$delimiter" "$i_del_space" "$value" + echo + + # terminate HERE-DOC + echo "FILE" + fi ;; *) From 8f687e5ce2e8ede46149be754f1a809c6a850c6c Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Sun, 14 Mar 2021 14:50:21 +0100 Subject: [PATCH 10/16] __ini_value: make shellcheck happy --- cdist/conf/type/__ini_value/gencode-remote | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__ini_value/gencode-remote b/cdist/conf/type/__ini_value/gencode-remote index d110d2a9..dc6a0431 100755 --- a/cdist/conf/type/__ini_value/gencode-remote +++ b/cdist/conf/type/__ini_value/gencode-remote @@ -75,8 +75,8 @@ SHELL elif [ "$state_should" != "absent" ]; then # generate the indentation string spaces() { - _i=$1 - while [ $_i -gt 0 ]; do + _i="$1" + while [ "$_i" -gt 0 ]; do printf " " _i=$((_i - 1)) done @@ -88,10 +88,10 @@ SHELL delimiter="$(cat "$__object/parameter/delimiter")" value="$(cat "$__object/parameter/value")" indentation="$(cat "$__object/parameter/indentation" || true)" - i_indent="$(spaces $indentation)" + i_indent="$(spaces "$indentation")" delimiter_space="$(cat "$__object/parameter/delimiter-space" || true)" - i_del_space="$(spaces $delimiter_space)" - comment_sign="$(cat "$__object/parameter/comment-sign" | cut -c1)" + i_del_space="$(spaces "$delimiter_space")" + comment_sign="$(cut -c1 < "$__object/parameter/comment-sign")" # Generate a simple shell script which just generates the file printf "cat <<'FILE' > '%s'\n" "$file" From ad736a66d055fc09b476a994e61dbe6fe10fff59 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Tue, 16 Mar 2021 21:38:08 +0100 Subject: [PATCH 11/16] __ini_value: remove is_state 'nosuchfile' Because the state 'nosuchfile' is exactly the same as 'absent', it was removed with the code connected to it. It's not important if the file exists or not - because in both cases, it contains no key-value. Also, the code if the explorer returned 'nosuchfile' was wrong: Completly overwrite the file with the assumption the file does not exist is not correct, as it can return for multiple objects of the same file and therefore, they overwrite themself. --- cdist/conf/type/__ini_value/explorer/state | 2 +- cdist/conf/type/__ini_value/gencode-remote | 118 ++++++--------------- 2 files changed, 35 insertions(+), 85 deletions(-) diff --git a/cdist/conf/type/__ini_value/explorer/state b/cdist/conf/type/__ini_value/explorer/state index e387d104..3827a354 100755 --- a/cdist/conf/type/__ini_value/explorer/state +++ b/cdist/conf/type/__ini_value/explorer/state @@ -21,7 +21,7 @@ file="$(cat "$__object/parameter/file")" # abort if no file exist if ! [ -f "$file" ]; then - echo nosuchfile + echo absent exit fi diff --git a/cdist/conf/type/__ini_value/gencode-remote b/cdist/conf/type/__ini_value/gencode-remote index dc6a0431..ab93077e 100755 --- a/cdist/conf/type/__ini_value/gencode-remote +++ b/cdist/conf/type/__ini_value/gencode-remote @@ -24,9 +24,8 @@ file="$(cat "$__object/parameter/file")" # validation check case "$state_should" in present|commented|absent) - if [ "$state_is" != "nosuchfile" ]; then - # Generate the basic awk struct if a file already exists - cat < "\$tmpfile" <<'AWK' SHELL - # generate the awk script and strip unnecessary things - { - # basic functions which everyone needs - cat "$__type/files/common.awk" + # generate the awk script and strip unnecessary things + { + # basic functions which everyone needs + cat "$__type/files/common.awk" - # generate the script - awk -v state="$state_should" ' - function parse(line) { - if(match(line, /^[ \t]*# %code_print%$/) > 0) { - if(state == "present") - print "v_print()" - else if(state == "commented") - print "v_print_commented()" - else - print "print \"script compile error! cdist state " state " unkown!\" > /dev/stderr" - } - else print line + # generate the script + awk -v state="$state_should" ' + function parse(line) { + if(match(line, /^[ \t]*# %code_print%$/) > 0) { + if(state == "present") + print "v_print()" + else if(state == "commented") + print "v_print_commented()" + else + print "print \"script compile error! cdist state " state " unkown!\" > /dev/stderr" } - { - if(match($0, /^[ \t]*# %codeblock_([^%]+)%$/) > 0) { - split($2, result, "_"); type = substr(result[2], 1, length(result[2]) - 1) - file = (ENVIRON["__type"] "/files/parts/" state "/" type ".awk") - while((getline line < file) > 0) - parse(line) - close(file) - } - else print - }' "$__type/files/base.awk" - } | strip_comments + else print line + } + { + if(match($0, /^[ \t]*# %codeblock_([^%]+)%$/) > 0) { + split($2, result, "_"); type = substr(result[2], 1, length(result[2]) - 1) + file = (ENVIRON["__type"] "/files/parts/" state "/" type ".awk") + while((getline line < file) > 0) + parse(line) + close(file) + } + else print + }' "$__type/files/base.awk" + } | strip_comments - # end of here-doc - cat < '%s'\n" "$file" - printf "%s cdist-generated file by %s/%s\n" "$comment_sign" \ - "${__type##*/}" "$__object_id" - echo - - # print values if available - section="$__object/parameter/section" - if [ -f "$section" ]; then - cat "$section" - echo - fi - comment="$__object/parameter/comment" - if [ -f "$comment" ]; then - printf "%s%s " "$i_indent" "$comment_sign" - cat "$comment" - fi - - # print the value - printf "%s%s%s%s%s%s%s\n" \ - "$i_indent" \ - "$(if [ "$state_should" = "commented" ]; then - printf "%s" "$comment_sign"; - fi)" \ - "$key" "$i_del_space" "$delimiter" "$i_del_space" "$value" - echo - - # terminate HERE-DOC - echo "FILE" - fi + # Do not threat it differently if the file does not exist. It's just + # absent. Because multiple explorers can say the file does not exist, + # so the file should not be completly overwritten all times. ;; *) From 46638f0839cff327b00c914fe3d626d8e16791f6 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Wed, 17 Mar 2021 18:17:21 +0100 Subject: [PATCH 12/16] __ini_value: change empty value check Change the short-circuit check for an empty value to a more structual approach. This might be better for the code or not .. --- cdist/conf/type/__ini_value/files/base.awk | 79 +++++++++++----------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/cdist/conf/type/__ini_value/files/base.awk b/cdist/conf/type/__ini_value/files/base.awk index 57535964..ddc52949 100644 --- a/cdist/conf/type/__ini_value/files/base.awk +++ b/cdist/conf/type/__ini_value/files/base.awk @@ -66,56 +66,53 @@ found {print; next} # main loop (til the line was found) !found { line = trim($0) - # short curcit on empty lines - if(line == "") { - push_line() - next - } + # process if the line is not empty (or only contains spaces) + if(line != "") { + # check for a ini section + if(substr(line, 1, 1) == "[" && substr(line, length(line), 1) == "]") { + is_section = 1 + curr_section = line - # check for a ini section - if(substr(line, 1, 1) == "[" && substr(line, length(line), 1) == "]") { - is_section = 1 - curr_section = line + if(curr_section == section) { + found_section = 1 + is_curr_section = 1 + } + else { + # if nothing found, print it in the valid section before the next one + if(is_curr_section) { + if(!found) { + # set found as it is there now + found=1 - if(curr_section == section) { - found_section = 1 - is_curr_section = 1 + # %codeblock_insert% + + # print line as it would else only be populated below + print + next + } + is_curr_section = 0 + } + } } else { - # if nothing found, print it in the valid section before the next one + # only current session is interessting if(is_curr_section) { - if(!found) { - # set found as it is there now - found=1 - - # %codeblock_insert% - - # print line as it would else only be populated below - print - next + # check for a comment + is_com = is_comment(line) + if(is_com) { + line = trim(substr(line, 2)) } - is_curr_section = 0 - } - } - } - else { - # only current session is interessting - if(is_curr_section) { - # check for a comment - is_com = is_comment(line) - if(is_com) { - line = trim(substr(line, 2)) - } - # check for a delimiter and a key (must be at first position due to trimming) - if((idel = index(line, delimiter)) && (ikey = index(line, key)) == 1) { - # check there are only spaces between the key and delimiter - if(check_spaces(substr(line, ikey + length(key), idel - (length(key) + 1)))) { - found = 1 + # check for a delimiter and a key (must be at first position due to trimming) + if((idel = index(line, delimiter)) && (ikey = index(line, key)) == 1) { + # check there are only spaces between the key and delimiter + if(check_spaces(substr(line, ikey + length(key), idel - (length(key) + 1)))) { + found = 1 - # %codeblock_found% + # %codeblock_found% - next + next + } } } } From 19c701e95dcbc60938cd554532d9503eb71605ec Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Sat, 20 Mar 2021 15:10:11 +0100 Subject: [PATCH 13/16] __ini_value: make type nonparallel Because of the temporary files and because multiple types can change a file at the same time, it can't be run in parallel. --- cdist/conf/type/__ini_value/nonparallel | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 cdist/conf/type/__ini_value/nonparallel diff --git a/cdist/conf/type/__ini_value/nonparallel b/cdist/conf/type/__ini_value/nonparallel new file mode 100644 index 00000000..e69de29b From 0d4868dcd52c5c172c680bcf5aa42b3da16c7611 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Sat, 20 Mar 2021 15:39:38 +0100 Subject: [PATCH 14/16] __ini_value: new parameter --quote This parameter ensures the value is surrounded by double quotes. As it directly edits the value variable, the quoting will be added/removed automaticly. --- cdist/conf/type/__ini_value/explorer/state | 5 +++++ cdist/conf/type/__ini_value/files/common.awk | 7 ++++++- cdist/conf/type/__ini_value/man.rst | 4 ++++ cdist/conf/type/__ini_value/parameter/boolean | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__ini_value/explorer/state b/cdist/conf/type/__ini_value/explorer/state index 3827a354..507cabe9 100755 --- a/cdist/conf/type/__ini_value/explorer/state +++ b/cdist/conf/type/__ini_value/explorer/state @@ -57,6 +57,11 @@ BEGIN { comment_signs[i++] = tmp } + if(system("test -f " (_param "quote")) == 0) { + # quote it now that it only wins checks against quoted values + value = ("\"" value "\"") + } + found=0 curr_section="" if(section == "") diff --git a/cdist/conf/type/__ini_value/files/common.awk b/cdist/conf/type/__ini_value/files/common.awk index c8505b40..e5f3594c 100644 --- a/cdist/conf/type/__ini_value/files/common.awk +++ b/cdist/conf/type/__ini_value/files/common.awk @@ -11,6 +11,11 @@ BEGIN { get_param_array("comment-sign", comment_signs) comment_sign = comment_signs[0] + if(system("test -f " (_param "quote")) == 0) { + # quote it now that it only wins checks against quoted values + value = ("\"" value "\"") + } + base_spaces = spaces(indentation) delimiter_spaces = spaces(delimiter_space) delimiter_w_spaces = (delimiter_spaces delimiter delimiter_spaces) @@ -59,5 +64,5 @@ function v_print_commented() { } # print comment function c_print() { - printf "%s%s%s%s%s", base_spaces, comment_sign, " ", comment, ORS + printf "%s%s %s%s", base_spaces, comment_sign, comment, ORS } diff --git a/cdist/conf/type/__ini_value/man.rst b/cdist/conf/type/__ini_value/man.rst index 0812d432..38a8d67c 100644 --- a/cdist/conf/type/__ini_value/man.rst +++ b/cdist/conf/type/__ini_value/man.rst @@ -79,6 +79,10 @@ normalize configuration file. Even if a key-value pair is correct as-is, it will correct the line to be pretty and perfect. +quote + Wrap double quotes (``"``) around the value. If the value is previously + unquoted, the file will be modified to quote the value. + MESSAGES -------- diff --git a/cdist/conf/type/__ini_value/parameter/boolean b/cdist/conf/type/__ini_value/parameter/boolean index f9a8b6aa..5b7d2b39 100644 --- a/cdist/conf/type/__ini_value/parameter/boolean +++ b/cdist/conf/type/__ini_value/parameter/boolean @@ -1 +1,2 @@ normalize +quote From 122354a0dcc071b0b21eea644b37a988383aaec7 Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Wed, 29 Sep 2021 20:23:01 +0200 Subject: [PATCH 15/16] __ini_value: draft of comment handling work in progress for a long time and I didn't touched it again till just to commit it ... I have to work on it. --- cdist/conf/type/__ini_value/files/comment.awk | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 cdist/conf/type/__ini_value/files/comment.awk diff --git a/cdist/conf/type/__ini_value/files/comment.awk b/cdist/conf/type/__ini_value/files/comment.awk new file mode 100644 index 00000000..1d3c04b7 --- /dev/null +++ b/cdist/conf/type/__ini_value/files/comment.awk @@ -0,0 +1,57 @@ +# We try to find a comment block -- how? +# check how much paragraphs it has +# check if +# +# this code is crap - at least not well written + +# Check the buffer if the comment was found +function check_comments() { + _lastline = bufindex - (buflen - 1) + _comm_size = length(comments) + + lastfreeline = 0 + lastfreecommline = 0 + comm_index = 0 + + # go through all lines + for(i = bufindex; i < _lastline; i++) { + _line = trim(linebuf[i]) + + # empty line? + if(_line == "") { + lastfreeline = i + continue + } + + # line start matched + if(_line == trim(comments[comm_index])) { + # end? else continue + if(comm_index < _comm_size) { + continue + } + else { + + } + } + # reset again cause not matched + else comm_index = 0 + + # empty comment line + if(is_comment(_line)) { + _comment = trim(substr(_line, 2)) + + # check if empty comment + if(_comment == "") { + lastfreecommline = i + } + } + + # check if comments fit in or is too big + if((_lastline - bufindex) < _comm_size) { + # too short + } + else { + #if() + } + } +} From b4f381ed4ca5fc8d012765ac3af50c79ac63692c Mon Sep 17 00:00:00 2001 From: Matthias Stecher Date: Wed, 29 Sep 2021 20:24:22 +0200 Subject: [PATCH 16/16] __ini_value: fix use of removed constant _param was removed in preference of the param functions. --- cdist/conf/type/__ini_value/files/common.awk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__ini_value/files/common.awk b/cdist/conf/type/__ini_value/files/common.awk index e5f3594c..bc51e0b8 100644 --- a/cdist/conf/type/__ini_value/files/common.awk +++ b/cdist/conf/type/__ini_value/files/common.awk @@ -11,7 +11,7 @@ BEGIN { get_param_array("comment-sign", comment_signs) comment_sign = comment_signs[0] - if(system("test -f " (_param "quote")) == 0) { + if(system("test -f " (ENVIRON["__object"] "/parameter/quote")) == 0) { # quote it now that it only wins checks against quoted values value = ("\"" value "\"") }