make section placement stable. slightly less verbose output
[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 -v Verbose
28 -b Keep backup file
29 -h|--help Help"
30 local s diff name init
31 local file_dir="$(dirname "$file")"
32 local exists=true
33 local verbose=false
34 local backup=false
35
36 case $1 in
37 -b) backup=true; shift ;;
38 -v) verbose=true; shift ;;
39 -h|--help) echo "$help"; return ;;
40 esac
41
42 if (( $# == 2 )); then
43 name=": $1"
44 shift
45 fi
46
47 local file="$1"
48 local file_name="${file##*/}"
49
50 local begin="#_#_# start delimiter of cedit section$name. do not modify. #_#_#"
51 local end="#_#_# end delimiter of cedit section$name. do not modify. #_#_#"
52
53 if [[ ! -e $file_dir ]]; then
54 if ! mkdir -p $file_dir; then
55 s=sudo
56 $s mkdir -p $file_dir || return 2
57 fi
58 fi
59 if [[ ! -e $file ]]; then
60 exists=false
61 if ! $s touch $file; then
62 s=sudo
63 $s touch $file || return 2
64 fi
65 fi
66
67 [[ -w $file ]] || s=sudo
68
69
70 local in_section=false
71 if $exists; then
72 local tailn=1
73 local temp="$(mktemp -d)/$file_name"
74 cp "$file" "$temp"
75 cp /dev/null "$file"
76 while IFS= read -r line; do
77 tailn=$(( tailn + 1 ))
78 if [[ $line == "$begin" ]]; then
79 in_section=true;
80 break
81 fi
82 printf '%s\n' "$line" >> $file
83 done < "$temp"
84 fi
85
86 IFS= read -d '' -n 1 -r init
87 if [[ $init ]]; then
88 $s tee -a "$file" >/dev/null <<<"$begin"
89 printf '%s' "$init" | $s tee -a "$file" >/dev/null
90 $s tee -a "$file" >/dev/null
91 $s tee -a "$file" >/dev/null <<<"$end"
92 fi
93
94 if $exists && $in_section; then
95 while IFS= read -r line; do
96 if [[ $line == "$begin" ]]; then
97 in_section=true;
98 fi
99 if ! $in_section; then
100 printf '%s\n' "$line" >> $file
101 fi
102 if [[ $line == $end ]]; then
103 in_section=false;
104 fi
105 done < <(tail -n +$tailn "$temp")
106 fi
107
108
109 if ! $exists; then
110 ret=1
111 if $verbose; then
112 echo "New file $file:"
113 cat "$file"
114 fi
115 elif type -t diff &>/dev/null; then
116 diff=$(diff -u "$temp" "$file")
117 ret=$?
118 if (( $ret )); then
119 echo "backup of original at $temp"
120 echo diff -u "$temp" "$file":
121 echo "$diff"
122 #elif $debug; then
123 # echo "No changes made to $file"
124 fi
125 else
126 # for systems like openwrt which don't have diff
127 diff=$(cmp "$temp" "$file")
128 ret=$?
129 if $verbose; then
130 echo "$diff"
131 fi
132 fi
133 if ! $backup; then
134 rm -r $"$temp"
135 fi
136 return $ret
137 }
138 cedit "$@"