-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnginx-conf-flatten
executable file
·351 lines (301 loc) · 11.2 KB
/
nginx-conf-flatten
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
#!/bin/bash
#
# flatten an nginx config
#
# replaces all occurences of the `include` directive
# with the relevant included files
#
# assumptions:
# - include file paths do not contain spaces
# (this seems compatible with how nginx handles includes)
# - no files are included from above the directory where the nginx config file
# being processed resides in
# set debug verbosity to none
[ -z "${NGINX_CONF_FLATTEN_DEBUG+x}" ] && NGINX_CONF_FLATTEN_DEBUG=""
function debug {
if [ "$NGINX_CONF_FLATTEN_DEBUG" != "" ]; then
echo "$@" >&2
fi
}
#
# get the path relative to a different base path
# if the former is relative
#
# $1 - path
# $2 - base path
function get-path-relative-to {
# if the path is absolute, that's all we need
if [[ "$1" = /* ]]; then
echo "$1"
else
echo "$2/$1"
fi
}
#
# extract the include paths from an nginx config file
#
# $1 - the file to work with
function nginx-extract-includes {
# assumption: include path does not contain spaces
egrep '^\s*include ' "$1" | sed -r -e "s/^\s*include\s*([^;]+).*$/\1/"
}
#
# handle all includes of a file to the temporary workdir
# creating the directory structure in the process
# and adding them to the NGINX_CONFIG_FILES variable
# for further processing
#
# $1 - the file to work with
function nginx-handle-includes {
# get the included files
# this will loop through actual globbed filenames
#
# assumption: no files are included from directories above the directory
# the main config file resides in
for i in $( nginx-extract-includes "$1" ); do
debug -n " +-- found include: $i"
# if the temporary copy of the file does not exist
if [ ! -e "$TMP_WORKDIR/$i" ]; then
debug " - copying!"
# create the directory structure
mkdir -p "$TMP_WORKDIR/$( dirname "$i" )"
# copy the file
cp "$NGINX_CONFIG_DIR/$i" "$TMP_WORKDIR/$i"
# add to the list of files to proces
NGINX_CONFIG_ELEMENTS+=("$i")
else
debug " - already copied."
fi
done
}
#
# generate a cleaned nginx config directory,
# containing only the files that are included from the config file
# passed as the argument, or files included from those, etc
#
# $NGINX_CONFIG - nginx config file to work off of
# $OUTPUT_DEST - target directory (must *not* exist)
function nginx-clean-directory {
# let's get the file in a temporary location
# (we don't want to screw up the original!)
cp "$NGINX_CONFIG" "$TMP_WORKDIR"/
# go one by one over the NGINX_CONFIG_ELEMENTS array
# but from the end
while [[ ${#NGINX_CONFIG_ELEMENTS[@]} > 0 ]]; do
CUR_INDEX=$(( ${#NGINX_CONFIG_ELEMENTS[@]} - 1 ))
CUR_ELEMENT=${NGINX_CONFIG_ELEMENTS[$CUR_INDEX]}
debug " +-- working with index: $CUR_INDEX"
debug " $CUR_ELEMENT"
unset "NGINX_CONFIG_ELEMENTS[$CUR_INDEX]"
nginx-handle-includes "$CUR_ELEMENT";
done
# move the temporary work dir to the output location
debug "+-- moving the temporary output directory to the final output location"
debug " src: $TMP_WORKDIR"
debug " dst: $OUTPUT_DEST"
mv "$TMP_WORKDIR" "$OUTPUT_DEST"
}
#
# flatten an nginx config file,
# including all includes inline, recursively
#
# $NGINX_CONFIG - nginx config file to work off of
# $OUTPUT_DEST - where to output the assembled, flattened file (must not exist)
function nginx-flatten {
# let's get the file in a temporary location
# (we don't want to screw up the original!)
cp "$NGINX_CONFIG" "$TMP_WORKDIR"/
NGINX_CONFIG_COPY="$TMP_WORKDIR/$( basename "$NGINX_CONFIG")"
OLDIFS="$IFS"
IFS=$'\n'
while CURRENT_INCLUDES="$( egrep -n '^\s*include\s*.+;.*$' "$NGINX_CONFIG_COPY" )"; do
PREVIOUS_CI_LINE=0;
for ci in $CURRENT_INCLUDES; do
# get the actual file glob
CI_FILE_GLOB="$( echo "$ci" | sed -r -e "s/^[0-9]+\:\s*include\s*([^;]+).*$/\1/" )"
CI_LINE="$( echo "$ci" | cut -d ':' -f 1 )"
CI_INDENT="$( echo "$ci" | cut -d ':' -f 2 | sed -r -e 's/^(\s*).*$/\1/' )"
DATE_EXT="$( date +%s%N )"
debug " +-- previous line : $PREVIOUS_CI_LINE"
debug " ci line : $CI_LINE"
debug " indent : '$CI_INDENT'"
debug " glob : '$CI_FILE_GLOB'"
tail -n "+$(( $PREVIOUS_CI_LINE + 1 ))" "$NGINX_CONFIG_COPY" | head -n $(( $CI_LINE - 1 - $PREVIOUS_CI_LINE )) > "$NGINX_CONFIG_COPY.$DATE_EXT"
echo -e "\n$CI_INDENT############################################################\n$CI_INDENT### $CI_FILE_GLOB \n$CI_INDENT############################################################" >> "$NGINX_CONFIG_COPY.$DATE_EXT"
sed -r -e "s/^/$CI_INDENT/" $CI_FILE_GLOB >> "$NGINX_CONFIG_COPY.$DATE_EXT"
echo -e "\n$CI_INDENT############################################################\n$CI_INDENT### end $CI_FILE_GLOB \n$CI_INDENT############################################################" >> "$NGINX_CONFIG_COPY.$DATE_EXT"
PREVIOUS_CI_LINE="$CI_LINE"
done
debug " +-- previous line : $PREVIOUS_CI_LINE"
debug " finishing this run off."
DATE_EXT="$( date +%s%N )"
tail -n "+$(( $PREVIOUS_CI_LINE + 1 ))" "$NGINX_CONFIG_COPY" > "$NGINX_CONFIG_COPY.$DATE_EXT"
cat $NGINX_CONFIG_COPY.* > "$NGINX_CONFIG_COPY"
rm $NGINX_CONFIG_COPY.*
done
IFS="$OLDIFS"
debug "+-- moving the temporary output file to the output destination"
debug " src: $NGINX_CONFIG_COPY"
debug " dst: $OUTPUT_DEST"
if [ "$OUTPUT_DEST" == '-' ]; then
cat "$NGINX_CONFIG_COPY"
else
mv "$NGINX_CONFIG_COPY" "$OUTPUT_DEST"
fi
debug "+-- cleaning up the temporary output directory"
rm -rf "$TMP_WORKDIR"
}
#
# print the include tree, or dump it to a file
function nginx-tree {
# includes map
declare -A NGINX_INCLUDES_MAP
# go one by one over the NGINX_CONFIG_ELEMENTS array
# using it as a stack
while [[ ${#NGINX_CONFIG_ELEMENTS[@]} > 0 ]]; do
CUR_INDEX=$(( ${#NGINX_CONFIG_ELEMENTS[@]} - 1 ))
CUR_ELEMENT="${NGINX_CONFIG_ELEMENTS[$CUR_INDEX]}"
debug " +-- working with index: $CUR_INDEX"
debug " $CUR_ELEMENT"
unset "NGINX_CONFIG_ELEMENTS[$CUR_INDEX]"
if [ "${NGINX_INCLUDES_MAP[$CUR_ELEMENT]}" == "" ]; then
# ...create the include map
CURRENT_INCLUDES=""
# this will loop through actual globbed filenames
for i in $( nginx-extract-includes "$CUR_ELEMENT" ); do
NGINX_CONFIG_ELEMENTS+=("$i")
CURRENT_INCLUDES="$CURRENT_INCLUDES $i"
done
NGINX_INCLUDES_MAP[$CUR_ELEMENT]="$CURRENT_INCLUDES"
fi
# otherwise we've processed this file and all included files already
done
# let's do this again, now having the map data
CUR_INDENT=""
INDENT_ALREADY_DECREASED=0
NGINX_CONFIG_ELEMENTS=("$NGINX_CONFIG")
while [[ ${#NGINX_CONFIG_ELEMENTS[@]} > 0 ]]; do
CUR_INDEX=$(( ${#NGINX_CONFIG_ELEMENTS[@]} - 1 ))
CUR_ELEMENT="${NGINX_CONFIG_ELEMENTS[$CUR_INDEX]}"
debug " +-- working with index: $CUR_INDEX"
debug " $CUR_ELEMENT"
unset "NGINX_CONFIG_ELEMENTS[$CUR_INDEX]"
if [ "$CUR_ELEMENT" == " DECREASE INDENT " ]; then
CUR_INDENT="${CUR_INDENT:3}"
if [ "$INDENT_ALREADY_DECREASED" == 0 ]; then
if [ "$OUTPUT_DEST" == '-' ]; then
echo "$CUR_INDENT"
else
echo "$CUR_INDENT" >> "$OUTPUT_DEST"
fi
fi
INDENT_ALREADY_DECREASED=1
else
INDENT_ALREADY_DECREASED=0
if [ "$OUTPUT_DEST" == '-' ]; then
echo "$CUR_INDENT- $CUR_ELEMENT"
else
echo "$CUR_INDENT- $CUR_ELEMENT" >> "$OUTPUT_DEST"
fi
if [ "${NGINX_INCLUDES_MAP[$CUR_ELEMENT]}" != "" ]; then
NGINX_CONFIG_ELEMENTS+=(" DECREASE INDENT ")
# we need the order of includes reversed
for i in `echo "${NGINX_INCLUDES_MAP[$CUR_ELEMENT]}" | tr ' ' $'\n' | tac`; do
NGINX_CONFIG_ELEMENTS+=("$i")
done
CUR_INDENT=" $CUR_INDENT"
fi
fi
done
}
#
# print the usage
function print-usage {
cat - <<HEREDOC
usage:
$0 <mode> <input_file> <output_file|output_directory>
modes:
tree:
generate a tree of includes and save it to <output_file>
(or print to standard output if <output_file> not given)
flatten:
flatten an nginx config file by inlining all includes recursively,
save to <output_file> (or print to standard output if <output_file>
not given)
clean-directory:
generate a cleaned nginx config directory, containing only the files
that are included from the input file, or files included from those,
and so on; output to <output_directory>
HEREDOC
}
ORIG_CWD="$PWD"
# we really need 3 arguments:
# $1 - mode of operation
# $2 - source file
# $3 - destination file/directory
if [ "$1" == "" ] || [ "$2" == "" ]; then
print-usage
exit 1
fi
# source file exists?
if [ ! -f "$2" ] || [ ! -r "$2" ]; then
echo
echo "ERROR: source config file $2 doesn't exist or read access not granted"
echo
exit 2
fi
if [ "$1" == "flatten" ] || [ "$1" == "tree" ]; then
if [ "$3" == "" ]; then
OUTPUT_DEST="-"
debug "+-- output to stdout."
else
# destination file/directory must not exist
OUTPUT_DEST="$( get-path-relative-to "$3" "$ORIG_CWD" )"
if [ -e "$OUTPUT_DEST" ]; then
echo
echo "WARNING: output file/directory exists; quitting!"
echo
exit 3
fi
fi
# for clean-director we always have to have $3
else
if [ "$3" == "" ]; then
print-usage
exit 1
fi
# destination file/directory must not exist
OUTPUT_DEST="$( get-path-relative-to "$3" "$ORIG_CWD" )"
if [ -e "$OUTPUT_DEST" ]; then
echo
echo "WARNING: output file/directory exists; quitting!"
echo
exit 3
fi
fi
NGINX_CONFIG="$( realpath -eL "$2" )"
debug "+-- config file: '$NGINX_CONFIG'"
NGINX_CONFIG_DIR="$( dirname "$NGINX_CONFIG" )"
debug " config directory: 'NGINX_CONFIG_DIR'"
cd "$NGINX_CONFIG_DIR"
# the list of files whose includes we have not copied yet
NGINX_CONFIG_ELEMENTS=("$NGINX_CONFIG")
# what are we doing, eh?
if [ "$1" == "flatten" ]; then
TMP_WORKDIR="$( mktemp -d /tmp/nginx-conf-flatten.XXXX )"
debug "+-- TMP_WORKDIR: $TMP_WORKDIR"
nginx-flatten
elif [ "$1" == "clean-directory" ]; then
TMP_WORKDIR="$( mktemp -d /tmp/nginx-conf-flatten.XXXX )"
debug "+-- TMP_WORKDIR: $TMP_WORKDIR"
nginx-clean-directory
elif [ "$1" == "tree" ]; then
nginx-tree
else
print-usage
exit 1
fi
# cleanup
rm -rf "$TMP_WORKDIR"
# get back to the original directory we've been running from
cd "$ORIG_CWD"