zotero: initial commit for building from source

Firefox 115 is needed to match upstream and avoid endless patch failures
of zotero.
It requires cbindgen 0.26 to compile (Firefox 128 supports cbindgen
0.27+).
See https://discuss.haiku-os.org/t/progress-on-porting-firefox/13493/234
This commit is contained in:
Mynacol
2026-02-11 19:04:43 +01:00
parent 70ee9e4a03
commit ce00ee56de
6 changed files with 531 additions and 185 deletions
@@ -0,0 +1,118 @@
diff --git a/app/scripts/fetch_xulrunner b/app/scripts/fetch_xulrunner
index 0d871782c3..bea85feae9 100755
--- a/app/scripts/fetch_xulrunner
+++ b/app/scripts/fetch_xulrunner
@@ -422,73 +422,11 @@ cd xulrunner
if [ $BUILD_MAC == 1 ]; then
GECKO_VERSION="$GECKO_VERSION_MAC"
- DOWNLOAD_URL="https://ftp.mozilla.org/pub/firefox/releases/$GECKO_VERSION"
- rm -rf Firefox.app
- if [ -e "Firefox $GECKO_VERSION.app.zip" ]; then
- echo "Using Firefox $GECKO_VERSION.app.zip"
- unzip "Firefox $GECKO_VERSION.app.zip"
- else
- curl -o Firefox.dmg "$DOWNLOAD_URL/mac/en-US/Firefox%20$GECKO_VERSION.dmg"
- set +e
- hdiutil detach -quiet /Volumes/Firefox 2>/dev/null
- set -e
- hdiutil attach -quiet Firefox.dmg
- cp -a /Volumes/Firefox/Firefox.app .
- hdiutil detach -quiet /Volumes/Firefox
- fi
-
- # Download custom components (e.g., XUL), as an xz-compressed tarball of the MacOS folder with
- # custom files in it
- echo
- rm -rf MacOS
- if [ -n "$custom_components_hash_mac" ]; then
- if [ -e "Firefox $GECKO_VERSION MacOS.zip" ]; then
- echo "Using Firefox $GECKO_VERSION MacOS.zip"
- unzip "Firefox $GECKO_VERSION MacOS.zip"
- else
- echo "Downloading custom Firefox components"
- echo
- curl -o MacOS.tar.xz "${custom_components_url}mac/$custom_components_hash_mac.tar.xz"
-
- # Verify hash
- if [[ "`uname`" = "Darwin" ]]; then
- shasum=shasum
- else
- shasum=sha256sum
- fi
- echo
- echo "$custom_components_hash_mac MacOS.tar.xz" | $shasum -c -
- echo
-
- tar xvf MacOS.tar.xz
- fi
- echo
- fi
-
- pushd Firefox.app/Contents/Resources
+ pushd firefox
modify_omni mac
popd
- # Replace "FirefoxCP" with "ZoteroCP" for subprocesses ("Isolated Web Content", "Socket Process", "Web Content", etc.)
- info_plist=Firefox.app/Contents/MacOS/plugin-container.app/Contents/Resources/English.lproj/InfoPlist.strings
- from=$(get_utf16_chars "FirefoxCP")
- to=$(get_utf16_chars "ZoteroCP")
- perl -pi -e "s/$from/$to/" $info_plist
- # Check for UTF-16 "ZoteroCP"
- if ! grep -a -q "Z.o.t.e.r.o.C.P." $info_plist; then
- echo '"ZoteroCP" not found in InfoPlist.strings after replacement'
- exit 1
- fi
-
- if [ ! -e "Firefox $GECKO_VERSION.app.zip" ]; then
- rm "Firefox.dmg"
- fi
-
- #if [ ! -e "Firefox $GECKO_VERSION MacOS.zip" ]; then
- # rm "MacOS.zip"
- #fi
- echo $("$SCRIPT_DIR/xulrunner_hash" -p m) > hash-mac
fi
if [ $BUILD_WIN == 1 ]; then
@@ -563,36 +501,9 @@ fi
if [ $BUILD_LINUX == 1 ]; then
GECKO_VERSION="$GECKO_VERSION_LINUX"
- DOWNLOAD_URL="https://ftp.mozilla.org/pub/firefox/releases/$GECKO_VERSION"
-
-
- # Include 32-bit build if not in CI
- if [[ "${CI:-}" = "1" ]] || [[ "${SKIP_32:-}" = "1" ]]; then
- arches="x86_64"
- else
- arches="i686 x86_64"
- fi
- for arch in $arches; do
- xdir="firefox-$arch"
- rm -rf $xdir
-
- archived_file="firefox-$GECKO_VERSION-$arch.tar.bz2"
- if [ -e "$archived_file" ]; then
- echo "Using $archived_file"
- cp "$archived_file" "firefox-$GECKO_VERSION.tar.bz2"
- else
- curl -O "$DOWNLOAD_URL/linux-$arch/en-US/firefox-$GECKO_VERSION.tar.bz2"
- fi
-
- tar xvf firefox-$GECKO_VERSION.tar.bz2
- mv firefox firefox-$arch
-
- pushd firefox-$arch
- modify_omni $arch
+ pushd firefox
+ modify_omni linux
popd
- echo $($SCRIPT_DIR/xulrunner_hash -p l) > hash-linux
- rm "firefox-$GECKO_VERSION.tar.bz2"
- done
fi
echo Done
-33
View File
@@ -1,33 +0,0 @@
{
pname,
version,
meta,
stdenv,
fetchurl,
undmg,
}:
stdenv.mkDerivation (finalAttrs: {
inherit pname version meta;
src = fetchurl {
url = "https://download.zotero.org/client/release/${finalAttrs.version}/Zotero-${finalAttrs.version}.dmg";
hash = "sha256-lDf/jULLQyzxNVGRUKuF2df+FTbJK08z+fFQbVgwjsY=";
};
sourceRoot = ".";
nativeBuildInputs = [ undmg ];
dontConfigure = true;
dontBuild = true;
dontFixup = true; # breaks notarization
installPhase = ''
runHook preInstall
mkdir -p $out/Applications
cp -r Zotero.app $out/Applications
runHook postInstall
'';
})
+17
View File
@@ -0,0 +1,17 @@
diff --git a/js-build/build.js b/js-build/build.js
index 5e920db6d8..befe280606 100644
--- a/js-build/build.js
+++ b/js-build/build.js
@@ -36,9 +36,9 @@ if (require.main === module) {
...scssFiles.map(scf => getSass(scf, { ignore: ignoreMask }, signatures)),
getSymlinks(symlinks, { nodir: true, ignore: ignoreMask }, signatures),
getSymlinks(symlinkDirs, { ignore: ignoreMask }, signatures),
- getPDFReader(signatures),
- getPDFWorker(signatures),
- getZoteroNoteEditor(signatures)
+ //getPDFReader(signatures),
+ //getPDFWorker(signatures),
+ //getZoteroNoteEditor(signatures)
]);
await writeSignatures(signatures);
-139
View File
@@ -1,139 +0,0 @@
{
pname,
version,
meta,
lib,
stdenv,
fetchurl,
wrapGAppsHook3,
makeDesktopItem,
atk,
cairo,
dbus-glib,
gdk-pixbuf,
glib,
gtk3,
libGL,
libva,
libxtst,
libxrandr,
libxi,
libxfixes,
libxext,
libxdamage,
libxcursor,
libxcomposite,
libx11,
libxcb,
libgbm,
pango,
pciutils,
alsaSupport ? true,
alsa-lib,
jackSupport ? true,
libjack2,
pulseSupport ? true,
libpulseaudio,
sndioSupport ? true,
sndio,
}:
stdenv.mkDerivation (finalAttrs: {
inherit pname version meta;
src = fetchurl {
url = "https://download.zotero.org/client/release/${finalAttrs.version}/Zotero-${finalAttrs.version}_linux-x86_64.tar.bz2";
hash = "sha256-uV0R0L8EoZt59hMKXFlJ+EhONArPpRbb/tIV+wZKLgY=";
};
dontPatchELF = true;
nativeBuildInputs = [ wrapGAppsHook3 ];
libPath =
lib.makeLibraryPath (
[
atk
cairo
dbus-glib
gdk-pixbuf
glib
gtk3
libGL
libva
libx11
libxcomposite
libxcursor
libxdamage
libxext
libxfixes
libxi
libxrandr
libxtst
libxcb
libgbm
pango
pciutils
]
++ lib.optional alsaSupport alsa-lib
++ lib.optional jackSupport libjack2
++ lib.optional pulseSupport libpulseaudio
++ lib.optional sndioSupport sndio
)
+ ":"
+ lib.makeSearchPathOutput "lib" "lib" [ stdenv.cc.cc ];
desktopItem = makeDesktopItem {
name = "zotero";
exec = "zotero -url %U";
icon = "zotero";
comment = finalAttrs.meta.description;
desktopName = "Zotero";
genericName = "Reference Management";
categories = [
"Office"
"Database"
];
startupNotify = true;
mimeTypes = [
"x-scheme-handler/zotero"
"text/plain"
];
};
installPhase = ''
runHook preInstall
# Copy package contents to the output directory
mkdir -p "$prefix/usr/lib/zotero-bin-${finalAttrs.version}"
cp -r * "$prefix/usr/lib/zotero-bin-${finalAttrs.version}"
mkdir -p "$out/bin"
ln -s "$prefix/usr/lib/zotero-bin-${finalAttrs.version}/zotero" "$out/bin/"
# Install desktop file and icons
mkdir -p $out/share/applications
cp ${finalAttrs.desktopItem}/share/applications/* $out/share/applications/
for size in 32 64 128; do
install -Dm444 icons/icon''${size}.png \
$out/share/icons/hicolor/''${size}x''${size}/apps/zotero.png
done
install -Dm444 icons/symbolic.svg \
$out/share/icons/hicolor/symbolic/apps/zotero-symbolic.svg
runHook postInstall
'';
postFixup = ''
for executable in \
zotero-bin plugin-container updater vaapitest \
minidump-analyzer glxtest
do
if [ -e "$out/usr/lib/zotero-bin-${finalAttrs.version}/$executable" ]; then
patchelf --interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
"$out/usr/lib/zotero-bin-${finalAttrs.version}/$executable"
fi
done
find . -executable -type f -exec \
patchelf --set-rpath "$libPath" \
"$out/usr/lib/zotero-bin-${finalAttrs.version}/{}" \;
'';
})
+344 -13
View File
@@ -1,30 +1,361 @@
{
lib,
stdenv,
callPackage,
}:
fetchurl,
fetchFromGitHub,
buildNpmPackage,
which,
git,
nodejs_20,
nodejs_24,
perl,
python3,
curl,
wget,
zip,
unzip,
xz,
gawk,
rsync,
buildMozillaMach,
python311,
rustPlatform,
cmake,
python3Packages,
wrapGAppsHook3,
makeDesktopItem,
atk,
cairo,
dbus-glib,
gdk-pixbuf,
glib,
gtk3,
libGL,
libva,
xorg,
libgbm,
pango,
pciutils,
alsaSupport ? true,
alsa-lib,
jackSupport ? true,
libjack2,
pulseSupport ? true,
libpulseaudio,
sndioSupport ? true,
sndio,
}:
let
nodejs = nodejs_20;
pname = "zotero";
version = "7.0.30";
src = fetchFromGitHub {
owner = "zotero";
repo = "zotero";
tag = version;
hash = "sha256-/DDtKtRM5ddNekItHI6wAY1YoJmqSk77Lfubo/I6KxU=";
fetchSubmodules = true;
};
pdf-js = buildNpmPackage {
pname = "zotero-pdf-js";
inherit version;
nodejs = nodejs_24;
src = "${src}/pdf-worker/pdf.js";
npmDepsHash = "sha256-/me+tZdxChpPw0bsvD1fWqBgZezsN8EhL/pC7wTDuFE=";
prePatch = ''
# Drop unmaintained @jazzer fuzzer, it leads to `prebuild: command not found` and is not needed for builds.
# TODO: use https://gitlab.alpinelinux.org/alpine/aports/-/raw/master/community/zotero/zotero_drop-jazzer.patch?inline=false instead
substituteInPlace package.json \
--replace-fail '"@jazzer.js/core": "^2.1.0",' ""
'';
buildPhase = ''
npm exec gulp lib-legacy
npm exec gulp generic-legacy
npm exec gulp minified-legacy
'';
installPhase = ''
mkdir -p $out
cp -r . $out
'';
};
epub-js = buildNpmPackage {
pname = "zotero-epub-js";
inherit version nodejs;
src = "${src}/reader/epubjs/epub.js";
npmDepsHash = "sha256-JYOEDX6SxB4Epwq5PZ5Y+EJO6UGKsOBIm2XIAqOwDO8=";
npmBuildScript = "prepare";
installPhase = ''
mkdir -p $out
cp -r . $out
'';
};
pdf-reader = buildNpmPackage {
pname = "zotero-pdf-reader";
inherit version;
nodejs = nodejs_24;
src = "${src}/reader";
npmDepsHash = "sha256-kD3xA3N0gETKnB1nNl0c7Zkh+3zQEcQtsY7cZBdh8KQ=";
postPatch = ''
rm -rf pdfjs/pdf.js
cp -r ${pdf-js} pdfjs/pdf.js
rm -rf epubjs/epub.js
cp -r ${epub-js} epubjs/epub.js
chmod -R u+w epubjs/epub.js
substituteInPlace epubjs/epub.js/package.json \
--replace-fail '"prepare":' '"prepare_old":'
'';
installPhase = ''
mkdir -p $out
cp -r . $out
'';
};
pdf-worker = buildNpmPackage {
pname = "zotero-pdf-worker";
inherit version nodejs;
src = "${src}/pdf-worker";
npmDepsHash = "sha256-TGuN1fZOClzm6xD2rmn5BAemN4mbyOVaLbSRyMeDIm8=";
nativeBuildInputs = [
rsync
];
postPatch = ''
rm -rf pdf.js
cp -r ${pdf-js} pdf.js
'';
installPhase = ''
mkdir -p $out
cp -r . $out
'';
};
note-editor = buildNpmPackage {
pname = "zotero-note-editor";
inherit version nodejs;
src = "${src}/note-editor";
npmDepsHash = "sha256-9DJNlbyRgiipjrpiXGVFOl5zALJOwLCyw8TRkfwm5Ns=";
makeCacheWritable = true;
installPhase = ''
mkdir -p $out
cp -r . $out
'';
};
rust-cbindgen-026 = rustPlatform.buildRustPackage rec {
pname = "rust-cbindgen";
version = "0.26.0";
src = fetchFromGitHub {
owner = "mozilla";
repo = "cbindgen";
rev = "v${version}";
hash = "sha256-gyNZAuxpeOjuC+Rh9jAyHSBQRRYUlYoIrBKuCFg3Hao=";
};
cargoHash = "sha256-Mn6TigV/+zqG5CsjHMDYAN54P6qw4G03g7JuUM7GbPw=";
#buildInputs = lib.optional stdenv.isDarwin Security;
nativeCheckInputs = [
cmake
python3Packages.cython
];
checkFlags = [
# Disable tests that require rust unstable features
# https://github.com/eqrion/cbindgen/issues/338
"--skip test_expand"
"--skip test_bitfield"
"--skip lib_default_uses_debug_build"
"--skip lib_explicit_debug_build"
"--skip lib_explicit_release_build"
"--skip bin_explicit_release_build"
"--skip bin_default_uses_debug_build"
"--skip bin_explicit_debug_build"
]
++ lib.optionals stdenv.isDarwin [
# WORKAROUND: test_body fails when using clang
# https://github.com/eqrion/cbindgen/issues/628
"--skip test_body"
];
meta = {
license = lib.licenses.mpl20;
};
};
firefox-115 =
(buildMozillaMach rec {
pname = "firefox-esr-115";
version = "115.31.0esr";
applicationName = "Mozilla Firefox ESR";
src = fetchurl {
url = "mirror://mozilla/firefox/releases/${version}/source/firefox-${version}.source.tar.xz";
sha512 = "5a56764be6f3d1a4c9f2ee289ec2f220670ad3b99e9ab83a63e24f5fcd023611af7c9bdb81f9baef0d5fe003576d56cee01cf563f6686905363d4c925e4022e2";
};
meta = {
platforms = lib.platforms.unix;
badPlatforms = lib.platforms.darwin;
broken = stdenv.buildPlatform.is32bit;
# since Firefox 60, build on 32-bit platforms fails with "out of memory".
# not in `badPlatforms` because cross-compilation on 64-bit machine might work.
license = lib.licenses.mpl20;
};
}).override
{
python3 = python311;
elfhackSupport = false;
rust-cbindgen = rust-cbindgen-026;
};
in
buildNpmPackage rec {
inherit
pname
version
src
nodejs
;
npmDepsHash = "sha256-qWeUeiwM6sCNovSoaEP3b42VTnCFSWLK9y8qPnWcSTE=";
nativeBuildInputs = [
#which
git
nodejs
perl
python3
curl
wget
zip
unzip
xz
gawk
rsync
];
patches = [
./git-revs.patch
./avoid-xulrunner-fetch.patch
];
postPatch = ''
substituteInPlace app/scripts/dir_build \
--replace-quiet 'hash=`git -C "$ROOT_DIR" rev-parse --short HEAD`' 'hash="e9281c51fd464246b60eee4b3ba999eb4f67d36f"'
rm -rf reader
cp -r ${pdf-reader} reader
rm -rf pdf-worker
cp -r ${pdf-worker} pdf-worker
rm -rf note-editor
cp -r ${note-editor} note-editor
patchShebangs --build app/
'';
#preBuild = "app/scripts/check_requirements";
buildPhase = ''
runHook preBuild
npm run build
# Place firefox files at the right place
mkdir -p app/xulrunner
cp -r ${firefox-115}/lib/firefox/ app/xulrunner/
chmod -R u+w app/xulrunner/
app/scripts/dir_build
runHook postBuild
'';
desktopItem = makeDesktopItem {
name = "zotero";
exec = "zotero -url %U";
icon = "zotero";
comment = meta.description;
desktopName = "Zotero";
genericName = "Reference Management";
categories = [
"Office"
"Database"
];
startupNotify = true;
mimeTypes = [
"x-scheme-handler/zotero"
"text/plain"
];
};
installPhase = ''
runHook preInstall
mkdir -p $out/lib/
cp -r app/staging/*/. $out/lib/
runHook postInstall
'';
/*
installPhase = ''
runHook preInstall
# Copy package contents to the output directory
mkdir -p "$prefix/usr/lib/zotero-bin-${version}"
cp -r * "$prefix/usr/lib/zotero-bin-${version}"
mkdir -p "$out/bin"
ln -s "$prefix/usr/lib/zotero-bin-${version}/zotero" "$out/bin/"
# Install desktop file and icons
mkdir -p $out/share/applications
cp ${desktopItem}/share/applications/* $out/share/applications/
for size in 32 64 128; do
install -Dm444 icons/icon''${size}.png \
$out/share/icons/hicolor/''${size}x''${size}/apps/zotero.png
done
install -Dm444 icons/symbolic.svg \
$out/share/icons/hicolor/symbolic/apps/zotero-symbolic.svg
runHook postInstall
'';
postFixup = ''
for executable in \
zotero-bin plugin-container updater vaapitest \
minidump-analyzer glxtest
do
if [ -e "$out/usr/lib/zotero-bin-${version}/$executable" ]; then
patchelf --interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
"$out/usr/lib/zotero-bin-${version}/$executable"
fi
done
find . -executable -type f -exec \
patchelf --set-rpath "$libPath" \
"$out/usr/lib/zotero-bin-${version}/{}" \;
'';
*/
meta = {
homepage = "https://www.zotero.org";
description = "Collect, organize, cite, and share your research sources";
mainProgram = "zotero";
sourceProvenance = [ lib.sourceTypes.binaryNativeCode ];
license = lib.licenses.agpl3Only;
platforms = [
"x86_64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
platforms = lib.platforms.all;
maintainers = with lib.maintainers; [
atila
justanotherariel
];
};
in
if stdenv.hostPlatform.isDarwin then
callPackage ./darwin.nix { inherit pname version meta; }
else
callPackage ./linux.nix { inherit pname version meta; }
}
@@ -0,0 +1,52 @@
{ lib
, stdenv
, fetchFromGitHub
, rustPlatform
, cmake
, python3Packages
, Security
}:
rustPlatform.buildRustPackage rec {
pname = "rust-cbindgen";
version = "0.26.0";
src = fetchFromGitHub {
owner = "mozilla";
repo = "cbindgen";
rev = "v${version}";
hash = "sha256-gyNZAuxpeOjuC+Rh9jAyHSBQRRYUlYoIrBKuCFg3Hao=";
};
cargoHash = "sha256-pdTxhECAZzBx5C01Yx7y/OGwhhAdlEDpqLBdvQcb8bc=";
buildInputs = lib.optional stdenv.isDarwin Security;
nativeCheckInputs = [
cmake
python3Packages.cython
];
checkFlags = [
# Disable tests that require rust unstable features
# https://github.com/eqrion/cbindgen/issues/338
"--skip test_expand"
"--skip test_bitfield"
"--skip lib_default_uses_debug_build"
"--skip lib_explicit_debug_build"
"--skip lib_explicit_release_build"
] ++ lib.optionals stdenv.isDarwin [
# WORKAROUND: test_body fails when using clang
# https://github.com/eqrion/cbindgen/issues/628
"--skip test_body"
];
meta = with lib; {
changelog = "https://github.com/mozilla/cbindgen/blob/v${version}/CHANGES";
description = "Project for generating C bindings from Rust code";
mainProgram = "cbindgen";
homepage = "https://github.com/mozilla/cbindgen";
license = licenses.mpl20;
maintainers = with maintainers; [ hexa ];
};
}