Project

General

Profile

« Previous | Next » 

Revision 6106c789

Added by koszko almost 2 years ago

rewrite parts of build script in awk

View differences:

CHROMIUM_exports_init.js
1
// SPDX-License-Identifier: CC0-1.0
2

  
3
window.killtheweb={is_chrome: true, browser: window.chrome};
MOZILLA_exports_init.js
1
// SPDX-License-Identifier: GPL-3.0-or-later
2

  
3
/**
4
 * This file is part of Haketilo.
5
 *
6
 * Function: Data structure to query items by URL patterns.
7
 *
8
 * Copyright (C) 2021 Wojtek Kosior
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * As additional permission under GNU GPL version 3 section 7, you
21
 * may distribute forms of that code without the copy of the GNU
22
 * GPL normally required by section 4, provided you include this
23
 * license notice and, in case of non-source distribution, a URL
24
 * through which recipients can access the Corresponding Source.
25
 * If you modify file(s) with this exception, you may extend this
26
 * exception to your version of the file(s), but you are not
27
 * obligated to do so. If you do not wish to do so, delete this
28
 * exception statement from your version.
29
 *
30
 * As a special exception to the GPL, any HTML file which merely
31
 * makes function calls to this code, and for that purpose
32
 * includes it by reference shall be deemed a separate work for
33
 * copyright law purposes. If you modify this code, you may extend
34
 * this exception to your version of the code, but you are not
35
 * obligated to do so. If you do not wish to do so, delete this
36
 * exception statement from your version.
37
 *
38
 * You should have received a copy of the GNU General Public License
39
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
40
 *
41
 * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
42
 * license. Although I request that you do not make use this code in a
43
 * proprietary program, I am not going to enforce this in court.
44
 */
