123 lines
3.5 KiB
Bash
123 lines
3.5 KiB
Bash
#!/bin/sh
|
|
# Copyright (c) 2017 Markus Weippert
|
|
# GNU General Public License v3.0 (see https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
PARAMS="
|
|
backrefs/bool//false
|
|
create/bool//false
|
|
insertafter/str
|
|
insertbefore/str
|
|
line=value/str
|
|
path=dest=destfile=name/str/r
|
|
regex=regexp/str
|
|
state/str//present
|
|
$FILE_PARAMS
|
|
"
|
|
RESPONSE_VARS=""
|
|
|
|
escape_slash() {
|
|
echo "$1" | sed -e 's|^/|\\/|;:a;s|\([^\]\(\\\\\)*\)/|\1\\/|g;ta;q'
|
|
}
|
|
|
|
escape_chars() {
|
|
echo "$1" | sed 's|['"${2:-}"'\]|\\&|g;q'
|
|
}
|
|
|
|
get_last_match() {
|
|
echo "$2" | sed -nre "/$1/=" | sed '$!d'
|
|
}
|
|
|
|
save_changes() {
|
|
[ -n "$_ansible_check_mode" -o -z "$CHANGED" ] ||
|
|
echo "$1" > "$path" 2>/dev/null ||
|
|
fail "path $path not writeable"
|
|
}
|
|
|
|
line_present() {
|
|
local index old new mode tmp
|
|
|
|
[ -f "$path" ] && {
|
|
old="$(cat "$path")" || fail "path $path not readable"
|
|
} || {
|
|
[ -n "$create" ] || fail "path $path does not exist"
|
|
[ -n "$_ansible_check_mode" ] ||
|
|
mkdir -p "$(dirname "$path")"
|
|
old=""
|
|
}
|
|
|
|
index="$(get_last_match "$line_match" "$old")"
|
|
[ -n "$index" ] && {
|
|
tmp="$(echo "$old" | sed -n "${index}{p;q}")"
|
|
[ -z "$backrefs" ] || line="$(echo "$tmp" |
|
|
sed -re "s/$line_match/$(escape_slash "$line")/")"
|
|
[ "$tmp" = "$line" ] || {
|
|
new="$(echo "$old" | sed "${index}c $(escape_chars "$line" |
|
|
sed 's|^\s|\\&|;q')")"
|
|
changed
|
|
}
|
|
} || [ -n "$backrefs" ] || {
|
|
[ -n "${insertafter#[EB]OF}" ] && {
|
|
index="$(get_last_match "$(escape_slash "$insertafter")" "$old")"
|
|
mode="a"
|
|
} || [ -z "${insertbefore#BOF}" ] || {
|
|
index="$(get_last_match "$(escape_slash "$insertbefore")" "$old")"
|
|
mode="i"
|
|
}
|
|
[ -n "$index" ] && {
|
|
new="$(echo "$old" | sed "$index$mode $(escape_chars "$line" |
|
|
sed 's|^\s|\\&|;q')")"
|
|
} || {
|
|
[ "$insertafter" = "BOF" -o "$insertbefore" = "BOF" ] &&
|
|
new="$line$N$old" || {
|
|
tmp="$(echo "$old" | sed '${/^$/d}')"
|
|
new="$tmp${tmp:+$N}$line"
|
|
}
|
|
}
|
|
changed
|
|
}
|
|
|
|
[ -z "$CHANGED" ] || {
|
|
[ -z "$_ansible_diff" ] || set_diff "$old" "$new" "$path" "$path"
|
|
[ -n "$_ansible_check_mode" ] || save_changes "$new"
|
|
}
|
|
}
|
|
|
|
line_absent() {
|
|
local index new old
|
|
|
|
[ -f "$path" ] || return 0
|
|
|
|
old="$(cat "$path")" || fail "path $path not readable"
|
|
index="$(get_last_match "$line_match" "$old")"
|
|
[ -z "$index" ] || {
|
|
new="$(echo "$old" | sed -re "/$line_match/d")"
|
|
changed
|
|
}
|
|
|
|
[ -z "$_ansible_diff" ] || set_diff "$old" "$new" "$path" "$path"
|
|
[ -n "$_ansible_check_mode" -o -z "$CHANGED" ] || save_changes "$new"
|
|
}
|
|
|
|
main() {
|
|
case "$state" in
|
|
absent|present) :;;
|
|
*) fail "state must be absent or present";;
|
|
esac
|
|
[ -n "$regex" ] &&
|
|
line_match="$(escape_slash "$regex")" ||
|
|
line_match="^$(escape_chars "$line" '/.[*^$()+?{|')\$"
|
|
[ ! -d "$file" ] || fail "path $path is a directory"
|
|
case "$state" in
|
|
present)
|
|
[ -z "$backrefs" -o -n "$regex" ] ||
|
|
fail "regexp is required with backrefs"
|
|
[ -n "$line" ] || fail "line is required with state present"
|
|
line_present;;
|
|
absent)
|
|
[ -n "$line" -o -n "$regex" ] ||
|
|
fail "line or regexp is required with state absent"
|
|
line_absent;;
|
|
esac
|
|
set_file_attributes "$path" "" "y"
|
|
}
|