nginx-conf-flatten 6.92 KB
Newer Older
Michał Woźniak's avatar
Michał Woźniak committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/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

Michał Woźniak's avatar
Michał Woźniak committed
15
16
17
18
function debug {
    echo "$@" >&2
}

Michał Woźniak's avatar
Michał Woźniak committed
19
20

#
21
22
23
24
25
26
27
28
29
30
31
32
33
# 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
}
Michał Woźniak's avatar
Michał Woźniak committed
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


# 
# 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
Michał Woźniak's avatar
Michał Woźniak committed
59
        debug -n "        +-- found include: $i"
Michał Woźniak's avatar
Michał Woźniak committed
60
61
        # if the temporary copy of the file does not exist
        if [ ! -e "$TMP_WORKDIR/$i" ]; then
Michał Woźniak's avatar
Michał Woźniak committed
62
            debug " - copying!"
Michał Woźniak's avatar
Michał Woźniak committed
63
64
65
66
67
68
69
            # 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
Michał Woźniak's avatar
Michał Woźniak committed
70
            debug " - already copied."
Michał Woźniak's avatar
Michał Woźniak committed
71
72
73
74
75
        fi
    done
}


76
77
78
79
80
81
82
#
# 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)
Michał Woźniak's avatar
Michał Woźniak committed
83
84
85
86
87
88
89
90
91
92
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]}
Michał Woźniak's avatar
Michał Woźniak committed
93
94
        debug "    +-- working with index: $CUR_INDEX"
        debug "        $CUR_ELEMENT"
Michał Woźniak's avatar
Michał Woźniak committed
95
96
97
        unset "NGINX_CONFIG_ELEMENTS[$CUR_INDEX]"
        nginx-handle-includes "$CUR_ELEMENT";
    done
98
99
100
101
102
103
    
    # 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"
Michał Woźniak's avatar
Michał Woźniak committed
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
#
# 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 )"
            DATE_EXT="$( date +%s%N )"
            #debug "    +-- previous line : $PREVIOUS_CI_LINE"
            #debug "        ci line       : $CI_LINE"
            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############################################################\n### $ci \n############################################################" >> "$NGINX_CONFIG_COPY.$DATE_EXT"
            cat $CI_FILE_GLOB >> "$NGINX_CONFIG_COPY.$DATE_EXT"
            echo -e "\n############################################################\n### end $ci \n############################################################" >> "$NGINX_CONFIG_COPY.$DATE_EXT"
            PREVIOUS_CI_LINE="$CI_LINE"
        done
        #debug "pre-cat waiting..."
        #read
        cat $NGINX_CONFIG_COPY.* > "$NGINX_CONFIG_COPY"
        rm $NGINX_CONFIG_COPY.*
        #debug "post-rm waiting..."
        #read
    done
    IFS="$OLDIFS"
Michał Woźniak's avatar
Michał Woźniak committed
145

Michał Woźniak's avatar
Michał Woźniak committed
146
147
    debug "+-- moving the temporary output file to the output destination"
    debug "    src: $NGINX_CONFIG_COPY"
148
149
    debug "    dst: $OUTPUT_DEST"
    mv "$NGINX_CONFIG_COPY" "$OUTPUT_DEST"
Michał Woźniak's avatar
Michał Woźniak committed
150
    debug "+-- cleaning up the temporary output directory"
Michał Woźniak's avatar
Michał Woźniak committed
151
    rm -rf "$TMP_WORKDIR"
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
}

function print-usage {
    cat - <<HEREDOC
    
usage:
    $0 <mode> <source_file> <output_file|output_directory>
    
modes:
    
    flatten:
        flatten an nginx config file by inlining all includes recursively,
        save to <output_file>
        
    clean-directory:
        generate a cleaned nginx config directory, containing only the files
        that are included from the source 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" == "" ] || [ "$3" == "" ]; 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
Michał Woźniak's avatar
Michał Woźniak committed
193
fi
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

# 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


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"

TMP_WORKDIR="$( mktemp -d /tmp/nginx-conf-flatten.XXXX )"
debug "+-- TMP_WORKDIR: $TMP_WORKDIR"

# 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
    nginx-flatten "$NGINX_CONFIG" "$3"
elif [ "$1" == "clean-directory" ]; then
    nginx-clean-directory "$NGINX_CONFIG" "$3"
else
    print-usage
    exit 1
fi

# get back to the original directory we've been running from
cd "$ORIG_CWD"