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.
#
@ -17,26 +17,74 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
file="/$__object_id"
[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file")
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
regex=$(cat "$__object/parameter/regex")
greparg=""
needle="regex"
else
if [ ! -f "$__object/parameter/line" ]; then
echo "Parameter line and regex missing - cannot explore" >&2
exit 1
fi
regex="$(cat "$__object/parameter/line")"
greparg="-F -x"
needle="line"
fi
# Allow missing file - thus 2>/dev/null
if grep -q $greparg -- "$regex" "$file" 2>/dev/null; then
echo present
if [ -f "$__object/parameter/file" ]; then
file="$(cat "$__object/parameter/file")"
else
echo absent
file="/$__object_id"
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
#
# 2012 Nico Schottelius (nico-cdist at schottelius.org)
# 2014 Steven Armstrong (steven-cdist at armstrong.cc)
# 2018 Steven Armstrong (steven-cdist at armstrong.cc)
#
# This file is part of cdist.
#
@ -18,76 +17,108 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
file="/$__object_id"
regex=""
state_should="present"
[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file")
[ -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")
if [ -f "$__object/parameter/before" -a -f "$__object/parameter/after" ]; then
echo "Use either --before OR --after but not both." >&2
exit 1
fi
state_should="$(cat "$__object/parameter/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
present)
if [ ! "$line" ]; then
echo "Required parameter \"line\" is missing" >&2
exit 1
fi
present)
if [ "$state_is" = "wrongposition" ]; then
echo updated >> "$__messages_out"
remove=1
else
echo added >> "$__messages_out"
fi
add=1
;;
absent)
echo removed >> "$__messages_out"
remove=1
;;
esac
#echo "echo \"$line\" >> $file"
#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
cat << DONE
tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX)
# preserve ownership and permissions of existing file
if [ -f "$file" ]; then
cp -p "$file" "\$tmpfile"
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"
eof
echo "removed" >> "$__messages_out"
;;
*)
echo "Unknown state: $state_should" >&2
exit 1
;;
esac
DONE

View file

@ -13,72 +13,102 @@ This cdist type allows you to add lines and remove lines from files.
REQUIRED PARAMETERS
-------------------
None.
OPTIONAL PARAMETERS
-------------------
state
'present' or 'absent', defaults to 'present'
after
Insert the given line after this pattern.
line
Specifies the line which should be absent or present
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.
before
Insert the given line before this pattern.
file
If supplied, use this as the destination file.
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
--------
added
The line was added.
The line was added.
updated
The line or its position was changed.
removed
The line was removed.
The line was removed.
EXAMPLES
--------
.. code-block:: sh
# Manage the DAEMONS line in rc.conf
__line daemons --file /etc/rc.conf --line 'DAEMONS=(hwclock !network sshd crond postfix)'
# Manage a hosts entry for www.example.com.
__line /etc/hosts \
--line '127.0.0.2 www.example.com'
# Ensure the home mount is present in /etc/fstab - explicitly make it present
__line home-fstab \
--file /etc/fstab \
--line 'filer.fs:/vol/home /home nfs defaults 0 0' \
--state present
# Manage another hosts entry for test.example.com.
__line hosts:test.example.com \
--file /etc/hosts \
--line '127.0.0.3 test.example.com'
# Removes the line specifiend in "include_www" from the file "lighttpd.conf"
__line legacy_timezone --file /etc/rc.conf --regex 'TIMEZONE=.*' --state absent
# Remove the line starting with TIMEZONE from the /etc/rc.conf file.
__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
--------
:strong:`grep`\ (1)
:strong:`cdist-type`\ (7)
AUTHORS
-------
Nico Schottelius <nico-cdist--@--schottelius.org>
Steven Armstrong <steven-cdist--@--armstrong.cc>
COPYING
-------
Copyright \(C) 2012-2013 Nico Schottelius. 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.
Copyright \(C) 2018 Steven Armstrong. Free use of this software is
granted under the terms of the GNU General Public License version 3 (GPLv3).

View file

@ -0,0 +1 @@
present

View file

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