#!/bin/bash -e # Copyright (c) 2011 Zotero # Center for History and New Media # George Mason University, Fairfax, Virginia, USA # http://zotero.org # # 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . CALLDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" . "$CALLDIR/config.sh" . "$CALLDIR/scripts/utils.sh" if [ "`uname`" = "Darwin" ]; then MAC_NATIVE=1 else MAC_NATIVE=0 fi if [ "`uname -o 2> /dev/null`" = "Cygwin" ]; then WIN_NATIVE=1 else WIN_NATIVE=0 fi function usage { cat >&2 < /dev/null; then rsync -a "$1/" "$2/" else mkdir -p "$2" cp -a "$1/." "$2/" fi } function abspath { echo $(cd $(dirname $1); pwd)/$(basename $1); } function check_lfs_file { if [ "$(head --bytes 5 "$1")" = "versi" ]; then echo "$1 not checked out -- install Git LFS and run 'git lfs pull'" >&2 exit 1 fi } SOURCE_DIR="" ZIP_FILE="" BUILD_MAC=0 BUILD_WIN=0 BUILD_LINUX=0 PACKAGE=1 DEVTOOLS=0 quick_build=0 arch="" while getopts "d:f:p:a:c:tseq" opt; do case $opt in d) SOURCE_DIR="$OPTARG" ;; f) ZIP_FILE="$OPTARG" ;; p) for (( i=0; i<${#OPTARG}; i++ )); do case ${OPTARG:i:1} in m) BUILD_MAC=1 ;; w) BUILD_WIN=1 ;; l) BUILD_LINUX=1 ;; *) echo "$0: Invalid platform option ${OPTARG:i:1}" >&2 usage ;; esac done ;; a) arch="$OPTARG" ;; c) UPDATE_CHANNEL="$OPTARG" ;; t) DEVTOOLS=1 ;; e) SIGN=1 ;; s) PACKAGE=0 ;; q) quick_build=1 ;; *) usage ;; esac shift $((OPTIND-1)); OPTIND=1 done xul_hash_file() { local _platform=$1 local _arch=$2 case $_platform in m) echo "hash-mac";; w) [[ $_arch == x64 ]] && _arch="win-x64" [[ $_arch == arm64 ]] && _arch="win-arm64" echo "hash-${_arch}";; l) [[ $_arch == x64 ]] && _arch="x86_64" echo "hash-linux-${_arch}";; *) echo "Invalid platform '$_platform'" >&2 exit 1 esac } function check_xulrunner_hash { local _platform=$1 local _arch=$2 local platform_hash_file=$(xul_hash_file "$_platform" "${_arch:-universal}") # TEMP: If previous Windows hash file without architecture is present, force a refresh, # because the Firefox folder might have been changed without the new hash file being # updated, resulting in a broken build (e.g, fx140 using fx128). We'll want to keep this # as long as we're switching back to <=fx128. This isn't an issue on macOS because there's # no architecture and isn't an issue on Linux because the runtime folder names changed. if [[ $_platform = 'w' ]] && [[ -e "$CALLDIR/xulrunner/hash-win" ]]; then echo "Found old hash-win -- forcing redownload" rm "$CALLDIR"/xulrunner/hash-win* fi if [ ! -e "$CALLDIR/xulrunner/$platform_hash_file" ]; then echo "$platform_hash_file not found -- downloading" echo $CALLDIR/scripts/fetch_xulrunner -p $_platform ${_arch:+-a $_arch} else recalculated_xulrunner_hash=$("$CALLDIR/scripts/xulrunner_hash" -p $_platform ${_arch:+-a $_arch}) current_xulrunner_hash=$(< "$CALLDIR/xulrunner/$platform_hash_file") if [ "$current_xulrunner_hash" != "$recalculated_xulrunner_hash" ]; then echo "xulrunner hashes don't match -- redownloading" echo "$CALLDIR/scripts/fetch_xulrunner" -p $_platform ${_arch:+-a $_arch} current_xulrunner_hash=$(< "$CALLDIR/xulrunner/$platform_hash_file") if [ "$current_xulrunner_hash" != "$recalculated_xulrunner_hash" ]; then echo "xulrunner hashes don't match after running fetch_xulrunner!" exit 1 fi fi fi } # Derive platform flags from host if none provided if [[ $BUILD_MAC == 0 ]] && [[ $BUILD_WIN == 0 ]] && [[ $BUILD_LINUX == 0 ]]; then case "$(uname -s)" in Darwin) BUILD_MAC=1 ;; Linux) BUILD_LINUX=1 ;; CYGWIN*|MINGW*) BUILD_WIN=1 ;; esac fi # Check xulrunner hashes for requested builds if [ $BUILD_MAC == 1 ]; then check_xulrunner_hash m fi if [ $BUILD_WIN == 1 ]; then if [[ -n $arch ]]; then check_xulrunner_hash w $(get_canonical_arch w $arch) else for _a in win-x64 win-arm64 win32; do check_xulrunner_hash w "$_a" done fi fi if [ $BUILD_LINUX == 1 ]; then if [[ -n $arch ]]; then check_xulrunner_hash l $(get_canonical_arch l $arch) else for _a in x64 arm64; do check_xulrunner_hash l "$_a" done fi fi # Require source dir or ZIP file if [[ -z "$SOURCE_DIR" ]] && [[ -z "$ZIP_FILE" ]]; then usage elif [[ -n "$SOURCE_DIR" ]] && [[ -n "$ZIP_FILE" ]]; then usage fi # Require at least one platform if [[ $BUILD_MAC == 0 ]] && [[ $BUILD_WIN == 0 ]] && [[ $BUILD_LINUX == 0 ]]; then usage fi if [[ -z "${ZOTERO_TEST:-}" ]] || [[ $ZOTERO_TEST == "0" ]]; then include_tests=0 else include_tests=1 fi # Bundle devtools with dev builds if [ "$UPDATE_CHANNEL" == "beta" ] || [ "$UPDATE_CHANNEL" == "dev" ] || [ "$UPDATE_CHANNEL" == "test" ]; then DEVTOOLS=1 fi if [ -z "$UPDATE_CHANNEL" ]; then UPDATE_CHANNEL="default"; fi BUILD_ID=`date +%Y%m%d%H%M%S` # Paths to Gecko runtimes MAC_RUNTIME_PATH="$CALLDIR/xulrunner/Firefox.app" WIN_RUNTIME_PATH_PREFIX="$CALLDIR/xulrunner/firefox-" LINUX_RUNTIME_PATH_PREFIX="$CALLDIR/xulrunner/firefox-linux-" base_dir="$BUILD_DIR/base" app_dir="$BUILD_DIR/base/app" omni_dir="$BUILD_DIR/base/app/omni" shopt -s extglob mkdir -p "$app_dir" rm -rf "$STAGE_DIR" mkdir "$STAGE_DIR" rm -rf "$DIST_DIR" mkdir "$DIST_DIR" # Save build id, which is needed for updates manifest echo $BUILD_ID > "$DIST_DIR/build_id" cd "$app_dir" # Copy 'browser' files from Firefox # # omni.ja is left uncompressed within the Firefox application files by fetch_xulrunner # # TEMP: Also extract .hyf hyphenation files from the outer (still compressed) omni.ja # This works around https://bugzilla.mozilla.org/show_bug.cgi?id=1772900 set +e if [ $BUILD_MAC == 1 ]; then cp -Rp "$MAC_RUNTIME_PATH"/Contents/Resources/browser/omni "$app_dir" unzip -qj "$MAC_RUNTIME_PATH"/Contents/Resources/omni.ja "hyphenation/*" -d "$app_dir"/hyphenation/ elif [[ $BUILD_WIN == 1 ]]; then # These are non-arch-specific files, so just find a runtime we fetched: # - If the caller specified -a, that arch is guaranteed present. # - Otherwise prefer win-x64 → win-arm64 → win32, falling back to the first # directory that exists under xulrunner/. if [[ -n $arch ]]; then omni_arch=$(get_canonical_arch w $arch) else for cand in win-x64 win-arm64 win32; do [[ -d "${WIN_RUNTIME_PATH_PREFIX}${cand}" ]] && { omni_arch="$cand"; break; } done fi cp -Rp "${WIN_RUNTIME_PATH_PREFIX}${omni_arch}"/browser/omni "$app_dir" unzip -qj "${WIN_RUNTIME_PATH_PREFIX}${omni_arch}"/omni.ja "hyphenation/*" \ -d "$app_dir"/hyphenation/ elif [[ $BUILD_LINUX == 1 ]]; then # Same as above if [[ -n $arch ]]; then omni_arch=$(get_canonical_arch l $arch) else for cand in x86_64 arm64; do [[ -d "${LINUX_RUNTIME_PATH_PREFIX}${cand}" ]] && { omni_arch="$cand"; break; } done fi cp -Rp "${LINUX_RUNTIME_PATH_PREFIX}${omni_arch}"/browser/omni "$app_dir" unzip -qj "${LINUX_RUNTIME_PATH_PREFIX}${omni_arch}"/omni.ja "hyphenation/*" \ -d "$app_dir"/hyphenation/ fi set -e cd $omni_dir # Remove Firefox files that we don't need rm actors/AboutLogins{Parent,Child}.sys.mjs rm actors/AboutMessagePreview{Parent,Child}.sys.mjs rm actors/AboutNewTab{Parent,Child}.sys.mjs rm actors/AboutPrivateBrowsing{Parent,Child}.sys.mjs rm actors/AboutProtections{Parent,Child}.sys.mjs rm actors/AboutReader{Parent,Child}.sys.mjs rm actors/AboutTabCrashed{Parent,Child}.sys.mjs rm actors/AboutWelcome{Parent,Child}.sys.mjs rm actors/ASRouter{Parent,Child}.sys.mjs rm actors/BackupUI{Parent,Child}.sys.mjs rm actors/BlockedSite{Parent,Child}.sys.mjs rm actors/BrowserProcessChild.sys.mjs rm actors/BrowserTabChild.sys.mjs rm actors/ClickHandler{Parent,Child}.sys.mjs rm actors/ContentSearch{Parent,Child}.sys.mjs rm actors/DecoderDoctor{Parent,Child}.sys.mjs rm actors/DOMFullscreen{Parent,Child}.sys.mjs rm actors/EncryptedMedia{Parent,Child}.sys.mjs rm actors/FormValidation{Parent,Child}.sys.mjs rm actors/LinkHandler{Parent,Child}.sys.mjs rm actors/MigrationWizard{Parent,Child}.sys.mjs rm actors/PageData{Parent,Child}.sys.mjs # Not our PageData actor rm actors/PageInfoChild.sys.mjs rm actors/PageStyle{Parent,Child}.sys.mjs rm actors/Plugin{Parent,Child}.sys.mjs # GMP plugins, which we remove rm actors/PointerLock{Parent,Child}.sys.mjs #rm actors/RFPHelper{Parent,Child}.sys.mjs rm actors/ScreenshotsComponentChild.sys.mjs #rm actors/SearchSERPTelemetry{Parent,Child}.sys.mjs #rm actors/ShoppingSidebar{Parent,Child}.sys.mjs rm actors/SpeechDispatcher{Parent,Child}.sys.mjs rm actors/WebRTC{Parent,Child}.sys.mjs # Keep some essential files from chrome/browser/ mkdir chrome/browser-fx browser_keep=( content/browser/license.html # For web-ext content/browser/parent/ext-browser.js # For spellchecking content/browser/built_in_addons.json # Statically imported by BackupService, which SelectableProfileService pulls in when it's # instantiated as a command-line handler at startup content/browser/backup/backup-constants.mjs ) for file in "${browser_keep[@]}"; do mkdir -p "$(dirname "chrome/browser-fx/$file")" mv "chrome/browser/$file" "chrome/browser-fx/$file" done # Delete everything else rm -r chrome/browser # Move essential files back mv chrome/browser-fx chrome/browser #rm modules/SearchSERPTelemetry.sys.mjs # Move some Firefox files that would be overwritten out of the way mv chrome.manifest chrome.manifest-fx mv defaults defaults-fx # Extract Zotero files if [ -n "$ZIP_FILE" ]; then ZIP_FILE="`abspath $ZIP_FILE`" echo "Building from $ZIP_FILE" unzip -q $ZIP_FILE -d "$omni_dir" else if command -v rsync > /dev/null; then rsync_params="" if [ $include_tests -eq 0 ]; then rsync_params="--exclude /test" fi rsync -a $rsync_params "$SOURCE_DIR/" ./ else copy_dir "$SOURCE_DIR" . if [ $include_tests -eq 0 ]; then rm -rf ./test fi fi fi mv defaults defaults-z mv defaults-fx defaults prefs_file=defaults/preferences/zotero.js # Transfer Firefox prefs, omitting some with undesirable overrides from the base prefs # # - network.captive-portal-service.enabled # Disable the captive portal check against Mozilla servers # - extensions.systemAddon.update.url grep -E -v '(network.captive-portal-service.enabled|extensions.systemAddon.update.url)' defaults/preferences/firefox.js > $prefs_file rm defaults/preferences/firefox.js # Combine app and "extension" Zotero prefs echo "" >> $prefs_file echo "#" >> $prefs_file echo "# Zotero app prefs" >> $prefs_file echo "#" >> $prefs_file echo "" >> $prefs_file cat "$CALLDIR/assets/prefs.js" >> $prefs_file echo "" >> $prefs_file echo "# Zotero extension prefs" >> $prefs_file echo "" >> $prefs_file cat defaults-z/preferences/zotero.js >> $prefs_file # Babel strips the trailing newline, so anything appended below would share a line echo "" >> $prefs_file rm -rf defaults-z # Platform-specific prefs if [ $BUILD_MAC == 1 ]; then perl -pi -e 's/pref\("browser\.preferences\.instantApply", false\);/pref\("browser\.preferences\.instantApply", true);/' $prefs_file perl -pi -e 's/%GECKO_VERSION%/'"$GECKO_VERSION_MAC"'/g' $prefs_file # Fix horizontal mousewheel scrolling (this is set to 4 in the Fx60 .app greprefs.js, but # defaults to 1 in later versions of Firefox, and needs to be 1 to work on macOS) echo 'pref("mousewheel.with_shift.action", 1);' >> $prefs_file elif [ $BUILD_WIN == 1 ]; then perl -pi -e 's/%GECKO_VERSION%/'"$GECKO_VERSION_WIN"'/g' $prefs_file elif [ $BUILD_LINUX == 1 ]; then # Modify platform-specific prefs perl -pi -e 's/pref\("browser\.preferences\.instantApply", false\);/pref\("browser\.preferences\.instantApply", true);/' $prefs_file perl -pi -e 's/%GECKO_VERSION%/'"$GECKO_VERSION_LINUX"'/g' $prefs_file # Auto-scroll is disabled by default on Linux # https://bugzilla.mozilla.org/show_bug.cgi?id=1747208 perl -pi -e 's/pref\("general\.autoScroll", false\);/pref\("general.autoScroll", true);/' $prefs_file fi # Clear list of built-in add-ons, but leave the en-US dictionary echo '{"dictionaries": {"en-US": "dictionaries/en-US.dic"}, "system": []}' > chrome/browser/content/browser/built_in_addons.json # chrome.manifest mv chrome.manifest zotero.manifest mv chrome.manifest-fx chrome.manifest # TEMP #echo "manifest zotero.manifest" >> "$base_dir/chrome.manifest" cat zotero.manifest >> chrome.manifest rm zotero.manifest # Update channel perl -pi -e 's/pref\("app\.update\.channel", "[^"]*"\);/pref\("app\.update\.channel", "'"$UPDATE_CHANNEL"'");/' $prefs_file echo -n "Channel: " grep app.update.channel $prefs_file echo # Add devtools prefs if [ $DEVTOOLS -eq 1 ]; then echo >> $prefs_file echo "// Dev Tools" >> $prefs_file echo 'pref("devtools.debugger.remote-enabled", true);' >> $prefs_file if [ $UPDATE_CHANNEL != "beta" ]; then echo 'pref("devtools.debugger.prompt-connection", false);' >> $prefs_file fi # Use 'zotero' instead of 'zotero-bin' when passing -jsdebugger flag on Linux, since we need # that to pass application.ini replace_line 'let command = Services.dirsvc.get\("XREExeF", Ci.nsIFile\).path;' \ 'let command = Services.dirsvc.get("XREExeF", Ci.nsIFile).path; command = command.replace("zotero-bin", "zotero");' \ chrome/devtools/modules/devtools/client/framework/browser-toolbox/Launcher.sys.mjs # Fix source display breaking when switching windows in the Browser Toolbox. # When the user switches which chrome window is being inspected (via the frame # picker), the thread actor's _onWindowReady handler clears all debuggees and # source actors, then re-adds debuggees. But it never calls addAllSources() to # re-emit the existing scripts — it only does that for BFCache navigations. # Since the scripts already exist (they're not new), onNewScript won't fire, # so the debugger's source list stays empty. Fix: also call addAllSources() # after frame switching, just like BFCache. replace_line '_onWindowReady\(\{ isTopLevel, isBFCache \}\)' \ '_onWindowReady({ isTopLevel, isBFCache, isFrameSwitching })' \ chrome/devtools/modules/devtools/server/actors/thread.js replace_line 'if \(isBFCache\) {' \ 'if (isBFCache || isFrameSwitching) {' \ chrome/devtools/modules/devtools/server/actors/thread.js # Suppress "Failed to get the active browserId" error when profile recording starts replace_line 'console\.error\(' \ 'if (false) console.error(' \ chrome/devtools/modules/devtools/shared/performance-new/recording-utils.sys.mjs # Stub out profile favicon lookup since we don't have PlacesUtils replace_line 'return getPageFavicons\(pageUrls\);' \ 'return pageUrls ? pageUrls.map(() => null) : [];' \ chrome/devtools/modules/devtools/client/performance-new/shared/background.sys.mjs # Use our profilerViewer.xhtml to display profiles. # We can't use basicViewer because that loads Zotero scripts, and profiling # runs in the Browser Toolbox child process, where a second Zotero instance # would collide with the locked database. replace_line 'const contentBrowser = await new Promise\(resolveOnContentBrowserCreated =>' \ 'if (typeof win.openWebLinkIn !== "function") { const ww = Cc["\@mozilla.org\/embedcomp\/window-watcher;1"].getService( Ci.nsIWindowWatcher ); const arg = { uri: urlToLoad }; arg.wrappedJSObject = arg; const viewerWin = ww.openWindow( null, "chrome:\/\/zotero\/content\/standalone\/profilerViewer.xhtml", null, "chrome,dialog=no,resizable,centerscreen,scrollbars", arg ); return await new Promise(resolve => { viewerWin.addEventListener("load", () => { resolve(viewerWin.document.getElementById("content")); }, { once: true }); }); } const contentBrowser = await new Promise(resolveOnContentBrowserCreated =>' \ chrome/devtools/modules/devtools/client/performance-new/shared/browser.js fi # 5.0.96.3 / 5.0.97-beta.37+ddc7be75c VERSION=`cat version` # 5.0.96 / 5.0.97 VERSION_NUMERIC=`perl -ne 'print and last if s/^(\d+\.\d+(\.\d+)?).*/\1/;' version` if [ -z "$VERSION" ]; then echo "Version number not found in version file" exit 1 fi rm version echo echo "Version: $VERSION" # Delete Mozilla signing info if present rm -rf META-INF # Copy branding cp -R "$CALLDIR"/assets/branding/locale/brand.{dtd,properties} chrome/en-US/locale/branding/ # Copy browser localization .ftl files for locale in `ls chrome/locale/`; do mkdir -p localization/$locale/branding cp "$CALLDIR/assets/branding/locale/brand.ftl" localization/$locale/branding/brand.ftl mkdir -p localization/$locale/toolkit/global cp chrome/locale/$locale/zotero/mozilla/arrowscrollbox.ftl localization/$locale/toolkit/global cp chrome/locale/$locale/zotero/mozilla/textActions.ftl localization/$locale/toolkit/global cp chrome/locale/$locale/zotero/mozilla/wizard.ftl localization/$locale/toolkit/global mkdir -p localization/$locale/browser cp chrome/locale/$locale/zotero/mozilla/browserSets.ftl localization/$locale/browser cp chrome/locale/$locale/zotero/mozilla/menubar.ftl localization/$locale/browser mkdir -p localization/$locale/devtools/client cp chrome/locale/$locale/zotero/mozilla/toolbox.ftl localization/$locale/devtools/client # TEMP: Until we've created zotero.ftl in all locales touch chrome/locale/$locale/zotero/zotero.ftl cp chrome/locale/$locale/zotero/*.ftl localization/$locale/ done # Add to chrome manifest echo "" >> chrome.manifest cat "$CALLDIR/assets/chrome.manifest" >> chrome.manifest replace_line 'handle: function bch_handle\(cmdLine\) {' 'handle: function bch_handle(cmdLine) { \/\/ TEST_OPTIONS_PLACEHOLDER ' modules/BrowserContentHandler.sys.mjs export CALLDIR && perl -pi -e 'BEGIN { local $/; open $fh, "$ENV{CALLDIR}/assets/commandLineHandler.js"; $replacement = <$fh>; close $fh; } s/\/\/ TEST_OPTIONS_PLACEHOLDER/$replacement/' modules/BrowserContentHandler.sys.mjs # Don't try to initialize Places, since we've removed its files #replace_line 'this._placesInitialized = true;' 'if (true) return; this._placesInitialized = true;' components/places/PlacesBrowserStartup.sys.mjs # Move test files to root directory if [ $include_tests -eq 1 ]; then cat test/chrome.manifest >> chrome.manifest rm test/chrome.manifest cp -R test/tests "$base_dir/tests" fi # Copy platform-specific assets if [ $BUILD_MAC == 1 ]; then copy_dir "$CALLDIR/assets/mac" . elif [ $BUILD_WIN == 1 ]; then copy_dir "$CALLDIR/assets/win" . elif [ $BUILD_LINUX == 1 ]; then copy_dir "$CALLDIR/assets/unix" . fi # Add word processor plug-ins echo >> chrome.manifest if [ $BUILD_MAC == 1 ]; then pluginDir="$CALLDIR/modules/zotero-word-for-mac-integration" mkdir -p "integration/word-for-mac" cp -RH "$pluginDir/components" \ "$pluginDir/resource" \ "$pluginDir/chrome.manifest" \ "integration/word-for-mac" echo -n "Word for Mac plugin version: " cat "integration/word-for-mac/resource/version.txt" echo echo >> $prefs_file cat "$CALLDIR/modules/zotero-word-for-mac-integration/defaults/preferences/zoteroMacWordIntegration.js" >> $prefs_file echo >> $prefs_file echo "manifest integration/word-for-mac/chrome.manifest" >> chrome.manifest elif [ $BUILD_WIN == 1 ]; then pluginDir="$CALLDIR/modules/zotero-word-for-windows-integration" mkdir -p "integration/word-for-windows" cp -RH "$pluginDir/components" \ "$pluginDir/resource" \ "$pluginDir/chrome.manifest" \ "integration/word-for-windows" echo -n "Word for Windows plugin version: " cat "integration/word-for-windows/resource/version.txt" echo echo >> $prefs_file cat "$CALLDIR/modules/zotero-word-for-windows-integration/defaults/preferences/zoteroWinWordIntegration.js" >> $prefs_file echo >> $prefs_file echo "manifest integration/word-for-windows/chrome.manifest" >> chrome.manifest fi # Libreoffice plugin for all platforms pluginDir="$CALLDIR/modules/zotero-libreoffice-integration" mkdir -p "integration/libreoffice" cp -RH "$pluginDir/chrome" \ "$pluginDir/components" \ "$pluginDir/resource" \ "$pluginDir/chrome.manifest" \ "integration/libreoffice" echo -n "LibreOffice plugin version: " cat "integration/libreoffice/resource/version.txt" echo echo >> $prefs_file cat "$CALLDIR/modules/zotero-libreoffice-integration/defaults/preferences/zoteroLibreOfficeIntegration.js" >> $prefs_file echo >> $prefs_file echo "manifest integration/libreoffice/chrome.manifest" >> chrome.manifest # Delete files that shouldn't be distributed find chrome -name .DS_Store -exec rm -f {} \; # Zip browser and Zotero files into omni.ja if [ $quick_build -eq 1 ]; then # If quick build, don't compress or optimize zip -qrXD omni.ja * else zip -qr9XD omni.ja * python3 "$CALLDIR/scripts/optimizejars.py" --optimize ./ ./ ./ fi mv omni.ja .. cd "$CALLDIR" rm -rf "$omni_dir" # Copy updater.ini cp "$CALLDIR/assets/updater.ini" "$base_dir" # Adjust chrome.manifest #perl -pi -e 's^(chrome|resource)/^jar:zotero.jar\!/$1/^g' "$BUILD_DIR/zotero/chrome.manifest" # Copy application.ini and modify cp "$CALLDIR/assets/application.ini" "$app_dir/application.ini" perl -pi -e "s/\{\{VERSION}}/$VERSION/" "$app_dir/application.ini" perl -pi -e "s/\{\{BUILDID}}/$BUILD_ID/" "$app_dir/application.ini" # Remove unnecessary files find "$BUILD_DIR" -name .DS_Store -exec rm -f {} \; # Mac if [ $BUILD_MAC == 1 ]; then echo 'Building Zotero.app' # Set up directory structure APPDIR="$STAGE_DIR/Zotero.app" rm -rf "$APPDIR" mkdir "$APPDIR" chmod 755 "$APPDIR" cp -r "$CALLDIR/mac/Contents" "$APPDIR" CONTENTSDIR="$APPDIR/Contents" # Merge relevant assets from Firefox mkdir "$CONTENTSDIR/MacOS" cp -r "$MAC_RUNTIME_PATH/Contents/MacOS/"!(firefox|firefox-bin|crashhelper|crashreporter.app|minidump-analyzer|nmhproxy|pingsender|updater.app) "$CONTENTSDIR/MacOS" cp -r "$MAC_RUNTIME_PATH/Contents/Resources/"!(application.ini|Assets.car|browser|defaults|precomplete|removed-files|updater.ini|update-settings.ini|webapprt*|*.icns|*.lproj) "$CONTENTSDIR/Resources" # Add our custom ChannelPrefs.framework and change channel if not a source build mkdir "$CONTENTSDIR/Frameworks" tar xvf "$CALLDIR/mac/ChannelPrefs.framework.tar.xz" -C "$CONTENTSDIR/Frameworks" if [ "$UPDATE_CHANNEL" != "source" ]; then "$CALLDIR/mac/set-channel-prefs-channel" "$CONTENTSDIR/Frameworks/ChannelPrefs.framework/ChannelPrefs" source $UPDATE_CHANNEL fi # Use our own launcher check_lfs_file "$CALLDIR/mac/zotero.xz" xz -d --stdout "$CALLDIR/mac/zotero.xz" > "$CONTENTSDIR/MacOS/zotero" chmod 755 "$CONTENTSDIR/MacOS/zotero" # Overlay custom Firefox components (e.g., XUL or libmozglue.dylib) if [ -n "$custom_components_hash_mac" ]; then cp -R "$MAC_RUNTIME_PATH/../MacOS/." "$CONTENTSDIR/MacOS/" fi # Use our own updater, because Mozilla's requires updates signed by Mozilla cd "$CONTENTSDIR/MacOS" check_lfs_file "$CALLDIR/mac/updater.tar.xz" tar xf "$CALLDIR/mac/updater.tar.xz" # Modify Info.plist perl -pi -e "s/\{\{VERSION\}\}/$VERSION/" "$CONTENTSDIR/Info.plist" perl -pi -e "s/\{\{VERSION_NUMERIC\}\}/$VERSION_NUMERIC/" "$CONTENTSDIR/Info.plist" if [ $UPDATE_CHANNEL == "beta" ] || [ $UPDATE_CHANNEL == "dev" ] || [ $UPDATE_CHANNEL == "source" ]; then perl -pi -e "s/org\.zotero\.zotero/org.zotero.zotero-$UPDATE_CHANNEL/" "$CONTENTSDIR/Info.plist" fi perl -pi -e "s/\{\{VERSION\}\}/$VERSION/" "$CONTENTSDIR/Info.plist" # Needed for "monkeypatch" Windows builds: # http://www.nntp.perl.org/group/perl.perl5.porters/2010/08/msg162834.html rm -f "$CONTENTSDIR/Info.plist.bak" echo grep -B 1 org.zotero.zotero "$CONTENTSDIR/Info.plist" echo grep -A 1 CFBundleShortVersionString "$CONTENTSDIR/Info.plist" echo grep -A 1 CFBundleVersion "$CONTENTSDIR/Info.plist" echo # Copy app files copy_dir "$base_dir" "$CONTENTSDIR/Resources" # Add word processor plug-ins mkdir "$CONTENTSDIR/Resources/integration" cp -RH "$CALLDIR/modules/zotero-libreoffice-integration/install" "$CONTENTSDIR/Resources/integration/libreoffice" cp -RH "$CALLDIR/modules/zotero-word-for-mac-integration/install" "$CONTENTSDIR/Resources/integration/word-for-mac" # Delete extraneous files find "$CONTENTSDIR" -depth -type d -name .git -exec rm -rf {} \; find "$CONTENTSDIR" \( -name .DS_Store -or -name update.rdf \) -exec rm -f {} \; # Add Safari extensions -- this depends on signing but needs to be done before generating # the precomplete file # # $SAFARI_APPEX is a stub appex built from the safari-web-extension wrapper project. The web # extension itself comes from $SAFARI_EXT_RESOURCES (a zotero-connectors build/safari # directory), which replaces the stub's placeholder resources here before signing. # # $SAFARI_APP_EXTENSION is an optional prebuilt legacy Safari App Extension, embedded # alongside the web extension for Safari versions that can't load Developer ID web # extensions (supported in Safari 18.4 and later). On Safari versions that can load the # web extension, the SFSafariAppExtensionBundleIdentifiersToReplace key causes it to # replace the App Extension. if [[ $SIGN == 1 ]] && [[ -n "$SAFARI_APPEX" ]] && [[ -d "$SAFARI_APPEX" ]]; then if [[ -z "${SAFARI_EXT_RESOURCES:-}" ]] || [[ ! -f "$SAFARI_EXT_RESOURCES/manifest.json" ]]; then echo "SAFARI_EXT_RESOURCES doesn't contain a web extension -- aborting" 2>&1 exit 1 fi bundle_identifier=$(/usr/libexec/PlistBuddy -c "Print CFBundleIdentifier" "$APPDIR/Contents/Info.plist") mkdir "$APPDIR/Contents/PlugIns" webext_appex="$APPDIR/Contents/PlugIns/ZoteroSafariWebExtension.appex" cp -R "$SAFARI_APPEX" "$webext_appex" appex_resources="$webext_appex/Contents/Resources" rm -rf "$appex_resources" mkdir "$appex_resources" cp -R "$SAFARI_EXT_RESOURCES/." "$appex_resources/" # Show the connector version in Safari connector_version=$(python3 -c "import json, sys; print(json.load(open(sys.argv[1]))['version'])" "$appex_resources/manifest.json") if [[ $connector_version == *999* ]] && [ "$UPDATE_CHANNEL" != "test" ]; then echo "Placeholder connector version $connector_version not allowed for '$UPDATE_CHANNEL' channel -- aborting" 2>&1 exit 1 fi /usr/libexec/PlistBuddy -c "Set CFBundleShortVersionString $connector_version" \ "$webext_appex/Contents/Info.plist" /usr/libexec/PlistBuddy -c "Set CFBundleVersion $connector_version" \ "$webext_appex/Contents/Info.plist" # Give the appex the same bundle identifier prefix as the parent app /usr/libexec/PlistBuddy -c "Set CFBundleIdentifier $bundle_identifier.SafariWebExtension" \ "$webext_appex/Contents/Info.plist" # Replace the legacy App Extension on Safari versions that can load the web extension /usr/libexec/PlistBuddy -c "Add :NSExtension:SFSafariAppExtensionBundleIdentifiersToReplace array" \ "$webext_appex/Contents/Info.plist" /usr/libexec/PlistBuddy -c "Add :NSExtension:SFSafariAppExtensionBundleIdentifiersToReplace:0 string $bundle_identifier.SafariExtension" \ "$webext_appex/Contents/Info.plist" # Add legacy Safari App Extension if [[ -n "${SAFARI_APP_EXTENSION:-}" ]]; then if [[ ! -d "$SAFARI_APP_EXTENSION" ]]; then echo "SAFARI_APP_EXTENSION not found at $SAFARI_APP_EXTENSION -- aborting" 2>&1 exit 1 fi appext_appex="$APPDIR/Contents/PlugIns/ZoteroSafariExtension.appex" cp -R "$SAFARI_APP_EXTENSION" "$appext_appex" rm -rf "$appext_appex/Contents/Resources/safari/test" /usr/libexec/PlistBuddy -c "Set CFBundleIdentifier $bundle_identifier.SafariExtension" \ "$appext_appex/Contents/Info.plist" fi fi # Copy over removed-files and make a precomplete file pushd "$CONTENTSDIR/Resources/" cp "$CALLDIR/update-packaging/removed-files_mac" removed-files python3 "$CALLDIR/scripts/createprecomplete.py" if [ ! -s precomplete ]; then echo "precomplete file not created -- aborting" 2>&1 exit 1 fi popd # Sign if [ $SIGN == 1 ]; then # Unlock keychain if a password is provided (necessary for building from a shell) if [ -n "$KEYCHAIN_PASSWORD" ]; then security -v unlock-keychain -p "$KEYCHAIN_PASSWORD" ~/Library/Keychains/$KEYCHAIN.keychain-db fi # Clear extended attributes, which can cause codesign to fail /usr/bin/xattr -cr "$APPDIR" # Sign libraries and updater without entitlements /usr/bin/codesign --force --options runtime --sign "$DEVELOPER_ID" \ "$APPDIR/Contents/MacOS/XUL" \ "$APPDIR/Contents/MacOS/updater.app/Contents/Frameworks/UpdateSettings.framework" \ "$APPDIR/Contents/MacOS/updater.app" \ "$APPDIR/Contents/Frameworks/ChannelPrefs.framework" find "$APPDIR/Contents" -name '*.dylib' -print0 | xargs -0 /usr/bin/codesign --force --options runtime --sign "$DEVELOPER_ID" # Sign bundled apps and main app bundle entitlements_file="$CALLDIR/mac/entitlements.xml" find "$APPDIR/Contents" -name '*.app' -not -name "updater.app" -print0 | xargs -0 /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" # Sign .jnilib (Java native shared library) within LibreOffice extension, since notarization # started failing without this. The .jnilib is within a .jar within the .oxt, so we have to # extract both, sign the libraries, and then update each ZIP. # # TODO: Remove this block once the plugin ships a jna.jar without the macOS native # libraries, which are never loaded (JNA is used only on Windows) pushd "$BUILD_DIR" mkdir libreoffice-repack cd libreoffice-repack unzip -q "$APPDIR/Contents/Resources/integration/libreoffice/Zotero_LibreOffice_Integration.oxt" external_jars/jna.jar unzip -q external_jars/jna.jar 'com/sun/jna/darwin*/libjnidispatch.jnilib' /usr/bin/codesign --force --options runtime --sign "$DEVELOPER_ID" com/sun/jna/darwin*/libjnidispatch.jnilib zip -u external_jars/jna.jar com/sun/jna/darwin*/libjnidispatch.jnilib zip -u "$APPDIR/Contents/Resources/integration/libreoffice/Zotero_LibreOffice_Integration.oxt" external_jars/jna.jar cd .. rm -rf libreoffice-repack popd # Sign Safari extensions # # Even though they're signed by Xcode, we sign them again to make sure they match the parent app signature for appex in "$APPDIR"/Contents/PlugIns/*.appex; do if [ ! -d "$appex" ]; then continue fi echo # Extract entitlements, which differ from parent app /usr/bin/codesign -d --entitlements "$BUILD_DIR/safari-entitlements.plist" --xml "$appex" find "$appex/Contents" -name '*.dylib' -exec /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" {} \; /usr/bin/codesign --force --options runtime --entitlements "$BUILD_DIR/safari-entitlements.plist" --sign "$DEVELOPER_ID" "$appex" done # Sign final app package echo /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" "$APPDIR" # Verify app /usr/bin/codesign --verify -vvvv "$APPDIR" # Verify Safari extensions for appex in "$APPDIR"/Contents/PlugIns/*.appex; do if [ ! -d "$appex" ]; then continue fi echo /usr/bin/codesign --verify -vvvv "$appex" done elif [ -n "$custom_components_hash_mac" ]; then # Mozilla's helper apps (plugin-container, GPU helper, etc.) are signed with Mozilla's Team ID # and the hardened runtime, so without our signature they can't load custom components such as # libmozglue.dylib and fail to launch. Re-sign them ad hoc, which removes both. (Signed builds # re-sign everything with our Developer ID above.) find "$APPDIR/Contents/MacOS" -maxdepth 1 -name '*.app' -not -name "updater.app" -print0 \ | xargs -0 /usr/bin/codesign --force --sign - fi # Build and notarize disk image if [ $PACKAGE == 1 ]; then if [ $MAC_NATIVE == 1 ]; then echo "Creating Mac installer" dmg="$DIST_DIR/Zotero-$VERSION.dmg" "$CALLDIR/mac/pkg-dmg" --source "$STAGE_DIR/Zotero.app" \ --target "$dmg" \ --sourcefile --volname Zotero --copy "$CALLDIR/mac/DSStore:/.DS_Store" \ --symlink /Applications:"/Drag Here to Install" > /dev/null if [ "$UPDATE_CHANNEL" != "test" ]; then # Upload disk image to Apple "$CALLDIR/scripts/notarize_mac_app" "$dmg" echo # Staple notarization info to disk image "$CALLDIR/scripts/notarization_stapler" "$dmg" echo "Notarization complete" else echo "Test build -- skipping notarization" fi echo else echo 'Not building on Mac; creating Mac distribution as a zip file' rm -f "$DIST_DIR/Zotero_mac.zip" cd "$STAGE_DIR" && zip -rqX "$DIST_DIR/Zotero-${VERSION}_mac.zip" Zotero.app fi fi fi # Windows if [ $BUILD_WIN == 1 ]; then echo "Building Windows common" COMMON_APPDIR="$STAGE_DIR/Zotero_common" mkdir "$COMMON_APPDIR" # Package non-arch-specific components if [ $PACKAGE -eq 1 ]; then # Copy installer files cp -r "$CALLDIR/win/installer" "$BUILD_DIR/win_installer" perl -pi -e "s/\{\{VERSION}}/$VERSION/" "$BUILD_DIR/win_installer/defines.nsi" mkdir "$COMMON_APPDIR/uninstall" # Compress 7zSD.sfx upx --best -o "`cygpath -w \"$BUILD_DIR/7zSD.sfx\"`" \ "`cygpath -w \"$CALLDIR/win/installer/7zstub/firefox/7zSD.sfx\"`" > /dev/null fi if [[ -n $arch ]]; then archs=("$(get_canonical_arch w $arch)"); else archs=(win-x64 win-arm64 win32); fi for arch in "${archs[@]}"; do echo "Building Zotero_$arch" runtime_path="${WIN_RUNTIME_PATH_PREFIX}$arch" # Set up directory APPDIR="$STAGE_DIR/Zotero_$arch" mkdir "$APPDIR" # Copy relevant assets from Firefox # # 'i686' is a huge directory containing x86 versions of xul.dll and other files in # Firefox ARM64 builds for use with the EME DRM plugins cp -R "$runtime_path"/!(application.ini|browser|crashhelper.exe|crashreporter*|default-browser-agent.exe|defaultagent*|defaults|desktop-launcher|devtools-files|firefox*|i686|maintenanceservice*|minidump-analyzer.exe|nmhproxy.exe|pingsender.exe|private_browsing*|precomplete|removed-files|uninstall|update*) "$APPDIR" # Copy zotero.exe, which is built directly from Firefox source and then modified by # ResourceHacker to add icons check_lfs_file "$CALLDIR/win/zotero.exe.tar.xz" tar xf "$CALLDIR/win/zotero.exe.tar.xz" --to-stdout zotero_$arch.exe > "$APPDIR/zotero.exe" # Use our own updater, because Mozilla's requires updates signed by Mozilla check_lfs_file "$CALLDIR/win/updater.exe.tar.xz" tar xf "$CALLDIR/win/updater.exe.tar.xz" --to-stdout updater-$arch.exe > "$APPDIR/updater.exe" # Update .exe version numbers (only possible on Windows) if [ $WIN_NATIVE == 1 ]; then # FileVersion is limited to four integers, so it won't be properly updated for non-release # builds (e.g., we'll show 5.0.97.0 for 5.0.97-beta.37). ProductVersion will be the full # version string. rcedit "`cygpath -w \"$APPDIR/zotero.exe\"`" \ --set-file-version "$VERSION_NUMERIC" \ --set-product-version "$VERSION" rcedit "`cygpath -w \"$APPDIR/updater.exe\"`" \ --set-file-version "$VERSION_NUMERIC" \ --set-product-version "$VERSION" fi # Copy app files copy_dir "$base_dir" "$APPDIR" #mv "$APPDIR/app/application.ini" "$APPDIR/" # Copy in common files copy_dir "$COMMON_APPDIR" "$APPDIR" cat "$CALLDIR/win/installer/updater_append.ini" >> "$APPDIR/updater.ini" # Add devtools #if [ $DEVTOOLS -eq 1 ]; then # # Create devtools.jar # cd "$BUILD_DIR" # mkdir -p devtools/locale # cp -r "$runtime_path"/devtools-files/chrome/devtools/* devtools/ # cp -r "$runtime_path"/devtools-files/chrome/locale/* devtools/locale/ # cd devtools # zip -r -q ../devtools.jar * # cd .. # rm -rf devtools # mv devtools.jar "$APPDIR" # # cp "$runtime_path/devtools-files/components/interfaces.xpt" "$APPDIR/components/" #fi # Add word processor plug-ins mkdir -p "$APPDIR/integration" cp -RH "$CALLDIR/modules/zotero-libreoffice-integration/install" "$APPDIR/integration/libreoffice" cp -RH "$CALLDIR/modules/zotero-word-for-windows-integration/install" "$APPDIR/integration/word-for-windows" if [ $arch = 'win32' ]; then rm "$APPDIR/integration/word-for-windows/libzoteroWinWordIntegration_x64.dll" rm "$APPDIR/integration/word-for-windows/libzoteroWinWordIntegration_ARM64.dll" elif [ $arch = 'win-x64' ]; then mv "$APPDIR/integration/word-for-windows/libzoteroWinWordIntegration_x64.dll" \ "$APPDIR/integration/word-for-windows/libzoteroWinWordIntegration.dll" rm "$APPDIR/integration/word-for-windows/libzoteroWinWordIntegration_ARM64.dll" elif [ $arch = 'win-arm64' ]; then mv "$APPDIR/integration/word-for-windows/libzoteroWinWordIntegration_ARM64.dll" \ "$APPDIR/integration/word-for-windows/libzoteroWinWordIntegration.dll" rm "$APPDIR/integration/word-for-windows/libzoteroWinWordIntegration_x64.dll" fi # Delete extraneous files find "$APPDIR" -depth -type d -name .git -exec rm -rf {} \; find "$APPDIR" \( -name .DS_Store -or -name '.git*' -or -name '.travis.yml' -or -name update.rdf -or -name '*.bak' \) -exec rm -f {} \; find "$APPDIR" \( -name '*.exe' -or -name '*.dll' \) -exec chmod 755 {} \; if [[ $PACKAGE -eq 1 ]] && [[ $SIGN -eq 1 ]]; then "$CALLDIR/win/codesign" "$APPDIR/zotero.exe" "$SIGNATURE_DESC" sleep $SIGNTOOL_DELAY "$CALLDIR/win/codesign" "$APPDIR/updater.exe" "$SIGNATURE_DESC Updater" sleep $SIGNTOOL_DELAY # Re-sign modified xul.dll "$CALLDIR/win/codesign" "$APPDIR/xul.dll" "$SIGNATURE_DESC" sleep $SIGNTOOL_DELAY "$CALLDIR/win/codesign" "$APPDIR/integration/word-for-windows/libzoteroWinWordIntegration.dll" "$SIGNATURE_DESC Word Plugin" fi # Copy over removed-files and make a precomplete file pushd "$APPDIR" cp "$CALLDIR/update-packaging/removed-files_$arch" removed-files python3 "$CALLDIR/scripts/createprecomplete.py" if [ ! -s precomplete ]; then echo "precomplete file not created -- aborting" 2>&1 exit 1 fi popd if [ $PACKAGE -eq 1 ]; then if [ $WIN_NATIVE -eq 1 ]; then echo "Creating Windows installer" # Build uninstaller if [ "$arch" = "win32" ]; then "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" /V1 "`cygpath -w \"$BUILD_DIR/win_installer/uninstaller.nsi\"`" elif [ "$arch" = "win-x64" ]; then "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" /DHAVE_64BIT_BUILD /V1 "`cygpath -w \"$BUILD_DIR/win_installer/uninstaller.nsi\"`" elif [ "$arch" = "win-arm64" ]; then "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" /DHAVE_64BIT_BUILD /D_ARM64_ /V1 "`cygpath -w \"$BUILD_DIR/win_installer/uninstaller.nsi\"`" fi mv "$BUILD_DIR/win_installer/helper.exe" "$APPDIR/uninstall" if [ $SIGN -eq 1 ]; then "$CALLDIR/win/codesign" "$APPDIR/uninstall/helper.exe" "$SIGNATURE_DESC Uninstaller" sleep $SIGNTOOL_DELAY fi if [ "$arch" = "win32" ]; then INSTALLER_PATH="$DIST_DIR/Zotero-${VERSION}_win32_setup.exe" elif [ "$arch" = "win-x64" ]; then INSTALLER_PATH="$DIST_DIR/Zotero-${VERSION}_x64_setup.exe" elif [ "$arch" = "win-arm64" ]; then INSTALLER_PATH="$DIST_DIR/Zotero-${VERSION}_arm64_setup.exe" fi # Stage installer INSTALLER_STAGE_DIR="$BUILD_DIR/win_installer/staging" rm -rf "$INSTALLER_STAGE_DIR" mkdir "$INSTALLER_STAGE_DIR" cp -r "$APPDIR" "$INSTALLER_STAGE_DIR/core" # Build and sign setup.exe if [ "$arch" = "win32" ]; then "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" /V1 "`cygpath -w \"$BUILD_DIR/win_installer/installer.nsi\"`" elif [ "$arch" = "win-x64" ]; then "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" /DHAVE_64BIT_BUILD /V1 "`cygpath -w \"$BUILD_DIR/win_installer/installer.nsi\"`" elif [ "$arch" = "win-arm64" ]; then "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" /DHAVE_64BIT_BUILD /D_ARM64_ /V1 "`cygpath -w \"$BUILD_DIR/win_installer/installer.nsi\"`" fi mv "$BUILD_DIR/win_installer/setup.exe" "$INSTALLER_STAGE_DIR" if [ $SIGN == 1 ]; then "$CALLDIR/win/codesign" "$INSTALLER_STAGE_DIR/setup.exe" "$SIGNATURE_DESC Setup" sleep $SIGNTOOL_DELAY fi # Compress application cd "$INSTALLER_STAGE_DIR" && 7z a -r -t7z "`cygpath -w \"$BUILD_DIR/app_$arch.7z\"`" \ -mx -m0=BCJ2 -m1=LZMA:d24 -m2=LZMA:d19 -m3=LZMA:d19 -mb0:1 -mb0s1:2 -mb0s2:3 > /dev/null # Combine 7zSD.sfx and app.tag into setup.exe cat "$BUILD_DIR/7zSD.sfx" "$CALLDIR/win/installer/app.tag" \ "$BUILD_DIR/app_$arch.7z" > "$INSTALLER_PATH" # Sign installer .exe if [ $SIGN == 1 ]; then "$CALLDIR/win/codesign" "$INSTALLER_PATH" "$SIGNATURE_DESC Installer" fi chmod 755 "$INSTALLER_PATH" else echo 'Not building on Windows; only building zip file' fi cd "$STAGE_DIR" zip -rqX "$DIST_DIR/Zotero-${VERSION}_$arch.zip" Zotero_$arch fi done rm -rf "$COMMON_APPDIR" fi # Linux if [ $BUILD_LINUX == 1 ]; then if [[ -n $arch ]]; then archs=("$(get_canonical_arch l $arch)") else archs=(x64 arm64) fi for arch in "${archs[@]}"; do [[ $arch == x64 ]] && arch="x86_64" runtime_path="${LINUX_RUNTIME_PATH_PREFIX}${arch}" # Set up directory echo 'Building Zotero_linux-'$arch APPDIR="$STAGE_DIR/Zotero_linux-$arch" rm -rf "$APPDIR" mkdir "$APPDIR" # Merge relevant assets from Firefox cp -r "$runtime_path/"!(application.ini|browser|crashhelper|crashreporter|crashreporter.ini|defaults|devtools-files|firefox|pingsender|precomplete|removed-files|run-mozilla.sh|update-settings.ini|updater|updater.ini) "$APPDIR" # Use our own launcher that calls the original Firefox executable with -app mv "$APPDIR"/firefox-bin "$APPDIR"/zotero-bin cp "$CALLDIR/linux/zotero" "$APPDIR"/zotero # Copy Ubuntu launcher files cp "$CALLDIR/linux/zotero.desktop" "$APPDIR" cp "$CALLDIR/linux/set_launcher_icon" "$APPDIR" # Use our own updater, because Mozilla's requires updates signed by Mozilla check_lfs_file "$CALLDIR/linux/updater.tar.xz" tar xf "$CALLDIR/linux/updater.tar.xz" --to-stdout updater-$arch > "$APPDIR/updater" chmod 755 "$APPDIR/updater" # Copy app files copy_dir "$base_dir" "$APPDIR" # Add word processor plug-ins mkdir "$APPDIR/integration" cp -RH "$CALLDIR/modules/zotero-libreoffice-integration/install" "$APPDIR/integration/libreoffice" # Firefox includes an 'icons' folder with updater.png, but some Linux distro builds omit it mkdir -p "$APPDIR/icons" # Copy icons cp "$CALLDIR/linux/icons/icon32.png" "$APPDIR/icons/" cp "$CALLDIR/linux/icons/icon64.png" "$APPDIR/icons/" cp "$CALLDIR/linux/icons/icon128.png" "$APPDIR/icons/" cp "$CALLDIR/linux/icons/symbolic.svg" "$APPDIR/icons/" # Delete extraneous files find "$APPDIR" -depth -type d -name .git -exec rm -rf {} \; find "$APPDIR" \( -name .DS_Store -or -name update.rdf \) -exec rm -f {} \; # Copy over removed-files and make a precomplete file pushd "$APPDIR" cp "$CALLDIR/update-packaging/removed-files_linux-$arch" removed-files python3 "$CALLDIR/scripts/createprecomplete.py" if [ ! -s precomplete ]; then echo "precomplete file not created -- aborting" 2>&1 exit 1 fi popd if [ $PACKAGE == 1 ]; then # Create tar rm -f "$DIST_DIR/Zotero-${VERSION}_linux-$arch.tar.xz" cd "$STAGE_DIR" tar -cJf "$DIST_DIR/Zotero-${VERSION}_linux-$arch.tar.xz" "Zotero_linux-$arch" fi done fi rm -rf $BUILD_DIR