Merge pull request #663 from asteven/type/__line

RFC: rewrite __line type for --before and --after support
This commit is contained in:
Darko Poljak 2018-06-16 10:51:33 +02:00 committed by GitHub
commit f75af95bda
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 228 additions and 116 deletions

View file

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh -e
# #
# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) # 2018 Steven Armstrong (steven-cdist at armstrong.cc)
# #
# This file is part of cdist. # This file is part of cdist.
# #
@ -17,26 +17,74 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>. # along with cdist. If not, see <http://www.gnu.org/licenses/>.
# #
#
file="/$__object_id" if [ -f "$__object/parameter/before" ]; then
[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file") position="before"
elif [ -f "$__object/parameter/after" ]; then
position="after"
else
# By default we append to the end of the file.
position="end"
fi
if [ -f "$__object/parameter/regex" ]; then if [ -f "$__object/parameter/regex" ]; then
regex=$(cat "$__object/parameter/regex") needle="regex"
greparg=""
else else
if [ ! -f "$__object/parameter/line" ]; then needle="line"
echo "Parameter line and regex missing - cannot explore" >&2
exit 1
fi
regex="$(cat "$__object/parameter/line")"
greparg="-F -x"
fi fi
# Allow missing file - thus 2>/dev/null if [ -f "$__object/parameter/file" ]; then
if grep -q $greparg -- "$regex" "$file" 2>/dev/null; then file="$(cat "$__object/parameter/file")"
echo present
else else
echo absent file="/$__object_id"
fi fi
awk -v position="$position" -v needle="$needle" '
function _find(_text, _pattern) {
if (needle == "regex") {
return match(_text, _pattern)
} else {
return index(_text, _pattern)
}
}
BEGIN {
getline anchor < (ENVIRON["__object"] "/parameter/" position)
getline pattern < (ENVIRON["__object"] "/parameter/" needle)
state = "absent"
}
{
if (position == "after") {
if (match($0, anchor)) {
getline
if (_find($0, pattern)) {
state = "present"
}
else {
state = "wrongposition"
}
exit 0
}
}
else if (position == "before") {
if (_find($0, pattern)) {
getline
if (match($0, anchor)) {
state = "present"
}
else {
state = "wrongposition"
}
exit 0
}
}
else {
if (_find($0, pattern)) {
state = "present"
exit 0
}
}
}
END {
print state
}
' "$file"

View file

@ -1,7 +1,6 @@
#!/bin/sh -e #!/bin/sh -e
# #
# 2012 Nico Schottelius (nico-cdist at schottelius.org) # 2018 Steven Armstrong (steven-cdist at armstrong.cc)
# 2014 Steven Armstrong (steven-cdist at armstrong.cc)
# #
# This file is part of cdist. # This file is part of cdist.
# #
@ -18,76 +17,108 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>. # along with cdist. If not, see <http://www.gnu.org/licenses/>.
# #
#
file="/$__object_id" if [ -f "$__object/parameter/before" -a -f "$__object/parameter/after" ]; then
regex="" echo "Use either --before OR --after but not both." >&2
state_should="present" exit 1
[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file") fi
[ -f "$__object/parameter/regex" ] && regex=$(cat "$__object/parameter/regex")
[ -f "$__object/parameter/state" ] && state_should=$(cat "$__object/parameter/state")
[ -f "$__object/parameter/line" ] && line=$(cat "$__object/parameter/line")
state_should="$(cat "$__object/parameter/state")"
state_is="$(cat "$__object/explorer/state")" state_is="$(cat "$__object/explorer/state")"
[ "$state_should" = "$state_is" ] && exit 0 if [ "$state_should" = "$state_is" ]; then
# nothing to do
exit 0
fi
if [ -f "$__object/parameter/before" ]; then
position="before"
elif [ -f "$__object/parameter/after" ]; then
position="after"
else
# By default we append to the end of the file.
position="end"
fi
if [ -f "$__object/parameter/regex" ]; then
needle="regex"
else
needle="line"
fi
if [ -f "$__object/parameter/file" ]; then
file="$(cat "$__object/parameter/file")"
else
file="/$__object_id"
fi
add=0
remove=0
case "$state_should" in case "$state_should" in
present) present)
if [ ! "$line" ]; then if [ "$state_is" = "wrongposition" ]; then
echo "Required parameter \"line\" is missing" >&2 echo updated >> "$__messages_out"
exit 1 remove=1
fi else
echo added >> "$__messages_out"
fi
add=1
;;
absent)
echo removed >> "$__messages_out"
remove=1
;;
esac
#echo "echo \"$line\" >> $file" cat << DONE
#line_sanitised=$(cat "$__object/parameter/line" | sed 's/"/\"/g')
# Idea: replace ' in the string:
# '"'"'
# |------> ': end the string
# |-|---> "'": create ' in the output string
# |--> ': continue the string
#
# Replace all \ so \t and other combinations are not interpreted
#
# line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g" -e 's/\\/\\\\/g')
# The one above does not work:
# --line "PS1='[\t] \[\033[1m\]\h\[\033[0m\]:\w\\$ '"
# becomes
# PS1='[\\t] \\[\\033[1m\\]\\h\\[\\033[0m\\]:\\w\\$ '
# Only replace ' with '"'"' and keep \ as they are
line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g")
printf '%s' "printf '%s\n' '$line_sanitised' >> $file"
echo "added" >> "$__messages_out"
;;
absent)
if [ "$regex" -a "$line" ]; then
echo "Mutally exclusive parameters regex and line given for state absent" >&2
exit 1
fi
greparg=""
if [ "$line" ]; then
regex="$line"
greparg="-F -x"
fi
cat << eof
tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX)
# preserve ownership and permissions of existing file # preserve ownership and permissions of existing file
if [ -f "$file" ]; then if [ -f "$file" ]; then
cp -p "$file" "\$tmpfile" cp -p "$file" "\$tmpfile"
fi fi
grep -v $greparg "$regex" '$file' > \$tmpfile || true
awk -v position="$position" -v needle="$needle" -v remove=$remove -v add=$add '
function _find(_text, _pattern) {
if (needle == "regex") {
return match(_text, _pattern)
} else {
return index(_text, _pattern)
}
}
BEGIN {
line_file = ENVIRON["__object"] "/parameter/line"
getline line < line_file
# Need to close line file as it may be re-read as pattern below.
close(line_file)
getline pattern < (ENVIRON["__object"] "/parameter/" needle)
getline anchor < (ENVIRON["__object"] "/parameter/" position)
}
{
if (remove) {
if (_find(\$0, pattern)) {
# skip over this line -> remove it
next
}
}
if (add) {
if (anchor && match(\$0, anchor)) {
if (position == "before") {
print line
print
} else if (position == "after") {
print
print line
}
next
}
}
print
}
END {
if (add && position == "end") {
print line
}
}
' "$file" > "\$tmpfile"
mv -f "\$tmpfile" "$file" mv -f "\$tmpfile" "$file"
eof DONE
echo "removed" >> "$__messages_out"
;;
*)
echo "Unknown state: $state_should" >&2
exit 1
;;
esac

