-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerate-script
executable file
·304 lines (242 loc) · 8.48 KB
/
generate-script
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
#! /bin/sh
exit_no_default() {
echo "Please, set the valid default site name in sites.json" >&2
exit 1
}
JOIN_FUNC="def join(str): reduce .[1:][] as \$item (.[0]|tostring; . + str + (\$item|tostring))"
DEFAULT="$(jq -r "${JOIN_FUNC}; .default|if type==\"array\" then join(\", \") else . end" sites.json)"
SITES_TEXT="$(jq -r "$(cat sites_to_help_text.jq)" sites.json)"
echo "${SITES_TEXT}" | grep -q ' (default)' || exit_no_default
cat <<EOF_
#! /bin/sh
print_help_exit() {
cat <<EOF
Usage: \$(basename "\$0") [-u|-f|-p] [-t|-S SUFFIX] [-s SITE]... FILE...
Options:
-h Show this help message and exit
-s SITE Specify the site name to upload, can be used
multiple times to upload to multiple sites
(default sites: ${DEFAULT})
-S SUFFIX Upload as files with the specified SUFFIX
-t Upload as text files (equivalent to -S txt)
-u Output URL
-f Output filename only
-p Output the same way as the server responses
-v Increase verbosity, can be specified multiple times
-q Decrease verbosity, can be specified multiple times
Supported sites:
EOF_
echo "${SITES_TEXT}"
cat <<'EOF_'
EOF
exit 0
}
print_usage_exit() {
echo "Usage: $(basename "$0") [-u|-f|-p] [-t|-S SUFFIX] [-s SITE]... FILE..."
exit 1
}
print_message() {
_MSG_LEVEL_="$1"
_FORMAT_="$2"
shift 2
# shellcheck disable=SC2059
[ "${_MSG_LEVEL_}" -le "${VERBOSITY}" ] && printf "${_FORMAT_}\n" "$@" >&2
}
alias error='print_message 1'
alias warning='print_message 2'
alias info='print_message 3'
alias debug='print_message 4'
get_site_data() {
_SITE_="$1"
_site_data_="$(echo "${SITES_JSON}" | jq -r ".sites[\"${_SITE_}\"]")"
[ "${_site_data_}" = null ] && _site_data_="$(echo "${SITES_JSON}" |
jq -r ".sites[]|select(.aliases)|select(.aliases[]|.==\"${_SITE_}\")")"
echo "${_site_data_}"
}
get_sites_data() {
_SITES_COUNT_="$1"
shift $(($# - _SITES_COUNT_))
for site in "$@"; do
_sites_data_="$(printf -- '%s\n%s' "${_sites_data_}" "$(get_site_data "${site}")")"
done
echo "${_sites_data_}"
}
get_field_value() {
_SITE_DATA_="$1"
_FIELDNAME_="$2"
_DEFAULT_VALUE_="$3"
_field_value_="$(echo "${_SITE_DATA_}" | jq -r ."${_FIELDNAME_}")"
([ -n "${_DEFAULT_VALUE_}" ] && [ "${_field_value_}" = null ]) && _field_value_="${_DEFAULT_VALUE_}"
echo "${_field_value_}"
}
SITES_JSON=$(cat <<'EOF'
EOF_
cat sites.json
cat <<'EOF_'
EOF
)
# Save default sites names in newline-separated jq strings, which preserve whitespace
DEFAULT_SITES="$(echo "${SITES_JSON}" | jq -c '.default|if type=="array" then .[] else . end')"
SITES_COUNT=0
OUTPUT_TYPE='url'
VERBOSITY=2
while getopts ':hvqs:tS:ufp' x; do
case $x in
h)
print_help_exit
;;
v)
VERBOSITY=$((VERBOSITY+1))
;;
q)
VERBOSITY=$((VERBOSITY-1))
;;
s)
SITES_COUNT=$((SITES_COUNT+1))
set -- "$@" "${OPTARG}"
# dash-only (bash and posh can work properly without this workaround):
# dash restarts (sets OPTIND to 1 and parses "$@" from the beginning) getopts if
# "$@" is changed before the while loop finishes a step, effectively producing
# an infinite loop;
# shifting forces subsequent getopts calls to skip already handled parameters
shift $((OPTIND-1)) # Parse from the beginning of the *shifted* array
OPTIND=1 # As you remember, bash and posh do not reset OPTIND automatically
;;
t)
SUFFIX='txt'
;;
S)
SUFFIX="${OPTARG}"
;;
u)
OUTPUT_TYPE='url'
;;
f)
OUTPUT_TYPE='filename'
;;
p)
OUTPUT_TYPE='preserve'
;;
\?)
echo -- "Invalid option: -${OPTARG}" >&2
print_usage_exit
;;
:)
echo -- "-${OPTARG} needs an argument" >&2
print_usage_exit
;;
esac
done
shift $((OPTIND-1))
if [ $# -lt 1 ]; then
print_usage_exit
fi
[ "$SITES_COUNT" -eq 0 ] && while read -r line; do
SITES_COUNT=$((SITES_COUNT+1))
set -- "$@" "$(echo "${line}" | jq -r .)"
# Avoid subshelling to be able to set variable
done <<EOF
${DEFAULT_SITES}
EOF
SITES_DATA="$(get_sites_data "${SITES_COUNT}" "$@")"
# Remove sites names from "$@", only filenames are allowed to be there
TO_SHIFT=$#
for arg; do
[ $# -eq $((TO_SHIFT + (TO_SHIFT - SITES_COUNT))) ] && break
set -- "$@" "${arg}"
done
shift $((TO_SHIFT))
if [ -n "${SUFFIX}" ]; then
TEMPDIR="$(mktemp --directory)"
[ -d "${TEMPDIR}" ] || (echo "Couldn't create a temporary directory" >&2 && exit 1)
TO_SHIFT=$#
for filename in "$@"; do
new_filename="$(basename "${filename}").${SUFFIX}"
ln -s "${filename}" "${TEMPDIR}/${new_filename}"
set -- "$@" "${new_filename}"
done
shift $((TO_SHIFT))
# Server doesn't need to know the exact locations of our temporary symlinks
cd "${TEMPDIR}" || (echo "Failed to cd to ${TEMPDIR}" >&2 && exit 1)
fi
build_response_handler() {
_SITE_DATA_="$1"
_RESPONSE_TEMPLATE_="$(get_field_value "${_SITE_DATA_}" response "\$json:files[].url")"
case "${_RESPONSE_TEMPLATE_}" in
"\$url") _HANDLE_RESPONSE_='(cat; echo) | head -n 1' ;; # Checking for eol would make code ugly
"\$json:"*) _HANDLE_RESPONSE_="jq -r $(echo "${_RESPONSE_TEMPLATE_}" | sed "s/^\$json:/./")" ;;
*) echo "Wrong response template value: \"${_RESPONSE_TEMPLATE_}\"" >&2; exit 1 ;;
esac
echo "${_HANDLE_RESPONSE_}"
}
build_form_headers() {
_SITE_DATA_="$1"
shift 1
_FILE_FORM_NAME_="$(get_field_value "${_SITE_DATA_}" file_form_name 'files[]')"
_ADDITIONAL_FORM_HEADERS_="$(echo "${_SITE_DATA_}" \
| jq -r 'select(.headers)|.headers|to_entries[]|"\(.key)=\(.value)"')"
# shellcheck disable=SC2039
_FORM_HEADERS_="$(printf -- "-F '${_FILE_FORM_NAME_}=@%s' " "$@" | head -c -1)"
# shellcheck disable=SC2039
[ -n "${_ADDITIONAL_FORM_HEADERS_}" ] && \
while read -r line; do
_FORM_HEADERS_="${_FORM_HEADERS_} \
$(printf -- "-F '%s' " "${line}" | head -c -1)"
done <<EOF
${_ADDITIONAL_FORM_HEADERS_}
EOF
echo "${_FORM_HEADERS_}"
}
upload_print() {
_SITE_DATA_="$1"
shift 1
_UPLOAD_URL_="$(get_field_value "${_SITE_DATA_}" upload)"
_DOWNLOAD_URL_="$(get_field_value "${_SITE_DATA_}" download)"
_HANDLE_RESPONSE_="$(build_response_handler "${_SITE_DATA_}")"
_FORM_HEADERS_="$(build_form_headers "${_SITE_DATA_}" "$@")"
# Single quotes inside ${_FORM_HEADERS_} to support filenames containing spaces and
# a subshell construct (cmd; cmd) in ${_HANDLE_RESPONSE_} used here, so we have to eval
# Let stderr through to print curl error messages
_RESPONSE_="$(eval "curl -fsSL ${_FORM_HEADERS_} -w '\n%{http_code}' '${_UPLOAD_URL_}'")"
_CURL_CODE_=$?
if [ "$(echo "${_RESPONSE_}" | tail -n 1)" -ne 200 ]; then
info "curl finished with ${_CURL_CODE_} exit code"
info "Response:\n${_RESPONSE_}"
exit $((_CURL_CODE_))
else
info "Response:\n${_RESPONSE_}"
fi
_OUTPUT_="$(echo "${_RESPONSE_}" | head -n -1 | eval "${_HANDLE_RESPONSE_}")"
echo "${_OUTPUT_}" | while read -r line; do
case "${OUTPUT_TYPE}" in
url)
echo "${_DOWNLOAD_URL_}" | sed "s|\$result|${line}|"
;;
filename)
# Filename must be the last entry in any given URL that points to a file
echo "${line}" | tr '/' '\n' | tail -n 1
;;
preserve)
echo "${line}"
;;
esac
done
}
echo "${SITES_DATA}" | jq -c . | while read -r line; do
MULTIPLE_FILES="$(get_field_value "${line}" multiple_files 'true')"
info 'Files:'
info ' %s' "$@"
if [ "${MULTIPLE_FILES}" = true ]; then
info 'Multiple files uploading is supported'
upload_print "${line}" "$@"
else
info 'Only single file uploading is supported'
for filename in "$@"; do
info "Uploading \"%s\" ..." "${filename}"
upload_print "${line}" "${filename}"
done
fi
done
# Cleanup
[ -n "${TEMPDIR}" ] && cd "${OLDPWD}" && rm -r "${TEMPDIR}"
EOF_