summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tools/copy-common-files.sh25
-rwxr-xr-xtools/import-crowdin.sh51
-rwxr-xr-xtools/make-assets.sh42
-rwxr-xr-xtools/make-browser.sh36
-rw-r--r--tools/make-chromium-meta.py34
-rwxr-xr-xtools/make-chromium.sh40
-rwxr-xr-xtools/make-clean.sh9
-rwxr-xr-xtools/make-dig.sh17
-rw-r--r--tools/make-firefox-meta.py36
-rwxr-xr-xtools/make-firefox.sh44
-rwxr-xr-xtools/make-mv3.sh145
-rwxr-xr-xtools/make-nodejs.sh44
-rwxr-xr-xtools/make-npm.sh43
-rw-r--r--tools/make-opera-meta.py26
-rwxr-xr-xtools/make-opera.sh53
-rwxr-xr-xtools/make-thunderbird.sh45
-rwxr-xr-xtools/pull-assets.sh11
17 files changed, 701 insertions, 0 deletions
diff --git a/tools/copy-common-files.sh b/tools/copy-common-files.sh
new file mode 100644
index 0000000..56fb20a
--- /dev/null
+++ b/tools/copy-common-files.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+DES=$1
+
+bash ./tools/make-assets.sh $DES
+
+cp -R src/css $DES/
+cp -R src/img $DES/
+mkdir $DES/js
+cp -R src/js/*.js $DES/js/
+cp -R src/js/codemirror $DES/js/
+cp -R src/js/scriptlets $DES/js/
+cp -R src/js/wasm $DES/js/
+cp -R src/lib $DES/
+cp -R src/web_accessible_resources $DES/
+cp -R src/_locales $DES/
+
+cp src/*.html $DES/
+cp platform/common/*.js $DES/js/
+cp platform/common/*.json $DES/
+cp LICENSE.txt $DES/
diff --git a/tools/import-crowdin.sh b/tools/import-crowdin.sh
new file mode 100755
index 0000000..d94fa07
--- /dev/null
+++ b/tools/import-crowdin.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+echo "*** uBlock: Importing from Crowdin archive"
+
+SRC=~/Downloads/crowdin
+rm -r $SRC || true > /dev/null
+unzip -q ~/Downloads/uBlock\ \(translations\).zip -d $SRC
+
+# https://www.assertnotmagic.com/2018/06/20/bash-brackets-quick-reference/
+
+DES=./src/_locales
+DESMV3=./platform/mv3/extension/_locales
+
+for dir in $SRC/*/; do
+ srclang=$(basename $dir)
+ deslang=${srclang/-/_}
+ deslang=${deslang%_AM}
+ deslang=${deslang%_ES}
+ deslang=${deslang%_IN}
+ deslang=${deslang%_LK}
+ deslang=${deslang%_NL}
+ deslang=${deslang%_PK}
+ deslang=${deslang%_SE}
+ if [[ $deslang == 'en' ]]; then
+ continue
+ fi
+ # ubo
+ mkdir -p "$DES/$deslang/" && cp "$SRC/$srclang/messages.json" "$DES/$deslang/"
+ # ubo lite
+ mkdir -p "$DESMV3/$deslang/" && cp "$SRC/$srclang/uBO-Lite/messages.json" "$DESMV3/$deslang/"
+ # descriptions
+ #cp "$SRC/$srclang/description.txt" "./dist/description/description-${deslang}.txt"
+ cp "$SRC/$srclang/uBO-Lite/webstore.txt" "./platform/mv3/description/webstore.$deslang.txt"
+done
+
+# Output files with possible misuse of `$`, as this can lead to severe
+# consequences, such as not being able to run the extension at all.
+# uBO does not use `$`, so any instance of `$` must be investigated.
+# See https://issues.adblockplus.org/ticket/6666
+echo "*** uBlock: Instances of '\$':"
+grep -FR "$" $DES/ || true
+grep -FR "$" $DESMV3/ || true
+
+
+rm -r $SRC
+echo "*** uBlock: Import done."
+git status
diff --git a/tools/make-assets.sh b/tools/make-assets.sh
new file mode 100755
index 0000000..2719f1d
--- /dev/null
+++ b/tools/make-assets.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+DES=$1/assets
+
+echo "*** Packaging assets in $DES... "
+
+rm -rf $DES
+cp -R ./assets $DES/
+
+VERSION=$(cat ./dist/version)
+if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+ echo "*** Removing $DES/assets.dev.json"
+ rm $DES/assets.dev.json
+else
+ echo "*** Removing $DES/assets.json"
+ rm $DES/assets.json
+fi
+
+mkdir $DES/thirdparties
+
+ASSETS_MAIN=dist/build/uAssets/main
+ASSETS_PROD=dist/build/uAssets/prod
+
+cp -R $ASSETS_MAIN/thirdparties/pgl.yoyo.org $DES/thirdparties/
+cp -R $ASSETS_MAIN/thirdparties/publicsuffix.org $DES/thirdparties/
+cp -R $ASSETS_MAIN/thirdparties/urlhaus-filter $DES/thirdparties/
+
+mkdir -p $DES/thirdparties/easylist
+cp $ASSETS_PROD/thirdparties/easylist.txt $DES/thirdparties/easylist/
+cp $ASSETS_PROD/thirdparties/easyprivacy.txt $DES/thirdparties/easylist/
+
+mkdir $DES/ublock
+cp $ASSETS_PROD/filters/badlists.txt $DES/ublock/badlists.txt
+cp $ASSETS_PROD/filters/badware.min.txt $DES/ublock/badware.min.txt
+cp $ASSETS_PROD/filters/filters.min.txt $DES/ublock/filters.min.txt
+cp $ASSETS_PROD/filters/privacy.min.txt $DES/ublock/privacy.min.txt
+cp $ASSETS_PROD/filters/quick-fixes.min.txt $DES/ublock/quick-fixes.min.txt
+cp $ASSETS_PROD/filters/unbreak.min.txt $DES/ublock/unbreak.min.txt
diff --git a/tools/make-browser.sh b/tools/make-browser.sh
new file mode 100755
index 0000000..b37280d
--- /dev/null
+++ b/tools/make-browser.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+DES=dist/build/uBlock0.browser
+
+mkdir -p $DES/js
+cp src/js/base64-custom.js $DES/js
+cp src/js/biditrie.js $DES/js
+cp src/js/filtering-context.js $DES/js
+cp src/js/hntrie.js $DES/js
+cp src/js/static-filtering-parser.js $DES/js
+cp src/js/static-net-filtering.js $DES/js
+cp src/js/static-filtering-io.js $DES/js
+cp src/js/text-utils.js $DES/js
+cp src/js/uri-utils.js $DES/js
+
+mkdir -p $DES/js/wasm
+cp -R src/js/wasm $DES/js/
+
+mkdir -p $DES/lib
+cp -R src/lib/punycode.js $DES/lib/
+cp -R src/lib/publicsuffixlist $DES/lib/
+cp -R src/lib/regexanalyzer $DES/lib/
+
+mkdir -p $DES/data
+cp -R submodules/uAssets/thirdparties/publicsuffix.org/list/* \
+ $DES/data
+cp -R submodules/uAssets/thirdparties/easylist-downloads.adblockplus.org/* \
+ $DES/data
+
+cp platform/browser/*.html $DES/
+cp platform/browser/*.js $DES/
+cp LICENSE.txt $DES/
diff --git a/tools/make-chromium-meta.py b/tools/make-chromium-meta.py
new file mode 100644
index 0000000..319b7a1
--- /dev/null
+++ b/tools/make-chromium-meta.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+
+import os
+import json
+import re
+import sys
+
+if len(sys.argv) == 1 or not sys.argv[1]:
+ raise SystemExit('Build dir missing.')
+
+proj_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0], '..')
+build_dir = os.path.abspath(sys.argv[1])
+
+version = ''
+with open(os.path.join(proj_dir, 'dist', 'version')) as f:
+ version = f.read().strip()
+
+manifest_out = {}
+manifest_out_file = os.path.join(build_dir, 'manifest.json')
+with open(manifest_out_file) as f:
+ manifest_out = json.load(f)
+
+manifest_out['version'] = version
+
+# Development build? If so, modify name accordingly.
+match = re.search('^\d+\.\d+\.\d+\.\d+$', version)
+if match:
+ manifest_out['name'] += ' development build'
+ manifest_out['short_name'] += ' dev build'
+ manifest_out['browser_action']['default_title'] += ' dev build'
+
+with open(manifest_out_file, 'w') as f:
+ json.dump(manifest_out, f, indent=2, separators=(',', ': '), sort_keys=True)
+ f.write('\n')
diff --git a/tools/make-chromium.sh b/tools/make-chromium.sh
new file mode 100755
index 0000000..89172d5
--- /dev/null
+++ b/tools/make-chromium.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+echo "*** uBlock0.chromium: Creating web store package"
+
+DES=dist/build/uBlock0.chromium
+rm -rf $DES
+mkdir -p $DES
+
+echo "*** uBlock0.chromium: Copying common files"
+bash ./tools/copy-common-files.sh $DES
+
+# Chromium-specific
+echo "*** uBlock0.chromium: Copying chromium-specific files"
+cp platform/chromium/*.js $DES/js/
+cp platform/chromium/*.html $DES/
+cp platform/chromium/*.json $DES/
+
+# Chrome store-specific
+cp -R $DES/_locales/nb $DES/_locales/no
+
+echo "*** uBlock0.chromium: Generating meta..."
+python3 tools/make-chromium-meta.py $DES/
+
+if [ "$1" = all ]; then
+ echo "*** uBlock0.chromium: Creating plain package..."
+ pushd $(dirname $DES/) > /dev/null
+ zip uBlock0.chromium.zip -qr $(basename $DES/)/*
+ popd > /dev/null
+elif [ -n "$1" ]; then
+ echo "*** uBlock0.chromium: Creating versioned package..."
+ pushd $(dirname $DES/) > /dev/null
+ zip uBlock0_"$1".chromium.zip -qr $(basename $DES/)/*
+ popd > /dev/null
+fi
+
+echo "*** uBlock0.chromium: Package done."
diff --git a/tools/make-clean.sh b/tools/make-clean.sh
new file mode 100755
index 0000000..6935eef
--- /dev/null
+++ b/tools/make-clean.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+echo "*** uBlock: Cleaning."
+rm -Rf dist/build
+echo "*** uBlock: Cleaned."
diff --git a/tools/make-dig.sh b/tools/make-dig.sh
new file mode 100755
index 0000000..2ced63c
--- /dev/null
+++ b/tools/make-dig.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+DES="dist/build/uBlock0.dig"
+
+./tools/make-nodejs.sh $DES
+./tools/make-assets.sh $DES
+
+cp -R platform/dig/* $DES/
+
+cd $DES
+npm run build
+
+echo "*** uBlock0.dig: Package done."
diff --git a/tools/make-firefox-meta.py b/tools/make-firefox-meta.py
new file mode 100644
index 0000000..fa4ed71
--- /dev/null
+++ b/tools/make-firefox-meta.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+
+import os
+import json
+import re
+import sys
+
+if len(sys.argv) == 1 or not sys.argv[1]:
+ raise SystemExit('Build dir missing.')
+
+proj_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0], '..')
+build_dir = os.path.abspath(sys.argv[1])
+
+version = ''
+with open(os.path.join(proj_dir, 'dist', 'version')) as f:
+ version = f.read().strip()
+
+firefox_manifest = {}
+firefox_manifest_file = os.path.join(build_dir, 'manifest.json')
+with open(firefox_manifest_file) as f2:
+ firefox_manifest = json.load(f2)
+
+if 'sidebar_action' in firefox_manifest:
+ match = re.search('^(\d+\.\d+\.\d+)(\.\d+)$', version)
+ if not match:
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1459007
+ # By design Firefox opens the sidebar with new installation of
+ # uBO when sidebar_action is present in the manifest.
+ # Remove sidebarAction support for stable release of uBO.
+ del firefox_manifest['sidebar_action']
+
+firefox_manifest['version'] = version
+
+with open(firefox_manifest_file, 'w') as f2:
+ json.dump(firefox_manifest, f2, indent=2, separators=(',', ': '), sort_keys=True)
+ f2.write('\n')
diff --git a/tools/make-firefox.sh b/tools/make-firefox.sh
new file mode 100755
index 0000000..2278c58
--- /dev/null
+++ b/tools/make-firefox.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+echo "*** uBlock0.firefox: Creating web store package"
+
+BLDIR=dist/build
+DES="$BLDIR"/uBlock0.firefox
+rm -rf $DES
+mkdir -p $DES
+
+echo "*** uBlock0.firefox: Copying common files"
+bash ./tools/copy-common-files.sh $DES
+
+# Firefox-specific
+echo "*** uBlock0.firefox: Copying firefox-specific files"
+cp platform/firefox/*.json $DES/
+cp platform/firefox/*.js $DES/js/
+
+# Firefox store-specific
+cp -R $DES/_locales/nb $DES/_locales/no
+
+# Firefox/webext-specific
+rm $DES/img/icon_128.png
+
+echo "*** uBlock0.firefox: Generating meta..."
+python3 tools/make-firefox-meta.py $DES/
+
+if [ "$1" = all ]; then
+ echo "*** uBlock0.firefox: Creating package..."
+ pushd $DES > /dev/null
+ zip ../$(basename $DES).xpi -qr *
+ popd > /dev/null
+elif [ -n "$1" ]; then
+ echo "*** uBlock0.firefox: Creating versioned package..."
+ pushd $DES > /dev/null
+ zip ../$(basename $DES).xpi -qr *
+ popd > /dev/null
+ mv "$BLDIR"/uBlock0.firefox.xpi "$BLDIR"/uBlock0_"$1".firefox.xpi
+fi
+
+echo "*** uBlock0.firefox: Package done."
diff --git a/tools/make-mv3.sh b/tools/make-mv3.sh
new file mode 100755
index 0000000..8b1b2ab
--- /dev/null
+++ b/tools/make-mv3.sh
@@ -0,0 +1,145 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+shopt -s extglob
+
+echo "*** uBOLite.mv3: Creating extension"
+
+PLATFORM="chromium"
+
+for i in "$@"; do
+ case $i in
+ quick)
+ QUICK="yes"
+ shift # past argument=value
+ ;;
+ full)
+ FULL="yes"
+ shift # past argument=value
+ ;;
+ firefox)
+ PLATFORM="firefox"
+ shift # past argument=value
+ ;;
+ chromium)
+ PLATFORM="chromium"
+ shift # past argument=value
+ ;;
+ (uBOLite_+([0-9]).+([0-9]).+([0-9]).+([0-9]))
+ TAGNAME="$i"
+ FULL="yes"
+ shift # past argument=value
+ ;;
+ esac
+done
+
+DES="dist/build/uBOLite.$PLATFORM"
+
+if [ "$QUICK" != "yes" ]; then
+ rm -rf $DES
+fi
+
+mkdir -p $DES
+cd $DES
+DES=$(pwd)
+cd - > /dev/null
+
+mkdir -p $DES/css/fonts
+mkdir -p $DES/js
+mkdir -p $DES/img
+
+if [ -n "$UBO_VERSION" ]; then
+ UBO_REPO="https://github.com/gorhill/uBlock.git"
+ UBO_DIR=$(mktemp -d)
+ echo "*** uBOLite.mv3: Fetching uBO $UBO_VERSION from $UBO_REPO into $UBO_DIR"
+ cd "$UBO_DIR"
+ git init -q
+ git remote add origin "https://github.com/gorhill/uBlock.git"
+ git fetch --depth 1 origin "$UBO_VERSION"
+ git checkout -q FETCH_HEAD
+ cd - > /dev/null
+else
+ UBO_DIR=.
+fi
+
+echo "*** uBOLite.mv3: Copying common files"
+cp -R $UBO_DIR/src/css/fonts/* $DES/css/fonts/
+cp $UBO_DIR/src/css/themes/default.css $DES/css/
+cp $UBO_DIR/src/css/common.css $DES/css/
+cp $UBO_DIR/src/css/dashboard-common.css $DES/css/
+cp $UBO_DIR/src/css/fa-icons.css $DES/css/
+
+cp $UBO_DIR/src/js/dom.js $DES/js/
+cp $UBO_DIR/src/js/fa-icons.js $DES/js/
+cp $UBO_DIR/src/js/i18n.js $DES/js/
+cp $UBO_DIR/src/lib/punycode.js $DES/js/
+
+cp -R $UBO_DIR/src/img/flags-of-the-world $DES/img
+
+cp LICENSE.txt $DES/
+
+echo "*** uBOLite.mv3: Copying mv3-specific files"
+if [ "$PLATFORM" = "firefox" ]; then
+ cp platform/mv3/firefox/background.html $DES/
+fi
+cp platform/mv3/extension/*.html $DES/
+cp platform/mv3/extension/*.json $DES/
+cp platform/mv3/extension/css/* $DES/css/
+cp -R platform/mv3/extension/js/* $DES/js/
+cp platform/mv3/extension/img/* $DES/img/
+cp -R platform/mv3/extension/_locales $DES/
+cp platform/mv3/README.md $DES/
+
+if [ "$QUICK" != "yes" ]; then
+ echo "*** uBOLite.mv3: Generating rulesets"
+ TMPDIR=$(mktemp -d)
+ mkdir -p $TMPDIR
+ if [ "$PLATFORM" = "chromium" ]; then
+ cp platform/mv3/chromium/manifest.json $DES/
+ elif [ "$PLATFORM" = "firefox" ]; then
+ cp platform/mv3/firefox/manifest.json $DES/
+ fi
+ ./tools/make-nodejs.sh $TMPDIR
+ cp platform/mv3/package.json $TMPDIR/
+ cp platform/mv3/*.js $TMPDIR/
+ cp platform/mv3/extension/js/utils.js $TMPDIR/js/
+ cp $UBO_DIR/assets/assets.json $TMPDIR/
+ cp $UBO_DIR/assets/resources/scriptlets.js $TMPDIR/
+ cp -R platform/mv3/scriptlets $TMPDIR/
+ mkdir -p $TMPDIR/web_accessible_resources
+ cp $UBO_DIR/src/web_accessible_resources/* $TMPDIR/web_accessible_resources/
+ cd $TMPDIR
+ node --no-warnings make-rulesets.js output=$DES platform="$PLATFORM"
+ cd - > /dev/null
+ rm -rf $TMPDIR
+fi
+
+echo "*** uBOLite.mv3: extension ready"
+echo "Extension location: $DES/"
+
+if [ "$FULL" = "yes" ]; then
+ EXTENSION="zip"
+ if [ "$PLATFORM" = "firefox" ]; then
+ EXTENSION="xpi"
+ fi
+ echo "*** uBOLite.mv3: Creating publishable package..."
+ if [ -z "$TAGNAME" ]; then
+ TAGNAME="uBOLite_$(jq -r .version $DES/manifest.json)"
+ else
+ tmp=$(mktemp)
+ jq --arg version "${TAGNAME:8}" '.version = $version' "$DES/manifest.json" > "$tmp" \
+ && mv "$tmp" "$DES/manifest.json"
+ fi
+ PACKAGENAME="$TAGNAME.$PLATFORM.mv3.$EXTENSION"
+ TMPDIR=$(mktemp -d)
+ mkdir -p $TMPDIR
+ cp -R $DES/* $TMPDIR/
+ cd $TMPDIR > /dev/null
+ zip $PACKAGENAME -qr ./*
+ cd - > /dev/null
+ cp $TMPDIR/$PACKAGENAME dist/build/
+ rm -rf $TMPDIR
+ echo "Package location: $(pwd)/dist/build/$PACKAGENAME"
+fi
diff --git a/tools/make-nodejs.sh b/tools/make-nodejs.sh
new file mode 100755
index 0000000..1e38ba1
--- /dev/null
+++ b/tools/make-nodejs.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+DES=$1
+
+mkdir -p $DES/js
+cp src/js/base64-custom.js $DES/js
+cp src/js/biditrie.js $DES/js
+cp src/js/dynamic-net-filtering.js $DES/js
+cp src/js/filtering-context.js $DES/js
+cp src/js/hnswitches.js $DES/js
+cp src/js/hntrie.js $DES/js
+cp src/js/redirect-resources.js $DES/js
+cp src/js/static-dnr-filtering.js $DES/js
+cp src/js/static-filtering-parser.js $DES/js
+cp src/js/static-net-filtering.js $DES/js
+cp src/js/static-filtering-io.js $DES/js
+cp src/js/tasks.js $DES/js
+cp src/js/text-utils.js $DES/js
+cp src/js/uri-utils.js $DES/js
+cp src/js/url-net-filtering.js $DES/js
+
+mkdir -p $DES/lib
+cp -R src/lib/csstree $DES/lib/
+cp -R src/lib/punycode.js $DES/lib/
+cp -R src/lib/regexanalyzer $DES/lib/
+cp -R src/lib/publicsuffixlist $DES/lib/
+
+# Convert wasm modules into json arrays
+mkdir -p $DES/js/wasm
+cp src/js/wasm/* $DES/js/wasm/
+node -pe "JSON.stringify(Array.from(fs.readFileSync('src/js/wasm/hntrie.wasm')))" \
+ > $DES/js/wasm/hntrie.wasm.json
+node -pe "JSON.stringify(Array.from(fs.readFileSync('src/js/wasm/biditrie.wasm')))" \
+ > $DES/js/wasm/biditrie.wasm.json
+node -pe "JSON.stringify(Array.from(fs.readFileSync('src/lib/publicsuffixlist/wasm/publicsuffixlist.wasm')))" \
+ > $DES/lib/publicsuffixlist/wasm/publicsuffixlist.wasm.json
+
+cp platform/nodejs/*.js $DES/
+cp platform/nodejs/README.md $DES/
+cp LICENSE.txt $DES/
diff --git a/tools/make-npm.sh b/tools/make-npm.sh
new file mode 100755
index 0000000..6bffadc
--- /dev/null
+++ b/tools/make-npm.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+DES="dist/build/uBlock0.npm"
+
+TMPDIR="$PWD/tmp"
+mkdir -p "$TMPDIR/node_modules"
+
+rm -rf $DES
+
+./tools/make-nodejs.sh $DES
+./tools/make-assets.sh $DES
+
+# Target-specific
+cp platform/npm/.npmignore $DES/
+cp platform/npm/*.json $DES/
+cp platform/npm/.*.json $DES/
+cp platform/npm/*.js $DES/
+cp -R platform/npm/tests $DES/
+
+cd $DES
+cd tests/data
+tar xzf bundle.tgz
+cd -
+npm run build
+tarballname=$(npm pack 2> /dev/null)
+if [ "$1" ]; then
+ echo "*** uBlock0.npm: Creating versioned package..."
+ mv $tarballname ../uBlock0_$1.npm.tgz
+else
+ echo "*** uBlock0.npm: Creating plain package..."
+ mv $tarballname ../uBlock0.npm.tgz
+fi
+ln -sf "$TMPDIR/node_modules"
+if [ -z "$GITHUB_ACTIONS" ]; then
+ npm install
+fi
+cd -
+
+echo "*** uBlock0.npm: Package done."
diff --git a/tools/make-opera-meta.py b/tools/make-opera-meta.py
new file mode 100644
index 0000000..4fb2cb9
--- /dev/null
+++ b/tools/make-opera-meta.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+
+import os
+import json
+import sys
+
+if len(sys.argv) == 1 or not sys.argv[1]:
+ raise SystemExit('Build dir missing.')
+
+proj_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0], '..')
+build_dir = os.path.abspath(sys.argv[1])
+
+version = ''
+with open(os.path.join(proj_dir, 'dist', 'version')) as f:
+ version = f.read().strip()
+
+manifest_out = {}
+manifest_out_file = os.path.join(build_dir, 'manifest.json')
+with open(manifest_out_file) as f:
+ manifest_out = json.load(f)
+
+manifest_out['version'] = version
+
+with open(manifest_out_file, 'w') as f2:
+ json.dump(manifest_out, f2, indent=2, separators=(',', ': '), sort_keys=True)
+ f2.write('\n')
diff --git a/tools/make-opera.sh b/tools/make-opera.sh
new file mode 100755
index 0000000..7ab2497
--- /dev/null
+++ b/tools/make-opera.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+echo "*** uBlock0.opera: Creating web store package"
+
+DES=dist/build/uBlock0.opera
+rm -rf $DES
+mkdir -p $DES
+
+echo "*** uBlock0.opera: Copying common files"
+bash ./tools/copy-common-files.sh $DES
+
+# Chromium-specific
+echo "*** uBlock0.opera: Copying chromium-specific files"
+cp platform/chromium/*.js $DES/js/
+cp platform/chromium/*.html $DES/
+
+# Opera-specific
+echo "*** uBlock0.opera: Copying opera-specific files"
+cp platform/opera/manifest.json $DES/
+
+rm -r $DES/_locales/az
+rm -r $DES/_locales/be
+rm -r $DES/_locales/cv
+rm -r $DES/_locales/gu
+rm -r $DES/_locales/hi
+rm -r $DES/_locales/hy
+rm -r $DES/_locales/ka
+rm -r $DES/_locales/kk
+rm -r $DES/_locales/ku
+rm -r $DES/_locales/mr
+rm -r $DES/_locales/si
+rm -r $DES/_locales/so
+rm -r $DES/_locales/th
+
+# Removing WASM modules until I receive an answer from Opera people: Opera's
+# uploader issue an error for hntrie.wasm and this prevents me from
+# updating uBO in the Opera store. The modules are unused anyway for
+# Chromium- based browsers.
+rm $DES/js/wasm/*.wasm
+rm $DES/js/wasm/*.wat
+rm $DES/lib/lz4/*.wasm
+rm $DES/lib/lz4/*.wat
+rm $DES/lib/publicsuffixlist/wasm/*.wasm
+rm $DES/lib/publicsuffixlist/wasm/*.wat
+
+echo "*** uBlock0.opera: Generating meta..."
+python3 tools/make-opera-meta.py $DES/
+
+echo "*** uBlock0.opera: Package done."
diff --git a/tools/make-thunderbird.sh b/tools/make-thunderbird.sh
new file mode 100755
index 0000000..315122a
--- /dev/null
+++ b/tools/make-thunderbird.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+echo "*** uBlock0.thunderbird: Creating web store package"
+
+BLDIR=dist/build
+DES="$BLDIR"/uBlock0.thunderbird
+rm -rf $DES
+mkdir -p $DES
+
+echo "*** uBlock0.thunderbird: copying common files"
+bash ./tools/copy-common-files.sh $DES
+
+echo "*** uBlock0.firefox: Copying firefox-specific files"
+cp platform/firefox/*.js $DES/js/
+
+echo "*** uBlock0.firefox: Copying thunderbird-specific files"
+cp platform/thunderbird/manifest.json $DES/
+
+# Firefox store-specific
+cp -R $DES/_locales/nb $DES/_locales/no
+
+# Firefox/webext-specific
+rm $DES/img/icon_128.png
+
+echo "*** uBlock0.thunderbird: Generating meta..."
+python3 tools/make-firefox-meta.py $DES/
+
+if [ "$1" = all ]; then
+ echo "*** uBlock0.thunderbird: Creating package..."
+ pushd $DES > /dev/null
+ zip ../$(basename $DES).xpi -qr *
+ popd > /dev/null
+elif [ -n "$1" ]; then
+ echo "*** uBlock0.thunderbird: Creating versioned package..."
+ pushd $DES > /dev/null
+ zip ../$(basename $DES).xpi -qr *
+ popd > /dev/null
+ mv "$BLDIR"/uBlock0.thunderbird.xpi "$BLDIR"/uBlock0_"$1".thunderbird.xpi
+fi
+
+echo "*** uBlock0.thunderbird: Package done."
diff --git a/tools/pull-assets.sh b/tools/pull-assets.sh
new file mode 100755
index 0000000..88e268d
--- /dev/null
+++ b/tools/pull-assets.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+#
+# This script assumes a linux environment
+
+set -e
+
+DES=dist/build/uAssets
+
+echo "*** Pull assets from remote into $DES"
+git clone --depth 1 --branch master https://github.com/uBlockOrigin/uAssets $DES/main
+git clone --depth 1 --branch gh-pages https://github.com/uBlockOrigin/uAssets $DES/prod