View file

@ -13,72 +13,102 @@ This cdist type allows you to add lines and remove lines from files.
REQUIRED PARAMETERS REQUIRED PARAMETERS
------------------- -------------------
None.
OPTIONAL PARAMETERS OPTIONAL PARAMETERS
------------------- -------------------
state after
'present' or 'absent', defaults to 'present' Insert the given line after this pattern.
line before
Specifies the line which should be absent or present Insert the given line before this pattern.
Must be present, if state is present.
Must not be combined with regex, if state is absent.
regex
If state is present, search for this pattern and add
given line, if the given regular expression does not match.
In case of absent, ensure all lines matching the
regular expression are absent.
The regular expression is interpreted by grep.
Must not be combined with line, if state is absent.
file file
If supplied, use this as the destination file. If supplied, use this as the destination file.
Otherwise the object_id is used. Otherwise the object_id is used.
line
Specifies the line which should be absent or present.
Must be present, if state is 'present'.
Ignored if regex is given and state is 'absent'.
regex
If state is 'present', search for this pattern and if it matches add
the given line.
If state is 'absent', ensure all lines matching the regular expression
are absent.
The regular expression is interpreted by awk's match function.
state
'present' or 'absent', defaults to 'present'
BOOLEAN PARAMETERS
------------------
None.
MESSAGES MESSAGES
-------- --------
added added
The line was added. The line was added.
updated
The line or its position was changed.
removed removed
The line was removed. The line was removed.
EXAMPLES EXAMPLES
-------- --------
.. code-block:: sh .. code-block:: sh
# Manage the DAEMONS line in rc.conf # Manage a hosts entry for www.example.com.
__line daemons --file /etc/rc.conf --line 'DAEMONS=(hwclock !network sshd crond postfix)' __line /etc/hosts \
--line '127.0.0.2 www.example.com'
# Ensure the home mount is present in /etc/fstab - explicitly make it present # Manage another hosts entry for test.example.com.
__line home-fstab \ __line hosts:test.example.com \
--file /etc/fstab \ --file /etc/hosts \
--line 'filer.fs:/vol/home /home nfs defaults 0 0' \ --line '127.0.0.3 test.example.com'
--state present
# Removes the line specifiend in "include_www" from the file "lighttpd.conf" # Remove the line starting with TIMEZONE from the /etc/rc.conf file.
__line legacy_timezone --file /etc/rc.conf --regex 'TIMEZONE=.*' --state absent __line legacy_timezone \
--file /etc/rc.conf \
--regex 'TIMEZONE=.*' \
--state absent
# Insert a line before another one.
__line password-auth-local:classify \
--file /etc/pam.d/password-auth-local \
--line '-session required pam_exec.so debug log=/tmp/classify.log /usr/local/libexec/classify' \
--before '^session[[:space:]]+include[[:space:]]+password-auth-ac$'
# Insert a line after another one.
__line password-auth-local:classify \
--file /etc/pam.d/password-auth-local \
--line '-session required pam_exec.so debug log=/tmp/classify.log /usr/local/libexec/classify' \
--after '^session[[:space:]]+include[[:space:]]+password-auth-ac$'
SEE ALSO SEE ALSO
-------- --------
:strong:`grep`\ (1) :strong:`cdist-type`\ (7)
AUTHORS AUTHORS
------- -------
Nico Schottelius <nico-cdist--@--schottelius.org> Steven Armstrong <steven-cdist--@--armstrong.cc>
COPYING COPYING
------- -------
Copyright \(C) 2012-2013 Nico Schottelius. You can redistribute it Copyright \(C) 2018 Steven Armstrong. Free use of this software is
and/or modify it under the terms of the GNU General Public License as granted under the terms of the GNU General Public License version 3 (GPLv3).
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

View file

@ -0,0 +1 @@
present

View file

@ -1,4 +1,6 @@
state after
regex before
file file
line line
regex
state