__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.
This commit is contained in:
matze 2021-03-05 20:38:19 +01:00
parent 22f637c15b
commit 8c7a6906de
17 changed files with 471 additions and 0 deletions

View File

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

View File

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

View File

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

View File

@ -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 <<SHELL
tmpfile="\$(mktemp '${file}.cdist.XXXXXXXX')"
if [ -f '$file' ]; then
cp -p '$file' "\$tmpfile"
fi
awk -f - '$file' > "\$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 <<SHELL
AWK
mv -f "\$tmpfile" '$file'
SHELL

View File

@ -0,0 +1,3 @@
# flush last line if it was not the meant comment
if(!was_comment(lastline, comment)) flush_buffer()
else lastlinepopulated = 0

View File

@ -0,0 +1,8 @@
# 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()

View File

@ -0,0 +1,9 @@
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 ""

View File

@ -0,0 +1,8 @@
# 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()

View File

@ -0,0 +1,9 @@
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()
print ""

View File

@ -0,0 +1,26 @@
#!/bin/sh -e
# __ini_value/gencode-remote
state_is="$(cat "$__object/explorer/state")"
state_should="$(cat "$__object/parameter/state")"
# short-circuit if nothing to do
if [ "$state_is" = "$state_should" ]; then exit; fi
# file to change
file="$(cat "$__object/parameter/file")"
# validation check
case "$state_should" in
present|commented|absent)
# FIXME no need for a seperate file?
"$__type/files/gen-awk.sh" "$file" "$state_should"
;;
*)
echo "not done yet!" >&2
exit 1
;;
esac

View File

@ -0,0 +1 @@
normalize

View File

@ -0,0 +1,2 @@
;
#

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1 @@
present

View File

@ -0,0 +1,6 @@
section
key
state
value
indentation
comment

View File

@ -0,0 +1 @@
comment-sign

View File

@ -0,0 +1,2 @@
file
delimiter