45

  
46
/* Polyfill for IceCat 60. */
47
String.prototype.matchAll = String.prototype.matchAll || function(regex) {
48
    if (regex.flags.search("g") === -1)
49
        throw new TypeError("String.prototype.matchAll called with a non-global RegExp argument");
50

  
51
    for (const matches = [];;) {
52
        if (matches[matches.push(regex.exec(this)) - 1] === null)
53
	    return matches.splice(0, matches.length - 1);
54
    }
55
}
56

  
57
window.killtheweb={is_mozilla: true, browser: this.browser};
build.sh
3 3
# Copyright (C) 2021 Wojtek Kosior
4 4
# Redistribution terms are gathered in the `copyright' file.
5 5

  
6
handle_export_line() {
7
    if [ "x$1" = "xEXPORTS_START" ]; then
8
	if [ "$STATE" = "before_block" ]; then
9
	    STATE="in_block"
10
	fi
11
    elif [ "x$1" = "xEXPORT" ]; then
12
	if [ "$STATE" != "in_block" ]; then
13
	    return
14
	fi
15

  
16
	EXPORTCODE="${EXPORTCODE}window.killtheweb.$2 = $2;$ENDL"
17

  
18
	PREVIOUS_FILE="$(map_get EXPORTS $2)"
19
	if [ "x$PREVIOUS_FILE" != "x" ]; then
20
	    errcho "export $2 present in both $PREVIOUS_FILE and $FILE"
21
	    return 1
22
	fi
23

  
24
	map_set_instr EXPORTS $2 "$FILE"
25

  
26
    elif [ "x$1" = "xEXPORTS_END" ]; then
27
	if [ "$STATE" = "in_block" ]; then
28
	    STATE="after_block"
29
	fi
30
    fi
31
}
32

  
33
translate_exports() {
34
    STATE="before_block"
35
    EXPORTCODE=''
36

  
37
    while read EXPORT_LINE; do
38
	handle_export_line $EXPORT_LINE || return 1
39
    done
40

  
41
    map_set_instr EXPORTCODES $FILEKEY "$EXPORTCODE"
42
}
43

  
44
add_exports() {
45
    FILE="$1"
46
    FILEKEY="$(sanitize "$FILE")"
47

  
48
    eval "$(grep -o 'EXPORT.\+' "$1" | translate_exports || exit 1)"
49
}
50

  
51
handle_import_line() {
52
    if [ "x$1" = "xIMPORTS_START" ]; then
53
	if [ "$STATE" = "before_block" ]; then
54
	    STATE="in_block"
55
	fi
56
    elif [ "x$1" = "xIMPORT" ]; then
57
	if [ "$STATE" != "in_block" ]; then
58
	    return
59
	fi
60

  
61
	IMPORTCODE="${IMPORTCODE}const $2 = window.killtheweb.$2;$ENDL"
62

  
63
	IMPORTS="$IMPORTS $2"
64

  
65
    elif [ "x$1" = "xIMPORTS_END" ]; then
66
	if [ "$STATE" = "in_block" ]; then
67
	    STATE="after_block"
68
	fi
69
    fi
70
}
71

  
72
translate_imports() {
73
    STATE="before_block"
74
    IMPORTCODE=''
75
    IMPORTS=''
76

  
77
    while read IMPORT_LINE; do
78
	handle_import_line $IMPORT_LINE || return 1
79
    done
80

  
81
    map_set_instr IMPORTCODES $FILEKEY "$IMPORTCODE"
82
    map_set_instr IMPORTS $FILEKEY "$IMPORTS"
83
}
84

  
85
add_imports() {
86
    FILE="$1"
87
    FILEKEY="$(sanitize "$FILE")"
88

  
89
    eval "$(grep -o 'IMPORT.\+' "$1" | translate_imports || exit 1)"
90
}
6
set -e
91 7

  
92
compute_scripts_list_rec() {
93
    local FILE="$1"
94
    local FILEKEY=$(sanitize "$1")
95

  
96
    local FILESTATE="$(map_get FILESTATES $FILEKEY)"
97
    if [ "xprocessed" = "x$FILESTATE" ]; then
98
	return
99
    fi
100
    if [ "xprocessing" = "x$FILESTATE" ]; then
101
	errcho "import loop on $FILE"
102
	return 1
103
    fi
104

  
105
    USED="$USED $FILEKEY"
106

  
107
    map_set FILESTATES $FILEKEY "processing"
108

  
109
    local IMPORT
110
    for IMPORT in $(map_get IMPORTS $FILEKEY); do
111
	NEXT_FILE="$(map_get EXPORTS $IMPORT)"
112
	if [ "x" = "x$NEXT_FILE" ]; then
113
	    errcho "nothing exports $IMPORT, required by $FILE"
114
	    return 1
115
	fi
116
	if ! compute_scripts_list_rec "$NEXT_FILE"; then
117
	    errcho "when satisfying $IMPORT for $FILE"
118
	    return 1
119
	fi
120
    done
121

  
122
    [ "x$FILE" = "xexports_init.js" ] || echo $FILE # exports_init.js is hardcoded to load first; the entire export system depends on it
123
    map_set FILESTATES $FILEKEY "processed"
124
}
125

  
126
compute_scripts_list() {
127
    USED=''
128
    echo COMPUTED_SCRIPTS=\"exports_init.js
129
    compute_scripts_list_rec "$1"
130
    echo \"
131

  
132
    for FILEKEY in $USED; do
133
	map_set_instr USED $FILEKEY yes
134
    done
135
}
8
. ./shell_utils.sh
136 9

  
137 10
as_json_list() {
138 11
    while true; do
139 12
	if [ "x" = "x$2" ]; then
140
	    echo -n '\\n'"\t\t\"$1\""'\\n\t'
13
	    printf '\\n\t\t"%s"\\n\t' "$1"
141 14
	    return
142 15
	fi
143
	echo -n '\\n'"\t\t\"$1\","
16
	printf '\\n\t\t"%s",' "$1"
144 17
	shift
145 18
    done
146 19
}
147 20

  
148 21
as_html_list() {
149 22
    while [ "x" != "x$1" ]; do
150
	echo -n '\\n'"    <script src=\"/$1\"></script>"
23
	printf '\\n    <script src="/%s"></script>' "$1"
151 24
	shift
152 25
    done
153 26
}
154 27

  
155
build_main() {
156
    # placate importers of these, as they are exported by the yet-to-be-created exports_init.js
157
    EXPORTS__browser=exports_init.js
158
    EXPORTS__is_chrome=exports_init.js
159
    EXPORTS__is_mozilla=exports_init.js
28
compute_scripts() {
29
    local DIRS="$1"
30
    local ROOT_SCRIPT="$2"
31

  
32
    local AVAILABLE="$(find $DIRS -name '[^.#]*.js')"
33

  
34
    awk -f compute_scripts.awk script_dependencies "$ROOT_SCRIPT" $AVAILABLE
35
}
160 36

  
161
    SCRIPTDIRS='background html common content'
37
build_main() {
38
    local ALL_SCRIPTDIRS='background html common content'
162 39

  
163
    SCRIPTS=$(find $SCRIPTDIRS -name '[^.#]*.js')
40
    local ALL_SCRIPTS_AVAILABLE="$(find $ALL_SCRIPTDIRS -name '[^.#]*.js')"
164 41

  
165
    for SCRIPT in $SCRIPTS; do
166
	add_exports $SCRIPT
167
	add_imports $SCRIPT
42
    local SCRIPT
43
    for SCRIPT in $ALL_SCRIPTS_AVAILABLE; do
44
	map_set SCRIPTS_UNUSED $(sanitize $SCRIPT) yes
168 45
    done
169 46

  
170
    eval "$(compute_scripts_list background/main.js || exit 1)"
171
    BGSCRIPTS="$(as_json_list $COMPUTED_SCRIPTS)"
172
    eval "$(compute_scripts_list content/main.js || exit 1)"
173
    CONTENTSCRIPTS="$(as_json_list $COMPUTED_SCRIPTS)"
174
    eval "$(compute_scripts_list html/display-panel.js || exit 1)"
175
    POPUPSCRIPTS="$(as_html_list $COMPUTED_SCRIPTS)"
176
    eval "$(compute_scripts_list html/options_main.js || exit 1)"
177
    OPTIONSSCRIPTS="$(as_html_list $COMPUTED_SCRIPTS)"
47
    local ROOT=background/main.js
48
    local SCRIPTS_BG="$(      compute_scripts 'common/ background/' $ROOT)"
49

  
50
    local ROOT=content/main.js
51
    local SCRIPTS_CONTENT="$( compute_scripts 'common/ content/'    $ROOT)"
52

  
53
    local ROOT=html/display-panel.js
54
    local SCRIPTS_POPUP="$(   compute_scripts 'common/ html/'       $ROOT)"
55

  
56
    local ROOT=html/options_main.js
57
    local SCRIPTS_OPTIONS="$( compute_scripts 'common/ html/'       $ROOT)"
178 58

  
179
    for DIR in $(find $SCRIPTDIRS -type d); do
59
    local BGSCRIPTS="$(      as_json_list $SCRIPTS_BG      )"
60
    local CONTENTSCRIPTS="$( as_json_list $SCRIPTS_CONTENT )"
61
    local POPUPSCRIPTS="$(   as_html_list $SCRIPTS_POPUP   )"
62
    local OPTIONSSCRIPTS="$( as_html_list $SCRIPTS_OPTIONS )"
63

  
64
    for SCRIPT in $SCRIPTS_BG $SCRIPTS_CONTENT $SCRIPTS_POPUP $SCRIPTS_OPTIONS
65
    do
66
	map_del SCRIPTS_UNUSED $(sanitize $SCRIPT)
67
    done
68

  
69
    for DIR in $(find $ALL_SCRIPTDIRS -type d); do
180 70
	mkdir -p "$BUILDDIR"/$DIR
181 71
    done
182 72

  
......
214 104
	sed "s^_OPTIONSSCRIPTS_^$OPTIONSSCRIPTS^" \
215 105
	    > "$BUILDDIR"/html/options.html
216 106

  
217
    for FILE in $SCRIPTS; do
107
    for FILE in $ALL_SCRIPTS_AVAILABLE; do
218 108
	FILEKEY=$(sanitize "$FILE")
219
	if [ "xyes" != "x$(map_get USED $FILEKEY)" ]; then
220
	    errcho "WARNING! $FILE not used"
109
	if [ "x$(map_get SCRIPTS_UNUSED $FILEKEY)" = "xyes" ]; then
110
	    printf 'WARNING! %s not used\n' "$FILE" >&2
221 111
	else
222
	    (echo "\
223
\"use strict\";
224

  
225
({fun: (function() {
226
$(map_get IMPORTCODES $FILEKEY)
227

  
228
";
229

  
230
# A hack to insert the contents of default_settings.json at the appropriate location in background/main.js
231
if [ "$FILE" = "background/main.js" ]; then
232
    # Uses an internal sed expression to escape and indent the JSON file for use in the external sed expression
233
    sed 's/^        `DEFAULT SETTINGS`$/'"$(sed -E 's/([\\\&\/])/\\\1/g; s/^/        /; s/$/\\/' < default_settings.json) "/g < "$FILE"
234
else
235
    cat $FILE
236
fi
237

  
238
echo "
239

  
240
$(map_get EXPORTCODES $FILEKEY)
241
})}).fun();") > "$BUILDDIR"/$FILE
112
	    awk -f compute_scripts.awk wrapped_code "$FILE" > "$BUILDDIR"/$FILE
242 113
	fi
243 114
    done
244 115

  
116
    # A hack to insert the contents of default_settings.json at the appropriate
117
    # location in background/main.js. Uses an internal sed expression to escape
118
    # and indent the JSON file for use in the external sed expression.
119
    sed -i 's/^        `DEFAULT SETTINGS`$/'"$(sed -E 's/([\\\&\/])/\\\1/g; s/^/        /; s/$/\\/' < default_settings.json) "/g "$BUILDDIR"/background/main.js
120

  
245 121
    if [ "$BROWSER" = "chromium" ]; then
246
	cat > "$BUILDDIR"/exports_init.js <<EOF
247
window.killtheweb={is_chrome: true, browser: window.chrome};
248
EOF
122
	cp CHROMIUM_exports_init.js "$BUILDDIR"/exports_init.js
249 123
    else
250
	cat > "$BUILDDIR"/exports_init.js <<EOF
251
/* Polyfill for IceCat 60. */
252
String.prototype.matchAll = String.prototype.matchAll || function(regex) {
253
    if (regex.flags.search("g") === -1)
254
        throw new TypeError("String.prototype.matchAll called with a non-global RegExp argument");
255

  
256
    for (const matches = [];;) {
257
        if (matches[matches.push(regex.exec(this)) - 1] === null)
258
	    return matches.splice(0, matches.length - 1);
259
    }
260
}
261

  
262
window.killtheweb={is_mozilla: true, browser: this.browser};
263
EOF
124
	cp MOZILLA_exports_init.js "$BUILDDIR"/exports_init.js
264 125
    fi
265 126

  
266 127
    cp -r copyright licenses/ "$BUILDDIR"
......
271 132

  
272 133
    if [ "$BROWSER" = "chromium" ]; then
273 134
	for MOZILLA_FILE in $(find "$BUILDDIR" -name "MOZILLA_*"); do
274
	    echo > "$MOZILLA_FILE"
135
	    printf '\n' > "$MOZILLA_FILE"
275 136
	done
276 137
    fi
277 138
    if [ "$BROWSER" = "mozilla" ]; then
278 139
	for CHROMIUM_FILE in $(find "$BUILDDIR" -name "CHROMIUM_*"); do
279
	    echo > "$CHROMIUM_FILE"
140
	    printf '\n' > "$CHROMIUM_FILE"
280 141
	done
281 142
    fi
282 143
}
283 144

  
145
print_usage() {
146
    printf 'usage:  %s mozilla|chromium [source directory] [update url]\n' \
147
	   "$0" >&2
148
}
149

  
284 150
main() {
285 151
    if [ "x$1" = "xmozilla" -o "x$1" = "xchromium" ]; then
286 152
	BROWSER=$1
287 153
    else
288
	errcho "usage:  $0 mozilla|chromium [source directory] [update url]"
154
	print_usage
289 155
	exit 1
290 156
    fi
291 157

  
......
296 162
	mkdir "$BUILDDIR"
297 163
	cd "$SRCDIR"
298 164
    else
299
	errcho "usage:  $0 mozilla|chromium [source directory] [update url]"
165
	print_usage
300 166
	exit 2
301 167
    fi
302 168

  
303 169
    UPDATE_URL="$3"
304 170

  
305
    . ./shell_utils.sh
306 171
    build_main
307 172
}
308 173

  
common/storage_light.js
13 13
 * IMPORT raw_storage
14 14
 * IMPORT is_mozilla
15 15
 * IMPORT observables
16
 * IMPORTS_END
16 17
 */
17 18

  
18 19
const reg_spec = new Set(["\\", "[", "]", "(", ")", "{", "}", ".", "*", "+"]);
compute_scripts.awk
1
# SPDX-License-Identifier: CC0-1.0
2
#
3
# Process javascript files and resolve dependencies between them
4
#
5
# This file is part of Haketilo
6
#
7
# Copyright (C) 2021, Wojtek Kosior
8
#
9
# This program is free software: you can redistribute it and/or modify
10
# it under the terms of the CC0 1.0 Universal License as published by
11
# the Creative Commons Corporation.
12
#
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
# CC0 1.0 Universal License for more details.
17

  
18
function read_file(filename,
19
		   imports_state, exports_state, line, record, result) {
20
    imports_state = "not_started"
21
    exports_state = "not_started"
22

  
23
    do {
24
	result = (getline line < filename)
25
	if (result < 0) {
26
	    printf "error reading %s", filename
27
	    exit 1
28
	}
29

  
30
	if (imports_state == "started" &&
31
	    line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORT[[:space:]]+[_a-zA-Z][_a-zA-Z0-9]*[[:space:]]*$/) {
32
	    record = line
33

  
34
	    sub(/^([[:space:]]*\*[[:space:]]+)?IMPORT[[:space:]]+/, "", record)
35
	    sub(/([[:space:]]+$)/,                                  "", record)
36

  
37
	    imports[filename,++import_counts[filename]] = record
38
	}
39
	if (imports_state == "started" &&
40
	    line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORTS_END[[:space:]]*$/)
41
	    imports_state = "finished"
42
	if (imports_state == "not_started" &&
43
	    line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORTS_START[[:space:]]*$/)
44
	    imports_state = "started"
45

  
46
	if (exports_state == "started" &&
47
	    line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORT[[:space:]]+[_a-zA-Z][_a-zA-Z0-9]*[[:space:]]*$/) {
48
	    record = line
49

  
50
	    sub(/^([[:space:]]*\*[[:space:]]+)?EXPORT[[:space:]]+/, "", record)
51
	    sub(/([[:space:]]+$)/,                                  "", record)
52

  
53
	    if (record in exports) {
54
		printf "ERROR: '%s' exported by both %s and %s\n",
55
		    exports[record], filename > "/dev/stderr"
56
	    }
57

  
58
	    provides[record] = filename
59
	    exports[filename,++export_counts[filename]] = record
60
	}
61
	if (exports_state == "started" &&
62
	    line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORTS_END[[:space:]]*$/)
63
	    exports_state = "finished"
64
	if (exports_state == "not_started" &&
65
	    line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORTS_START[[:space:]]*$/)
66
	    exports_state = "started"
67
    } while (result > 0)
68

  
69
    if (imports_state == "started") {
70
	printf "ERROR: Unclosed IMPORTS list in '%s'\n", filename	\
71
	    > "/dev/stderr"
72
	exit 1
73
    }
74

  
75
    if (exports_state == "started") {
76
	printf "ERROR: Unclosed EXPORTS list in '%s'\n", filename	\
77
	    > "/dev/stderr"
78
	exit 1
79
    }
80

  
81
    close(filename)
82
}
83

  
84
function print_file(filename,    line) {
85
    while ((getline line < filename) > 0)
86
	print(line)
87

  
88
    close(filename)
89
}
90

  
91
function print_imports_code(filename,    i, count, import_name) {
92
    count = import_counts[filename]
93
    for (i = 1; i <= count; i++) {
94
	import_name = imports[filename,i]
95
	printf "const %s = window.killtheweb.%s;\n", import_name, import_name
96
    }
97
}
98

  
99
function print_exports_code(filename,    i, count, export_name) {
100
    count = export_counts[filename]
101
    for (i = 1; i <= count; i++) {
102
	export_name = exports[filename,i]
103
	printf "window.killtheweb.%s = %s;\n", export_name, export_name
104
    }
105
}
106

  
107
function wrap_file(filename) {
108
    print "\"use strict\";\n\n({fun: (function() {\n"
109
    print_imports_code(filename)
110
    printf "\n\n"
111

  
112
    print_file(filename)
113

  
114
    printf "\n\n"
115
    print_exports_code(filename)
116
    print "\n})}).fun();"
117
}
118

  
119
function compute_dependencies(filename,    i, count, import_name, next_file) {
120
    if (processed[filename] == "used")
121
	return 0
122

  
123
    if (processed[filename] == "on_stack") {
124
	printf "import loop on %s\n", filename > "/dev/stderr"
125
	return 1
126
    }
127

  
128
    processed[filename] = "on_stack"
129

  
130
    count = import_counts[filename]
131
    for (i = 1; i <= count; i++) {
132
	import_name = imports[filename,i]
133
	if (!(import_name in provides)) {
134
	    printf "nothing exports %s, required by %s\n",
135
		import_name, filename > "/dev/stderr"
136
	    return 1
137
	}
138

  
139
	if (compute_dependencies(provides[import_name]) > 0) {
140
	    printf "when satisfying %s for %s\n",
141
		import_name, filename > "/dev/stderr"
142
	    return 1
143
	}
144
    }
145

  
146
    processed[filename] = "used"
147
    print filename
148

  
149
    return 0
150
}
151

  
152
function print_usage() {
153
    printf "usage:  %2 compute_scripts.awk script_dependencies|wrapped_code FILENAME[...]\n",
154
	ARGV[0] > "/dev/stderr"
155
    exit 1
156
}
157

  
158
function mock_exports_init() {
159
    provides["browser"]    = "exports_init.js"
160
    provides["is_chrome"]  = "exports_init.js"
161
    provides["is_mozilla"] = "exports_init.js"
162

  
163
    processed["exports_init.js"] = "used"
164
}
165

  
166
BEGIN {
167
    operation = ARGV[1]
168

  
169
    if (ARGC < 3)
170
	print_usage()
171

  
172
    root_filename = ARGV[2]
173

  
174
    for (i = 2; i < ARGC; i++)
175
	filenames[ARGV[i]]
176

  
177
    mock_exports_init()
178

  
179
    for (filename in filenames) {
180
	# A filename is allowed to appear multiple times in the list.
181
	# Let's only process it once.
182
	if (!(filename in processed))
183
	    read_file(filename)
184
	processed[filename] = "not_used"
185
    }
186

  
187
    if (operation == "script_dependencies") {
188
	print("exports_init.js")
189
	if (compute_dependencies(root_filename) > 0)
190
	    exit 1
191
    } else if (operation == "wrapped_code") {
192
	wrap_file(root_filename)
193
    } else {
194
	print_usage()
195
    }
196
}
copyright
6 6
Copyright: 2021 Wojtek Kosior <koszko@koszko.org>
7 7
License: GPL-3+-javascript or Alicense-1.0
8 8

  
9
Files: *.sh default_settings.json Makefile.in
9
Files: *.sh default_settings.json Makefile.in compute_scripts.awk
10
       CHROMIUM_exports_init.js
10 11
Copyright: 2021 Wojtek Kosior <koszko@koszko.org>
11 12
   2021 jahoti <jahoti@tilde.team>
12 13
License: CC0
process_html_file.sh
12 12
FILEKEY=$(sanitize "$FILE")
13 13

  
14 14
if [ "x$(map_get HTML_FILENAMES $FILEKEY)" = "xyes" ]; then
15
    errcho "import loop on $FILE"
15
    printf 'import loop on %s\n' "$FILE" >&2
16 16
    exit 1
17 17
fi
18 18

  
shell_utils.sh
3 3

  
4 4
# This file is meant to be sourced in sh.
5 5

  
6
ENDL="
7
"
8

  
9
# A "raw" echo, interprets neither backclash escapes nor command-line options.
10
# Does not emit trailing newline.
11
ech() {
12
    printf %s "$*"
13
}
14

  
15
errcho() {
16
    echo "$@" >&2
17
}
18

  
19 6
map_set_instr() {
20
    echo "$1__$2='$3'"
7
    printf "%s__%s='%s'" "$1" "$2" "$3"
21 8
}
22 9

  
23 10
map_set() {
......
29 16
}
30 17

  
31 18
map_get() {
32
    eval "echo \"\$$1__$2\""
19
    eval "printf %s \"\$$1__$2\""
33 20
}
34 21

  
35 22
map_del_instr() {
36
    echo "unset $1__$2"
23
    printf 'unset %s__%s' "$1" "$2"
37 24
}
38 25

  
39 26
map_del() {
......
41 28
}
42 29

  
43 30
sanitize() {
44
    echo "$1" | tr /.- _
31
    printf %s "$1" | tr /.- _
45 32
}
46 33

  
47 34
escape_regex_special() {
48
    ech "$1" | sed 's/\([]\.*?{},()[-]\)/\\\1/g'
35
    printf %s "$1" | sed 's/\([]\.*?{},()[-]\)/\\\1/g'
49 36
}
50 37

  
51 38
# Note: We don't actually parse JSON. We extract needed keys with sed regexes
52 39
# which does not work in the general case but is sufficient for now.
53 40
get_json_key() {
54 41
    local KEY_REG="$(escape_regex_special "$1")"
55
    ech "$2" |
42
    printf %s "$2" |
56 43
	sed 's/\(.*"'"$KEY_REG"'"[[:space:]]*:[[:space:]]*"\([^"]*\)"\)\?.*/\2/' |
57 44
	grep . | head -1
58 45
}
upload_amo.sh
24 24
XPI_PATH="$4"
25 25

  
26 26
base64url() {
27
    ech "$1" | base64 -w 0 | tr '/+' '_-' | tr -d '='
27
    printf %s "$1" | base64 -w 0 | tr '/+' '_-' | tr -d '='
28 28
}
29 29

  
30 30
sha256hmac() {
31
    base64url "$(ech "$2" | openssl dgst -sha256 -hmac "$1" -binary -)"
31
    base64url "$(printf %s "$2" | openssl dgst -sha256 -hmac "$1" -binary -)"
32 32
}
33 33

  
34 34
get_manifest_key() {
......
52 52
    local JWT_MESSAGE=$(base64url "$JWT_HEAD").$(base64url "$JWT_PAYLOAD")
53 53
    local JWT_SIGNATURE=$(sha256hmac "$SECRET" "$JWT_MESSAGE")
54 54
    local JWT=$JWT_MESSAGE.$JWT_SIGNATURE
55
    errcho "Using JWT: $JWT"
56
    ech $JWT
55
    printf "Using JWT: $JWT\n" >&2
56
    printf $JWT
57 57
}
58 58

  
59 59
get_extension_url() {
......
61 61
    EXTENSION_VER="$(get_manifest_key version "$XPI_PATH")"
62 62

  
63 63
    if [ -z "$EXTENSION_ID" -o -z "$EXTENSION_VER" ]; then
64
	errcho "Couldn't extract extension id and version. Please check if $XPI_PATH contains proper manifest.json file."
64
	printf "Couldn't extract extension id and version. Please check if %s contains proper manifest.json file.\n" \
65
	       "$XPI_PATH" >&2
65 66
	exit 1
66 67
    fi
67 68

  
68
    ech "https://addons.mozilla.org/api/v4/addons/$EXTENSION_ID/versions/$EXTENSION_VER/"
69
    printf 'https://addons.mozilla.org/api/v4/addons/%s/versions/%s/' \
70
	   "$EXTENSION_ID" "$EXTENSION_VER"
69 71
}
70 72

  
71
usage() {
72
   errcho "Usage:  $_PROG_NAME upload|check|test API_KEY SECRET XPI_PATH"
73
print_usage() {
74
    printf 'Usage:  %s upload|check|test API_KEY SECRET XPI_PATH\n' \
75
	   "$_PROG_NAME" >&2
73 76
}
74 77

  
75 78
if [ $# != 4 ]; then
76
    usage
79
    print_usage
77 80
    exit 1
78 81
fi
79 82

  
......
83 86
    test)
84 87
	curl "https://addons.mozilla.org/api/v4/accounts/profile/" \
85 88
	     -g -H "Authorization: JWT $(generate_jwt)"
86
	echo
89
	printf '\n'
87 90
	;;
88 91
    check)
89 92
	RETURNED_DATA="$(curl $(get_extension_url) \
......
95 98
			      -H "Authorization: JWT $(generate_jwt)")"
96 99
	;;
97 100
    *)
98
	usage
101
	print_usage
99 102
	exit 1
100 103
	;;
101 104
esac
write_makefile.sh
14 14
# CC0 1.0 Universal License for more details.
15 15

  
16 16
if [ ! -e record.conf ]; then
17
    echo "Record of configuration 'record.conf' does not exist." >&2
17
    printf "Record of configuration 'record.conf' does not exist.\n" >&2
18 18
    exit 1
19 19
elif [ "$(head -n 1 record.conf | cut -c -9)x" != "srcdir = x" ]; then
20
    echo "Record of configuration 'record.conf' is invalid." >&2
20
    printf "Record of configuration 'record.conf' is invalid.\n" >&2
21 21
    exit 2
22 22
fi
23 23

  

Also available in: Unified diff