diff options
-rwxr-xr-x | build.sh | 367 | ||||
-rwxr-xr-x | lib_build.sh | 300 |
2 files changed, 376 insertions, 291 deletions
@@ -1,306 +1,91 @@ #!/bin/sh -# Copyright (C) 2021 Wojtek Kosior +# Copyright (C) 2021 jahoti <jahoti@tilde.team> # Redistribution terms are gathered in the `copyright' file. -. ./shell_utils.sh - -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)" -} - -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 -} - -as_json_list() { - while true; do - if [ "x" = "x$2" ]; then - echo -n '\\n'"\t\t\"$1\""'\\n\t' - return - fi - echo -n '\\n'"\t\t\"$1\"," - shift - done -} - -as_html_list() { - while [ "x" != "x$1" ]; do - echo -n '\\n'" <script src=\"/$1\"></script>" +print_usage() { + EXIT_STATUS=${1:-0} + if [ "x$1" != x ]; then shift - done -} - -set_browser() { - if [ "x$1" = "xmozilla" -o "x$1" = "xchromium" ]; then - BROWSER="$1" - else - errcho "usage: $0 mozilla|chromium" - exit 1 + errcho "$@" fi + + errcho "usage: $0 [OPTION]... BROWSER" + errcho + errcho "the -- preceding long forms is optional" + errcho "browsers:" + errcho " -C, chromium: build for Chromium and derivatives" + errcho " -M, mozilla: build for Firefox and derivatives" + errcho "options:" + errcho " -b, build [LOC]: set file/directory to use for building" + errcho " -f, force: delete the build directory if it exists" + errcho " instead of throwing an error." + errcho " -h, help: print usage information and exit" + errcho " -o, output [LOC]: set output file/directory" + errcho " -z, zip_ext: pack the extension as a file" + errcho " -7, 7zip: use the '7z' command instead of 'zip'" + + exit $EXIT_STATUS } -main() { - set_browser "$1" - - # 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 - - SCRIPTDIRS='background html common content' - - SCRIPTS=$(find $SCRIPTDIRS -name '[^.#]*.js') - - for SCRIPT in $SCRIPTS; do - add_exports $SCRIPT - add_imports $SCRIPT - 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)" - - BUILDDIR=build_$BROWSER - rm -rf $BUILDDIR - mkdir $BUILDDIR - for DIR in $(find $SCRIPTDIRS -type d); do - mkdir -p $BUILDDIR/$DIR - done - - CHROMIUM_KEY='' - GECKO_APPLICATIONS='' - - if [ "$BROWSER" = "chromium" ]; then - CHROMIUM_KEY="$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64)" - CHROMIUM_KEY=$(echo chromium-key-dummy-file-$CHROMIUM_KEY | tr / -) - touch $BUILDDIR/$CHROMIUM_KEY - - CHROMIUM_KEY="\n\ - // WARNING!!!\n\ - // EACH USER SHOULD REPLACE DUMMY FILE's VALUE WITH A UNIQUE ONE!!!\n\ - // OTHERWISE, SECURITY CAN BE TRIVIALLY COMPROMISED!\n\ - // Only relevant to users of chrome-based browsers.\n\ - // Users of Firefox forks are safe.\n\ - \"$CHROMIUM_KEY\"\ -" - else - GECKO_APPLICATIONS="\n\ - \"applications\": {\n\ - \"gecko\": {\n\ - \"id\": \"{6fe13369-88e9-440f-b837-5012fb3bedec}\",\n\ - \"strict_min_version\": \"60.0\"\n\ - }\n\ - }," - fi - - sed "\ -s^_GECKO_APPLICATIONS_^$GECKO_APPLICATIONS^ -s^_CHROMIUM_KEY_^$CHROMIUM_KEY^ -s^_BGSCRIPTS_^$BGSCRIPTS^ -s^_CONTENTSCRIPTS_^$CONTENTSCRIPTS^" \ - < manifest.json > $BUILDDIR/manifest.json - - ./process_html_file.sh html/display-panel.html | - sed "s^_POPUPSCRIPTS_^$POPUPSCRIPTS^" \ - > $BUILDDIR/html/display-panel.html - - ./process_html_file.sh html/options.html | - sed "s^_OPTIONSSCRIPTS_^$OPTIONSSCRIPTS^" \ - > $BUILDDIR/html/options.html - - for FILE in $SCRIPTS; do - FILEKEY=$(sanitize "$FILE") - if [ "xyes" != "x$(map_get USED $FILEKEY)" ]; then - errcho "WARNING! $FILE not used" - 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 +. ./lib_build.sh + +BROWSER='' +BUILDDIR='' +MAKEZIP=0 +FORCE=0 +ZIP_COMMAND='zip -r' + +while [ "x$1" != x ]; do + case "$1" in + -C | chromium | --chromium) BROWSER=chromium;; + -M | mozilla | --mozilla) BROWSER=mozilla;; + -b | output | --build) BUILDDIR="$2" + shift;; + -f | force | --force) FORCE=1;; + -h | help | --help) print_usage;; + -o | output | --output) OUTPUT="$2" + shift;; + -z | zip_ext | --zip_ext) MAKEZIP=1;; + -7 | 7zip | --7zip) ZIP_COMMAND='7z a';; + *) print_usage 2 Unrecognized option "'$1'.";; + esac + shift +done + +if [ "x$BROWSER" = x ]; then + print_usage 1 No browser was specified. fi -echo " - -$(map_get EXPORTCODES $FILEKEY) -})}).fun();") > $BUILDDIR/$FILE - fi - done - - if [ "$BROWSER" = "chromium" ]; then - cat > $BUILDDIR/exports_init.js <<EOF -window.killtheweb={is_chrome: true, browser: window.chrome}; -EOF +BUILDDIR="${BUILDDIR:-build_$BROWSER}" +if [ -e "$BUILDDIR" ]; then + if [ $FORCE = 0 ]; then + errcho "Build directory '$BUILDDIR' exists." + exit 3 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 + rm -rf "$BUILDDIR" fi +fi - cp -r copyright licenses/ $BUILDDIR - cp html/*.css $BUILDDIR/html - mkdir $BUILDDIR/icons - cp icons/*.png $BUILDDIR/icons +if [ "x$OUTPUT" = x ]; then + case "$MAKEZIP$BROWSER" in + 0*) OUTPUT=build_$BROWSER;; + 1chromium) OUTPUT=build.crx;; + 1mozilla) OUTPUT=build.xpi;; + esac +fi - if [ "$BROWSER" = "chromium" ]; then - for MOZILLA_FILE in $(find $BUILDDIR -name "MOZILLA_*"); do - echo > "$MOZILLA_FILE" - done - fi - if [ "$BROWSER" = "mozilla" ]; then - for CHROMIUM_FILE in $(find $BUILDDIR -name "CHROMIUM_*"); do - echo > "$CHROMIUM_FILE" - done - fi -} +if [ -e "$OUTPUT" ]; then + errcho "Output location '$OUTPUT' exists." + exit 3 +fi -main "$@" +mkdir "$BUILDDIR" +main +if [ $MAKEZIP = 1 ]; then + make_zip + mv "$BUILDDIR"/build.zip "$OUTPUT" + rm -rf "$BUILDDIR" +elif [ "$BUILDDIR" != "$OUTPUT" ]; then + mv "$BUILDDIR" "$OUTPUT" +fi diff --git a/lib_build.sh b/lib_build.sh new file mode 100755 index 0000000..c808f03 --- /dev/null +++ b/lib_build.sh @@ -0,0 +1,300 @@ +#!/bin/sh + +# Copyright (C) 2021 Wojtek Kosior +# Redistribution terms are gathered in the `copyright' file. + +. ./shell_utils.sh + +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)" +} + +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 +} + +as_json_list() { + while true; do + if [ "x" = "x$2" ]; then + echo -n '\\n'"\t\t\"$1\""'\\n\t' + return + fi + echo -n '\\n'"\t\t\"$1\"," + shift + done +} + +as_html_list() { + while [ "x" != "x$1" ]; do + echo -n '\\n'" <script src=\"/$1\"></script>" + shift + done +} + +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 + + SCRIPTDIRS='background html common content' + + SCRIPTS=$(find $SCRIPTDIRS -name '[^.#]*.js') + + for SCRIPT in $SCRIPTS; do + add_exports $SCRIPT + add_imports $SCRIPT + 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)" + + rm -rf $BUILDDIR + mkdir $BUILDDIR + for DIR in $(find $SCRIPTDIRS -type d); do + mkdir -p $BUILDDIR/$DIR + done + + CHROMIUM_KEY='' + GECKO_APPLICATIONS='' + + if [ "$BROWSER" = "chromium" ]; then + CHROMIUM_KEY="$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64)" + CHROMIUM_KEY=$(echo chromium-key-dummy-file-$CHROMIUM_KEY | tr / -) + touch $BUILDDIR/$CHROMIUM_KEY + + CHROMIUM_KEY="\n\ + // WARNING!!!\n\ + // EACH USER SHOULD REPLACE DUMMY FILE's VALUE WITH A UNIQUE ONE!!!\n\ + // OTHERWISE, SECURITY CAN BE TRIVIALLY COMPROMISED!\n\ + // Only relevant to users of chrome-based browsers.\n\ + // Users of Firefox forks are safe.\n\ + \"$CHROMIUM_KEY\"\ +" + else + GECKO_APPLICATIONS="\n\ + \"applications\": {\n\ + \"gecko\": {\n\ + \"id\": \"{6fe13369-88e9-440f-b837-5012fb3bedec}\",\n\ + \"strict_min_version\": \"60.0\"\n\ + }\n\ + }," + fi + + sed "\ +s^_GECKO_APPLICATIONS_^$GECKO_APPLICATIONS^ +s^_CHROMIUM_KEY_^$CHROMIUM_KEY^ +s^_BGSCRIPTS_^$BGSCRIPTS^ +s^_CONTENTSCRIPTS_^$CONTENTSCRIPTS^" \ + < manifest.json > $BUILDDIR/manifest.json + + ./process_html_file.sh html/display-panel.html | + sed "s^_POPUPSCRIPTS_^$POPUPSCRIPTS^" \ + > $BUILDDIR/html/display-panel.html + + ./process_html_file.sh html/options.html | + sed "s^_OPTIONSSCRIPTS_^$OPTIONSSCRIPTS^" \ + > $BUILDDIR/html/options.html + + for FILE in $SCRIPTS; do + FILEKEY=$(sanitize "$FILE") + if [ "xyes" != "x$(map_get USED $FILEKEY)" ]; then + errcho "WARNING! $FILE not used" + 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 + fi + done + + if [ "$BROWSER" = "chromium" ]; then + cat > $BUILDDIR/exports_init.js <<EOF +window.killtheweb={is_chrome: true, browser: window.chrome}; +EOF + 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 + fi + + cp -r copyright licenses/ $BUILDDIR + cp html/*.css $BUILDDIR/html + mkdir $BUILDDIR/icons + cp icons/*.png $BUILDDIR/icons + + if [ "$BROWSER" = "chromium" ]; then + for MOZILLA_FILE in $(find $BUILDDIR -name "MOZILLA_*"); do + echo > "$MOZILLA_FILE" + done + fi + if [ "$BROWSER" = "mozilla" ]; then + for CHROMIUM_FILE in $(find $BUILDDIR -name "CHROMIUM_*"); do + echo > "$CHROMIUM_FILE" + done + fi +} + +make_zip() ( + cd "$BUILDDIR" + case $BROWSER in + mozilla) $ZIP_COMMAND build.zip *;; + chromium) exit 92;; # Still to do + esac +) |