09d7b824df54f2c29075d7feb248804e70b34e64
[cedit] / cedit
1 #!/bin/bash
2 # Copyright (C) 2016 Ian Kelling
3
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7
8 # http://www.apache.org/licenses/LICENSE-2.0
9
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 cedit() {
17 local help="Usage: [-h|--help ] [-v] [SECTION_NAME] FILE
18 Create/modify a section in a config file
19
20 Returns 1 if the file is modified by this command, 2 or higher
21 for other problems.
22
23 The section is #comment delimited. Reads STDIN for the contents of the
24 section. Without SECTION_NAME, it acts on a global unnamed
25 section. cedit is short for config edit.
26
27 -q Quiet
28 -s Silent. Quiet and exit 0 on modified file.
29 -v Verbose
30 -b Keep backup file
31 -h|--help Help"
32 local s diff name init file_dir exists verbose backup quiet silent
33 file_dir="$(dirname "$file")"
34 exists=true
35 verbose=false
36 backup=false
37 quiet=false
38 silent=false
39
40 case $1 in
41 -b) backup=true; shift ;;
42 -v) verbose=true; shift ;;
43 -q) quiet=true; shift ;;
44 -s) quiet=true; silent=true; shift ;;
45 -h|--help) echo "$help"; return ;;
46 esac
47
48 if (( $# == 2 )); then
49 name=": $1"
50 shift
51 fi
52
53 local file="$1"
54 local file_name="${file##*/}"
55
56 local comment
57 comment="#_#_#"
58
59 # bind zone files use ; for comments yes, a little hacky detection.
60 if [[ $file_name == db.* ]]; then
61 comment=";;_;_;"
62 fi
63 local begin="$comment start delimiter of cedit section$name. do not modify. $comment"
64 local end="$comment end delimiter of cedit section$name. do not modify. $comment"
65
66 if [[ ! -e $file_dir ]]; then
67 if ! mkdir -p $file_dir; then
68 s=sudo
69 $s mkdir -p $file_dir || return 2
70 fi
71 fi
72 if [[ ! -e $file ]]; then
73 exists=false
74 if ! $s touch $file; then
75 s=sudo
76 $s touch $file || return 2
77 fi
78 fi
79
80 [[ -w $file ]] || s=sudo
81
82
83 local in_section=false
84 if $exists; then
85 local tailn=1
86 local temp="$(mktemp -d)/$file_name"
87 cp "$file" "$temp"
88 cp /dev/null "$file"
89 while IFS= read -r line; do
90 tailn=$(( tailn + 1 ))
91 if [[ $line == "$begin" ]]; then
92 in_section=true;
93 break
94 fi
95 printf '%s\n' "$line" >> $file
96 done < "$temp"
97 fi
98
99 IFS= read -d '' -n 1 -r init
100 if [[ $init ]]; then
101 $s tee -a "$file" >/dev/null <<<"$begin"
102 printf '%s' "$init" | $s tee -a "$file" >/dev/null
103 $s tee -a "$file" >/dev/null
104 $s tee -a "$file" >/dev/null <<<"$end"
105 fi
106
107 if $exists && $in_section; then
108 while IFS= read -r line; do
109 if [[ $line == "$begin" ]]; then
110 in_section=true;
111 fi
112 if ! $in_section; then
113 printf '%s\n' "$line" >> $file
114 fi
115 if [[ $line == $end ]]; then
116 in_section=false;
117 fi
118 done < <(tail -n +$tailn "$temp")
119 fi
120
121
122 if ! $exists; then
123 ret=1
124 if $verbose; then
125 echo "New file $file:"
126 cat "$file"
127 fi
128 elif type -t diff &>/dev/null; then
129 diff=$(diff -u "$temp" "$file")
130 ret=$?
131 if (( $ret )) && ! $quiet; then
132 echo "backup of original at $temp"
133 echo diff -u "$temp" "$file":
134 echo "$diff"
135 #elif $debug; then
136 # echo "No changes made to $file"
137 fi
138 else
139 # for systems like openwrt which don't have diff
140 diff=$(cmp "$temp" "$file")
141 ret=$?
142 if $verbose; then
143 echo "$diff"
144 fi
145 fi
146 if ! $backup && $exists; then
147 rm -r "$temp"
148 fi
149 if $silent; then
150 case $ret in
151 0|1) return 0 ;;
152 *) return $ret ;;
153 esac
154 else
155 return $ret
156 fi
157 }
158 cedit "$@"