aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojtek Kosior <koszko@koszko.org>2021-11-30 19:31:49 +0100
committerWojtek Kosior <koszko@koszko.org>2021-11-30 19:32:21 +0100
commit6106c789ee818fd18240fd3f99eead598406852f (patch)
treef575e45b7872b7f85b33210db5e01caf7572c615
parent5b2a7a61fd5cf9982f105a3081c2ed7a298b71df (diff)
downloadbrowser-extension-6106c789ee818fd18240fd3f99eead598406852f.tar.gz
browser-extension-6106c789ee818fd18240fd3f99eead598406852f.zip
rewrite parts of build script in awk
-rw-r--r--CHROMIUM_exports_init.js3
-rw-r--r--MOZILLA_exports_init.js57
-rwxr-xr-xbuild.sh257
-rw-r--r--common/storage_light.js1
-rw-r--r--compute_scripts.awk196
-rw-r--r--copyright3
-rwxr-xr-xprocess_html_file.sh2
-rw-r--r--shell_utils.sh25
-rwxr-xr-xupload_amo.sh25
-rwxr-xr-xwrite_makefile.sh4
10 files changed, 343 insertions, 230 deletions
diff --git a/CHROMIUM_exports_init.js b/CHROMIUM_exports_init.js
new file mode 100644
index 0000000..d2ca065
--- /dev/null
+++ b/CHROMIUM_exports_init.js
@@ -0,0 +1,3 @@
+// SPDX-License-Identifier: CC0-1.0
+
+window.killtheweb={is_chrome: true, browser: window.chrome};
diff --git a/MOZILLA_exports_init.js b/MOZILLA_exports_init.js
new file mode 100644
index 0000000..0015f0c
--- /dev/null
+++ b/MOZILLA_exports_init.js
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/**
+ * This file is part of Haketilo.
+ *
+ * Function: Data structure to query items by URL patterns.
+ *
+ * Copyright (C) 2021 Wojtek Kosior
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * As additional permission under GNU GPL version 3 section 7, you
+ * may distribute forms of that code without the copy of the GNU
+ * GPL normally required by section 4, provided you include this
+ * license notice and, in case of non-source distribution, a URL
+ * through which recipients can access the Corresponding Source.
+ * If you modify file(s) with this exception, you may extend this
+ * exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ *
+ * As a special exception to the GPL, any HTML file which merely
+ * makes function calls to this code, and for that purpose
+ * includes it by reference shall be deemed a separate work for
+ * copyright law purposes. If you modify this code, you may extend
+ * this exception to your version of the code, but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
+ * license. Although I request that you do not make use this code in a
+ * proprietary program, I am not going to enforce this in court.
+ */
+
+/* Polyfill for IceCat 60. */
+String.prototype.matchAll = String.prototype.matchAll || function(regex) {
+ if (regex.flags.search("g") === -1)
+ throw new TypeError("String.prototype.matchAll called with a non-global RegExp argument");
+
+ for (const matches = [];;) {
+ if (matches[matches.push(regex.exec(this)) - 1] === null)
+ return matches.splice(0, matches.length - 1);
+ }
+}
+
+window.killtheweb={is_mozilla: true, browser: this.browser};
diff --git a/build.sh b/build.sh
index ed6a141..3d3d4be 100755
--- a/build.sh
+++ b/build.sh
@@ -3,180 +3,70 @@
# Copyright (C) 2021 Wojtek Kosior
# Redistribution terms are gathered in the `copyright' file.
-handle_export_line() {
- if [ "x$1" = "xEXPORTS_START" ]; then
- if [ "$STATE" = "before_block" ]; then
- STATE="in_block"
- fi
- elif [ "x$1" = "xEXPORT" ]; then
- if [ "$STATE" != "in_block" ]; then
- return
- fi
-
- EXPORTCODE="${EXPORTCODE}window.killtheweb.$2 = $2;$ENDL"
-
- PREVIOUS_FILE="$(map_get EXPORTS $2)"
- if [ "x$PREVIOUS_FILE" != "x" ]; then
- errcho "export $2 present in both $PREVIOUS_FILE and $FILE"
- return 1
- fi
-
- map_set_instr EXPORTS $2 "$FILE"
-
- elif [ "x$1" = "xEXPORTS_END" ]; then
- if [ "$STATE" = "in_block" ]; then
- STATE="after_block"
- fi
- fi
-}
-
-translate_exports() {
- STATE="before_block"
- EXPORTCODE=''
-
- while read EXPORT_LINE; do
- handle_export_line $EXPORT_LINE || return 1
- done
-
- map_set_instr EXPORTCODES $FILEKEY "$EXPORTCODE"
-}
-
-add_exports() {
- FILE="$1"
- FILEKEY="$(sanitize "$FILE")"
-
- eval "$(grep -o 'EXPORT.\+' "$1" | translate_exports || exit 1)"
-}
-
-handle_import_line() {
- if [ "x$1" = "xIMPORTS_START" ]; then
- if [ "$STATE" = "before_block" ]; then
- STATE="in_block"
- fi
- elif [ "x$1" = "xIMPORT" ]; then
- if [ "$STATE" != "in_block" ]; then
- return
- fi
-
- IMPORTCODE="${IMPORTCODE}const $2 = window.killtheweb.$2;$ENDL"
-
- IMPORTS="$IMPORTS $2"
-
- elif [ "x$1" = "xIMPORTS_END" ]; then
- if [ "$STATE" = "in_block" ]; then
- STATE="after_block"
- fi
- fi
-}
-
-translate_imports() {
- STATE="before_block"
- IMPORTCODE=''
- IMPORTS=''
-
- while read IMPORT_LINE; do
- handle_import_line $IMPORT_LINE || return 1
- done
-
- map_set_instr IMPORTCODES $FILEKEY "$IMPORTCODE"
- map_set_instr IMPORTS $FILEKEY "$IMPORTS"
-}
-
-add_imports() {
- FILE="$1"
- FILEKEY="$(sanitize "$FILE")"
-
- eval "$(grep -o 'IMPORT.\+' "$1" | translate_imports || exit 1)"
-}
+set -e
-compute_scripts_list_rec() {
- local FILE="$1"
- local FILEKEY=$(sanitize "$1")
-
- local FILESTATE="$(map_get FILESTATES $FILEKEY)"
- if [ "xprocessed" = "x$FILESTATE" ]; then
- return
- fi
- if [ "xprocessing" = "x$FILESTATE" ]; then
- errcho "import loop on $FILE"
- return 1
- fi
-
- USED="$USED $FILEKEY"
-
- map_set FILESTATES $FILEKEY "processing"
-
- local IMPORT
- for IMPORT in $(map_get IMPORTS $FILEKEY); do
- NEXT_FILE="$(map_get EXPORTS $IMPORT)"
- if [ "x" = "x$NEXT_FILE" ]; then
- errcho "nothing exports $IMPORT, required by $FILE"
- return 1
- fi
- if ! compute_scripts_list_rec "$NEXT_FILE"; then
- errcho "when satisfying $IMPORT for $FILE"
- return 1
- fi
- done
-
- [ "x$FILE" = "xexports_init.js" ] || echo $FILE # exports_init.js is hardcoded to load first; the entire export system depends on it
- map_set FILESTATES $FILEKEY "processed"
-}
-
-compute_scripts_list() {
- USED=''
- echo COMPUTED_SCRIPTS=\"exports_init.js
- compute_scripts_list_rec "$1"
- echo \"
-
- for FILEKEY in $USED; do
- map_set_instr USED $FILEKEY yes
- done
-}
+. ./shell_utils.sh
as_json_list() {
while true; do
if [ "x" = "x$2" ]; then
- echo -n '\\n'"\t\t\"$1\""'\\n\t'
+ printf '\\n\t\t"%s"\\n\t' "$1"
return
fi
- echo -n '\\n'"\t\t\"$1\","
+ printf '\\n\t\t"%s",' "$1"
shift
done
}
as_html_list() {
while [ "x" != "x$1" ]; do
- echo -n '\\n'" <script src=\"/$1\"></script>"
+ printf '\\n <script src="/%s"></script>' "$1"
shift
done
}
-build_main() {
- # placate importers of these, as they are exported by the yet-to-be-created exports_init.js
- EXPORTS__browser=exports_init.js
- EXPORTS__is_chrome=exports_init.js
- EXPORTS__is_mozilla=exports_init.js
+compute_scripts() {
+ local DIRS="$1"
+ local ROOT_SCRIPT="$2"
+
+ local AVAILABLE="$(find $DIRS -name '[^.#]*.js')"
+
+ awk -f compute_scripts.awk script_dependencies "$ROOT_SCRIPT" $AVAILABLE
+}
- SCRIPTDIRS='background html common content'
+build_main() {
+ local ALL_SCRIPTDIRS='background html common content'
- SCRIPTS=$(find $SCRIPTDIRS -name '[^.#]*.js')
+ local ALL_SCRIPTS_AVAILABLE="$(find $ALL_SCRIPTDIRS -name '[^.#]*.js')"
- for SCRIPT in $SCRIPTS; do
- add_exports $SCRIPT
- add_imports $SCRIPT
+ local SCRIPT
+ for SCRIPT in $ALL_SCRIPTS_AVAILABLE; do
+ map_set SCRIPTS_UNUSED $(sanitize $SCRIPT) yes
done
- eval "$(compute_scripts_list background/main.js || exit 1)"
- BGSCRIPTS="$(as_json_list $COMPUTED_SCRIPTS)"
- eval "$(compute_scripts_list content/main.js || exit 1)"
- CONTENTSCRIPTS="$(as_json_list $COMPUTED_SCRIPTS)"
- eval "$(compute_scripts_list html/display-panel.js || exit 1)"
- POPUPSCRIPTS="$(as_html_list $COMPUTED_SCRIPTS)"
- eval "$(compute_scripts_list html/options_main.js || exit 1)"
- OPTIONSSCRIPTS="$(as_html_list $COMPUTED_SCRIPTS)"
+ local ROOT=background/main.js
+ local SCRIPTS_BG="$( compute_scripts 'common/ background/' $ROOT)"
+
+ local ROOT=content/main.js
+ local SCRIPTS_CONTENT="$( compute_scripts 'common/ content/' $ROOT)"
+
+ local ROOT=html/display-panel.js
+ local SCRIPTS_POPUP="$( compute_scripts 'common/ html/' $ROOT)"
+
+ local ROOT=html/options_main.js
+ local SCRIPTS_OPTIONS="$( compute_scripts 'common/ html/' $ROOT)"
- for DIR in $(find $SCRIPTDIRS -type d); do
+ local BGSCRIPTS="$( as_json_list $SCRIPTS_BG )"
+ local CONTENTSCRIPTS="$( as_json_list $SCRIPTS_CONTENT )"
+ local POPUPSCRIPTS="$( as_html_list $SCRIPTS_POPUP )"
+ local OPTIONSSCRIPTS="$( as_html_list $SCRIPTS_OPTIONS )"
+
+ for SCRIPT in $SCRIPTS_BG $SCRIPTS_CONTENT $SCRIPTS_POPUP $SCRIPTS_OPTIONS
+ do
+ map_del SCRIPTS_UNUSED $(sanitize $SCRIPT)
+ done
+
+ for DIR in $(find $ALL_SCRIPTDIRS -type d); do
mkdir -p "$BUILDDIR"/$DIR
done
@@ -214,53 +104,24 @@ s^_CONTENTSCRIPTS_^$CONTENTSCRIPTS^" \
sed "s^_OPTIONSSCRIPTS_^$OPTIONSSCRIPTS^" \
> "$BUILDDIR"/html/options.html
- for FILE in $SCRIPTS; do
+ for FILE in $ALL_SCRIPTS_AVAILABLE; do
FILEKEY=$(sanitize "$FILE")
- if [ "xyes" != "x$(map_get USED $FILEKEY)" ]; then
- errcho "WARNING! $FILE not used"
+ if [ "x$(map_get SCRIPTS_UNUSED $FILEKEY)" = "xyes" ]; then
+ printf 'WARNING! %s not used\n' "$FILE" >&2
else
- (echo "\
-\"use strict\";
-
-({fun: (function() {
-$(map_get IMPORTCODES $FILEKEY)
-
-";
-
-# A hack to insert the contents of default_settings.json at the appropriate location in background/main.js
-if [ "$FILE" = "background/main.js" ]; then
- # Uses an internal sed expression to escape and indent the JSON file for use in the external sed expression
- sed 's/^ `DEFAULT SETTINGS`$/'"$(sed -E 's/([\\\&\/])/\\\1/g; s/^/ /; s/$/\\/' < default_settings.json) "/g < "$FILE"
-else
- cat $FILE
-fi
-
-echo "
-
-$(map_get EXPORTCODES $FILEKEY)
-})}).fun();") > "$BUILDDIR"/$FILE
+ awk -f compute_scripts.awk wrapped_code "$FILE" > "$BUILDDIR"/$FILE
fi
done
+ # A hack to insert the contents of default_settings.json at the appropriate
+ # location in background/main.js. Uses an internal sed expression to escape
+ # and indent the JSON file for use in the external sed expression.
+ sed -i 's/^ `DEFAULT SETTINGS`$/'"$(sed -E 's/([\\\&\/])/\\\1/g; s/^/ /; s/$/\\/' < default_settings.json) "/g "$BUILDDIR"/background/main.js
+
if [ "$BROWSER" = "chromium" ]; then
- cat > "$BUILDDIR"/exports_init.js <<EOF
-window.killtheweb={is_chrome: true, browser: window.chrome};
-EOF
+ cp CHROMIUM_exports_init.js "$BUILDDIR"/exports_init.js
else
- cat > "$BUILDDIR"/exports_init.js <<EOF
-/* Polyfill for IceCat 60. */
-String.prototype.matchAll = String.prototype.matchAll || function(regex) {
- if (regex.flags.search("g") === -1)
- throw new TypeError("String.prototype.matchAll called with a non-global RegExp argument");
-
- for (const matches = [];;) {
- if (matches[matches.push(regex.exec(this)) - 1] === null)
- return matches.splice(0, matches.length - 1);
- }
-}
-
-window.killtheweb={is_mozilla: true, browser: this.browser};
-EOF
+ cp MOZILLA_exports_init.js "$BUILDDIR"/exports_init.js
fi
cp -r copyright licenses/ "$BUILDDIR"
@@ -271,21 +132,26 @@ EOF
if [ "$BROWSER" = "chromium" ]; then
for MOZILLA_FILE in $(find "$BUILDDIR" -name "MOZILLA_*"); do
- echo > "$MOZILLA_FILE"
+ printf '\n' > "$MOZILLA_FILE"
done
fi
if [ "$BROWSER" = "mozilla" ]; then
for CHROMIUM_FILE in $(find "$BUILDDIR" -name "CHROMIUM_*"); do
- echo > "$CHROMIUM_FILE"
+ printf '\n' > "$CHROMIUM_FILE"
done
fi
}
+print_usage() {
+ printf 'usage: %s mozilla|chromium [source directory] [update url]\n' \
+ "$0" >&2
+}
+
main() {
if [ "x$1" = "xmozilla" -o "x$1" = "xchromium" ]; then
BROWSER=$1
else
- errcho "usage: $0 mozilla|chromium [source directory] [update url]"
+ print_usage
exit 1
fi
@@ -296,13 +162,12 @@ main() {
mkdir "$BUILDDIR"
cd "$SRCDIR"
else
- errcho "usage: $0 mozilla|chromium [source directory] [update url]"
+ print_usage
exit 2
fi
UPDATE_URL="$3"
- . ./shell_utils.sh
build_main
}
diff --git a/common/storage_light.js b/common/storage_light.js
index 32e3b1f..246e5eb 100644
--- a/common/storage_light.js
+++ b/common/storage_light.js
@@ -13,6 +13,7 @@
* IMPORT raw_storage
* IMPORT is_mozilla
* IMPORT observables
+ * IMPORTS_END
*/
const reg_spec = new Set(["\\", "[", "]", "(", ")", "{", "}", ".", "*", "+"]);
diff --git a/compute_scripts.awk b/compute_scripts.awk
new file mode 100644
index 0000000..123106c
--- /dev/null
+++ b/compute_scripts.awk
@@ -0,0 +1,196 @@
+# SPDX-License-Identifier: CC0-1.0
+#
+# Process javascript files and resolve dependencies between them
+#
+# This file is part of Haketilo
+#
+# Copyright (C) 2021, Wojtek Kosior
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the CC0 1.0 Universal License as published by
+# the Creative Commons Corporation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# CC0 1.0 Universal License for more details.
+
+function read_file(filename,
+ imports_state, exports_state, line, record, result) {
+ imports_state = "not_started"
+ exports_state = "not_started"
+
+ do {
+ result = (getline line < filename)
+ if (result < 0) {
+ printf "error reading %s", filename
+ exit 1
+ }
+
+ if (imports_state == "started" &&
+ line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORT[[:space:]]+[_a-zA-Z][_a-zA-Z0-9]*[[:space:]]*$/) {
+ record = line
+
+ sub(/^([[:space:]]*\*[[:space:]]+)?IMPORT[[:space:]]+/, "", record)
+ sub(/([[:space:]]+$)/, "", record)
+
+ imports[filename,++import_counts[filename]] = record
+ }
+ if (imports_state == "started" &&
+ line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORTS_END[[:space:]]*$/)
+ imports_state = "finished"
+ if (imports_state == "not_started" &&
+ line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORTS_START[[:space:]]*$/)
+ imports_state = "started"
+
+ if (exports_state == "started" &&
+ line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORT[[:space:]]+[_a-zA-Z][_a-zA-Z0-9]*[[:space:]]*$/) {
+ record = line
+
+ sub(/^([[:space:]]*\*[[:space:]]+)?EXPORT[[:space:]]+/, "", record)
+ sub(/([[:space:]]+$)/, "", record)
+
+ if (record in exports) {
+ printf "ERROR: '%s' exported by both %s and %s\n",
+ exports[record], filename > "/dev/stderr"
+ }
+
+ provides[record] = filename
+ exports[filename,++export_counts[filename]] = record
+ }
+ if (exports_state == "started" &&
+ line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORTS_END[[:space:]]*$/)
+ exports_state = "finished"
+ if (exports_state == "not_started" &&
+ line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORTS_START[[:space:]]*$/)
+ exports_state = "started"
+ } while (result > 0)
+
+ if (imports_state == "started") {
+ printf "ERROR: Unclosed IMPORTS list in '%s'\n", filename \
+ > "/dev/stderr"
+ exit 1
+ }
+
+ if (exports_state == "started") {
+ printf "ERROR: Unclosed EXPORTS list in '%s'\n", filename \
+ > "/dev/stderr"
+ exit 1
+ }
+
+ close(filename)
+}
+
+function print_file(filename, line) {
+ while ((getline line < filename) > 0)
+ print(line)
+
+ close(filename)
+}
+
+function print_imports_code(filename, i, count, import_name) {
+ count = import_counts[filename]
+ for (i = 1; i <= count; i++) {
+ import_name = imports[filename,i]
+ printf "const %s = window.killtheweb.%s;\n", import_name, import_name
+ }
+}
+
+function print_exports_code(filename, i, count, export_name) {
+ count = export_counts[filename]
+ for (i = 1; i <= count; i++) {
+ export_name = exports[filename,i]
+ printf "window.killtheweb.%s = %s;\n", export_name, export_name
+ }
+}
+
+function wrap_file(filename) {
+ print "\"use strict\";\n\n({fun: (function() {\n"
+ print_imports_code(filename)
+ printf "\n\n"
+
+ print_file(filename)
+
+ printf "\n\n"
+ print_exports_code(filename)
+ print "\n})}).fun();"
+}
+
+function compute_dependencies(filename, i, count, import_name, next_file) {
+ if (processed[filename] == "used")
+ return 0
+
+ if (processed[filename] == "on_stack") {
+ printf "import loop on %s\n", filename > "/dev/stderr"
+ return 1
+ }
+
+ processed[filename] = "on_stack"
+
+ count = import_counts[filename]
+ for (i = 1; i <= count; i++) {
+ import_name = imports[filename,i]
+ if (!(import_name in provides)) {
+ printf "nothing exports %s, required by %s\n",
+ import_name, filename > "/dev/stderr"
+ return 1
+ }
+
+ if (compute_dependencies(provides[import_name]) > 0) {
+ printf "when satisfying %s for %s\n",
+ import_name, filename > "/dev/stderr"
+ return 1
+ }
+ }
+
+ processed[filename] = "used"
+ print filename
+
+ return 0
+}
+
+function print_usage() {
+ printf "usage: %2 compute_scripts.awk script_dependencies|wrapped_code FILENAME[...]\n",
+ ARGV[0] > "/dev/stderr"
+ exit 1
+}
+
+function mock_exports_init() {
+ provides["browser"] = "exports_init.js"
+ provides["is_chrome"] = "exports_init.js"
+ provides["is_mozilla"] = "exports_init.js"
+
+ processed["exports_init.js"] = "used"
+}
+
+BEGIN {
+ operation = ARGV[1]
+
+ if (ARGC < 3)
+ print_usage()
+
+ root_filename = ARGV[2]
+
+ for (i = 2; i < ARGC; i++)
+ filenames[ARGV[i]]
+
+ mock_exports_init()
+
+ for (filename in filenames) {
+ # A filename is allowed to appear multiple times in the list.
+ # Let's only process it once.
+ if (!(filename in processed))
+ read_file(filename)
+ processed[filename] = "not_used"
+ }
+
+ if (operation == "script_dependencies") {
+ print("exports_init.js")
+ if (compute_dependencies(root_filename) > 0)
+ exit 1
+ } else if (operation == "wrapped_code") {
+ wrap_file(root_filename)
+ } else {
+ print_usage()
+ }
+}
diff --git a/copyright b/copyright
index 81f9966..a238d33 100644
--- a/copyright
+++ b/copyright
@@ -6,7 +6,8 @@ Files: *
Copyright: 2021 Wojtek Kosior <koszko@koszko.org>
License: GPL-3+-javascript or Alicense-1.0
-Files: *.sh default_settings.json Makefile.in
+Files: *.sh default_settings.json Makefile.in compute_scripts.awk
+ CHROMIUM_exports_init.js
Copyright: 2021 Wojtek Kosior <koszko@koszko.org>
2021 jahoti <jahoti@tilde.team>
License: CC0
diff --git a/process_html_file.sh b/process_html_file.sh
index 1ed0295..2f58cbf 100755
--- a/process_html_file.sh
+++ b/process_html_file.sh
@@ -12,7 +12,7 @@ FILE="$1"
FILEKEY=$(sanitize "$FILE")
if [ "x$(map_get HTML_FILENAMES $FILEKEY)" = "xyes" ]; then
- errcho "import loop on $FILE"
+ printf 'import loop on %s\n' "$FILE" >&2
exit 1
fi
diff --git a/shell_utils.sh b/shell_utils.sh
index 5fd24ff..6d4cc76 100644
--- a/shell_utils.sh
+++ b/shell_utils.sh
@@ -3,21 +3,8 @@
# This file is meant to be sourced in sh.
-ENDL="
-"
-
-# A "raw" echo, interprets neither backclash escapes nor command-line options.
-# Does not emit trailing newline.
-ech() {
- printf %s "$*"
-}
-
-errcho() {
- echo "$@" >&2
-}
-
map_set_instr() {
- echo "$1__$2='$3'"
+ printf "%s__%s='%s'" "$1" "$2" "$3"
}
map_set() {
@@ -29,11 +16,11 @@ map_set_export() {
}
map_get() {
- eval "echo \"\$$1__$2\""
+ eval "printf %s \"\$$1__$2\""
}
map_del_instr() {
- echo "unset $1__$2"
+ printf 'unset %s__%s' "$1" "$2"
}
map_del() {
@@ -41,18 +28,18 @@ map_del() {
}
sanitize() {
- echo "$1" | tr /.- _
+ printf %s "$1" | tr /.- _
}
escape_regex_special() {
- ech "$1" | sed 's/\([]\.*?{},()[-]\)/\\\1/g'
+ printf %s "$1" | sed 's/\([]\.*?{},()[-]\)/\\\1/g'
}
# Note: We don't actually parse JSON. We extract needed keys with sed regexes
# which does not work in the general case but is sufficient for now.
get_json_key() {
local KEY_REG="$(escape_regex_special "$1")"
- ech "$2" |
+ printf %s "$2" |
sed 's/\(.*"'"$KEY_REG"'"[[:space:]]*:[[:space:]]*"\([^"]*\)"\)\?.*/\2/' |
grep . | head -1
}
diff --git a/upload_amo.sh b/upload_amo.sh
index 115f39a..71e12ca 100755
--- a/upload_amo.sh
+++ b/upload_amo.sh
@@ -24,11 +24,11 @@ SECRET="$3"
XPI_PATH="$4"
base64url() {
- ech "$1" | base64 -w 0 | tr '/+' '_-' | tr -d '='
+ printf %s "$1" | base64 -w 0 | tr '/+' '_-' | tr -d '='
}
sha256hmac() {
- base64url "$(ech "$2" | openssl dgst -sha256 -hmac "$1" -binary -)"
+ base64url "$(printf %s "$2" | openssl dgst -sha256 -hmac "$1" -binary -)"
}
get_manifest_key() {
@@ -52,8 +52,8 @@ EOF
local JWT_MESSAGE=$(base64url "$JWT_HEAD").$(base64url "$JWT_PAYLOAD")
local JWT_SIGNATURE=$(sha256hmac "$SECRET" "$JWT_MESSAGE")
local JWT=$JWT_MESSAGE.$JWT_SIGNATURE
- errcho "Using JWT: $JWT"
- ech $JWT
+ printf "Using JWT: $JWT\n" >&2
+ printf $JWT
}
get_extension_url() {
@@ -61,19 +61,22 @@ get_extension_url() {
EXTENSION_VER="$(get_manifest_key version "$XPI_PATH")"
if [ -z "$EXTENSION_ID" -o -z "$EXTENSION_VER" ]; then
- errcho "Couldn't extract extension id and version. Please check if $XPI_PATH contains proper manifest.json file."
+ printf "Couldn't extract extension id and version. Please check if %s contains proper manifest.json file.\n" \
+ "$XPI_PATH" >&2
exit 1
fi
- ech "https://addons.mozilla.org/api/v4/addons/$EXTENSION_ID/versions/$EXTENSION_VER/"
+ printf 'https://addons.mozilla.org/api/v4/addons/%s/versions/%s/' \
+ "$EXTENSION_ID" "$EXTENSION_VER"
}
-usage() {
- errcho "Usage: $_PROG_NAME upload|check|test API_KEY SECRET XPI_PATH"
+print_usage() {
+ printf 'Usage: %s upload|check|test API_KEY SECRET XPI_PATH\n' \
+ "$_PROG_NAME" >&2
}
if [ $# != 4 ]; then
- usage
+ print_usage
exit 1
fi
@@ -83,7 +86,7 @@ case "$OPERATION" in
test)
curl "https://addons.mozilla.org/api/v4/accounts/profile/" \
-g -H "Authorization: JWT $(generate_jwt)"
- echo
+ printf '\n'
;;
check)
RETURNED_DATA="$(curl $(get_extension_url) \
@@ -95,7 +98,7 @@ case "$OPERATION" in
-H "Authorization: JWT $(generate_jwt)")"
;;
*)
- usage
+ print_usage
exit 1
;;
esac
diff --git a/write_makefile.sh b/write_makefile.sh
index d5c0fa9..4011fe8 100755
--- a/write_makefile.sh
+++ b/write_makefile.sh
@@ -14,10 +14,10 @@
# CC0 1.0 Universal License for more details.
if [ ! -e record.conf ]; then
- echo "Record of configuration 'record.conf' does not exist." >&2
+ printf "Record of configuration 'record.conf' does not exist.\n" >&2
exit 1
elif [ "$(head -n 1 record.conf | cut -c -9)x" != "srcdir = x" ]; then
- echo "Record of configuration 'record.conf' is invalid." >&2
+ printf "Record of configuration 'record.conf' is invalid.\n" >&2
exit 2
fi