diff --git a/home.nix b/home.nix index 8639d92..af971fb 100644 --- a/home.nix +++ b/home.nix @@ -19,10 +19,9 @@ in home.homeDirectory = lib.mkDefault home; home.packages = with pkgs; [ - element-desktop + mpkgs.element spotify kitty - vesktop flameshot krita davinci-resolve diff --git a/pkgs/default.nix b/pkgs/default.nix index 5d2608f..717457f 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -41,6 +41,8 @@ in font.monaco = use ./monaco-font/default.nix; + element = use ./element/default.nix; + home-manager = { module = let @@ -50,6 +52,9 @@ in }; in import "${home-manager}/nixos"; - sharedModules = [ ./home-manager/initialFile.nix ./tetrio/module.nix ]; + sharedModules = [ + ./home-manager/initialFile.nix + ./tetrio/module.nix + ]; }; } diff --git a/pkgs/element/default.nix b/pkgs/element/default.nix new file mode 100644 index 0000000..9ca5bbc --- /dev/null +++ b/pkgs/element/default.nix @@ -0,0 +1,180 @@ +{ + lib, + stdenv, + fetchFromGitHub, + makeWrapper, + makeDesktopItem, + nodejs, + electron_39, + element-web, + sqlcipher, + callPackage, + typescript, + # command line arguments which are always set + commandLineArgs ? "", + yarnConfigHook, + yarnBuildHook, + fetchYarnDeps, + asar, + copyDesktopItems, + darwin, + ... +}: + +let + pinData = import ./element-desktop-pin.nix; + inherit (pinData.hashes) desktopSrcHash desktopYarnHash; + executableName = "element-desktop"; + electron = electron_39; + seshat = callPackage ./seshat { }; +in +stdenv.mkDerivation ( + finalAttrs: + removeAttrs pinData [ "hashes" ] + // { + pname = "element-desktop"; + name = "${finalAttrs.pname}-${finalAttrs.version}"; + src = fetchFromGitHub { + owner = "element-hq"; + repo = "element-desktop"; + rev = "v${finalAttrs.version}"; + hash = desktopSrcHash; + }; + + offlineCache = fetchYarnDeps { + yarnLock = finalAttrs.src + "/yarn.lock"; + hash = desktopYarnHash; + }; + + env.ELECTRON_SKIP_BINARY_DOWNLOAD = "1"; + + nativeBuildInputs = [ + asar + copyDesktopItems + nodejs + makeWrapper + typescript + yarnConfigHook + yarnBuildHook + ] + ++ lib.optionals stdenv.hostPlatform.isDarwin [ darwin.autoSignDarwinBinariesHook ]; + + inherit seshat; + + # Only affects unused scripts in $out/share/element/electron/scripts. Also + # breaks because there are some `node`-scripts with a `npx`-shebang and + # this shouldn't be in the closure just for unused scripts. + dontPatchShebangs = true; + + postPatch = '' + cp -r ${electron.dist} electron-dist + chmod -R u+w electron-dist + + substituteInPlace package.json \ + --replace-fail \ + ' electron-builder",' \ + ' electron-builder --dir -c.electronDist=electron-dist -c.electronVersion=${electron.version} -c.mac.identity=null",' + + # `@electron/fuses` tries to run `codesign` and fails. Disable and use autoSignDarwinBinariesHook instead + substituteInPlace ./electron-builder.ts \ + --replace-fail "resetAdHocDarwinSignature:" "// resetAdHocDarwinSignature:" + + # Need to disable asar integrity check to copy in native seshat files, see postBuild phase + substituteInPlace ./electron-builder.ts \ + --replace-fail "enableEmbeddedAsarIntegrityValidation: true" "enableEmbeddedAsarIntegrityValidation: false" + ''; + + preBuild = '' + # Apply upstream patch + # Can be removed if upstream removes patches/@types+auto-launch+5.0.5.patch introduced in + # https://github.com/element-hq/element-desktop/commit/5e882f8e08d58bf9663c8e3ab33885bf7b3709de + node ./node_modules/patch-package/index.js + ''; + + postBuild = '' + # relative path to app.asar differs on Linux and MacOS + packed=$(find ./dist -name app.asar) + asar extract "$packed" tmp-app + + # linking here leads to Error: tmp-app/node_modules/matrix-seshat: file ... links out of the package + cp -r $seshat tmp-app/node_modules/matrix-seshat + + asar pack tmp-app "$packed" + ''; + + installPhase = '' + runHook preInstall + '' + + lib.optionalString stdenv.hostPlatform.isDarwin '' + mkdir -p "$out/Applications" "$out/bin" + mv dist/mac*/Element.app "$out/Applications" + + ln -s '${element-web}' "$out/Applications/Element.app/Contents/Resources/webapp" + + wrapProgram "$out/Applications/Element.app/Contents/MacOS/Element" \ + --add-flags ${lib.escapeShellArg commandLineArgs} + + makeWrapper "$out/Applications/Element.app/Contents/MacOS/Element" "$out/bin/${executableName}" + '' + + lib.optionalString (!stdenv.hostPlatform.isDarwin) '' + mkdir -p "$out/bin" "$out/share" + + cp -a dist/*-unpacked/resources $out/share/element + + ln -s '${element-web}' "$out/share/element/webapp" + + # icon, used in makeDesktopItem + mkdir -p "$out/share/icons/hicolor/512x512/apps" + ln -s "$out/share/element/build/icon.png" "$out/share/icons/hicolor/512x512/apps/element.png" + + # executable wrapper + # LD_PRELOAD workaround for sqlcipher not found: https://github.com/matrix-org/seshat/issues/102 + makeWrapper '${lib.getExe electron}' "$out/bin/${executableName}" \ + --set LD_PRELOAD ${sqlcipher}/lib/libsqlcipher.so \ + --add-flags "$out/share/element/app.asar" \ + --add-flags "\''${NIXOS_OZONE_WL:+\''${WAYLAND_DISPLAY:+--ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime=true}}" \ + --add-flags ${lib.escapeShellArg commandLineArgs} + '' + + '' + runHook postInstall + ''; + + # The desktop item properties should be kept in sync with data from upstream: + # https://github.com/element-hq/element-desktop/blob/develop/package.json + desktopItems = [ + (makeDesktopItem { + name = "element-desktop"; + exec = "${executableName} %u"; + icon = "element"; + desktopName = "Element"; + genericName = "Matrix Client"; + comment = finalAttrs.meta.description; + categories = [ + "Network" + "InstantMessaging" + "Chat" + ]; + startupWMClass = "Element"; + mimeTypes = [ + "x-scheme-handler/element" + "x-scheme-handler/io.element.desktop" + ]; + }) + ]; + + passthru = { + # run with: nix-shell ./maintainers/scripts/update.nix --argstr package element-desktop + updateScript = ./update.sh; + }; + + meta = { + description = "Feature-rich client for Matrix.org"; + homepage = "https://element.io/"; + changelog = "https://github.com/element-hq/element-desktop/blob/v${finalAttrs.version}/CHANGELOG.md"; + license = lib.licenses.agpl3Plus; + teams = [ lib.teams.matrix ]; + inherit (electron.meta) platforms; + mainProgram = "element-desktop"; + }; + } +) diff --git a/pkgs/element/element-desktop-pin.nix b/pkgs/element/element-desktop-pin.nix new file mode 100644 index 0000000..9c28e4b --- /dev/null +++ b/pkgs/element/element-desktop-pin.nix @@ -0,0 +1,7 @@ +{ + "version" = "1.12.10"; + "hashes" = { + "desktopSrcHash" = "sha256-2LQBT3+2JTR3XHO3DynOp8cw2m2SB/mGH01e3SFD/IM="; + "desktopYarnHash" = "sha256-QIzuVKmUS4tqXAzhpfLZOp51kLbfC1M2nrff8e+sdg4="; + }; +} diff --git a/pkgs/element/seshat/default.nix b/pkgs/element/seshat/default.nix new file mode 100644 index 0000000..5e3bb3f --- /dev/null +++ b/pkgs/element/seshat/default.nix @@ -0,0 +1,74 @@ +{ + lib, + stdenv, + rustPlatform, + fetchFromGitHub, + sqlcipher, + nodejs, + python3, + yarn, + fixup-yarn-lock, + fetchYarnDeps, + removeReferencesTo, +}: + +let + pinData = lib.importJSON ./pin.json; + +in +rustPlatform.buildRustPackage rec { + pname = "seshat-node"; + inherit (pinData) version cargoHash; + + src = fetchFromGitHub { + owner = "matrix-org"; + repo = "seshat"; + rev = version; + hash = pinData.srcHash; + }; + + sourceRoot = "${src.name}/seshat-node/native"; + + nativeBuildInputs = [ + nodejs + python3 + yarn + fixup-yarn-lock + ]; + buildInputs = [ sqlcipher ]; + + npm_config_nodedir = nodejs; + + yarnOfflineCache = fetchYarnDeps { + yarnLock = src + "/seshat-node/yarn.lock"; + sha256 = pinData.yarnHash; + }; + + buildPhase = '' + runHook preBuild + cd .. + chmod u+w . ./yarn.lock + export HOME=$PWD/tmp + mkdir -p $HOME + yarn config --offline set yarn-offline-mirror $yarnOfflineCache + fixup-yarn-lock yarn.lock + yarn install --offline --frozen-lockfile --ignore-platform --ignore-scripts --no-progress --non-interactive + patchShebangs node_modules/ + node_modules/.bin/neon build --release -- --target ${stdenv.hostPlatform.rust.rustcTarget} -Z unstable-options --out-dir target/release + runHook postBuild + ''; + + doCheck = false; + + installPhase = '' + runHook preInstall + shopt -s extglob + rm -rf native/!(index.node) + rm -rf node_modules $HOME + cp -r . $out + ${removeReferencesTo}/bin/remove-references-to -t ${stdenv.cc.cc} $out/native/index.node + runHook postInstall + ''; + + disallowedReferences = [ stdenv.cc.cc ]; +} diff --git a/pkgs/element/seshat/pin.json b/pkgs/element/seshat/pin.json new file mode 100644 index 0000000..aacdffa --- /dev/null +++ b/pkgs/element/seshat/pin.json @@ -0,0 +1,6 @@ +{ + "version": "2.3.3", + "srcHash": "sha256-HmKHWFoO8TQ9S/RcJnJ3h85/2uSkqGrgLnX82hkux4Q=", + "yarnHash": "1cbkv8ap7f8vxl5brzqb86d2dyxg555sz67cldrp0vgnk8sq6ibp", + "cargoHash": "sha256-klrFk0gpqQu/9MzLEYMNqEBETZMXtZJX67Sm5ZqyHfE==" +} diff --git a/pkgs/element/seshat/update.sh b/pkgs/element/seshat/update.sh new file mode 100644 index 0000000..6e7e75e --- /dev/null +++ b/pkgs/element/seshat/update.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env nix-shell +#!nix-shell -I nixpkgs=../../../../../../ -i bash -p wget prefetch-yarn-deps yarn nix-prefetch nix-prefetch-github + +if [ "$#" -gt 1 ] || [[ "$1" == -* ]]; then + echo "Regenerates packaging data for the seshat package." + echo "Usage: $0 [git release tag]" + exit 1 +fi + +version="$1" + +set -euo pipefail + +if [ -z "$version" ]; then + version="$(wget -O- "https://api.github.com/repos/matrix-org/seshat/tags" | jq -r '.[] | .name' | sort --version-sort | tail -1)" +fi + +SRC="https://raw.githubusercontent.com/matrix-org/seshat/$version" + +tmpdir=$(mktemp -d) +trap 'rm -rf "$tmpdir"' EXIT + +pushd $tmpdir +wget "$SRC/seshat-node/yarn.lock" +yarn_hash=$(prefetch-yarn-deps yarn.lock) +popd + +src_hash=$(nix-prefetch-github matrix-org seshat --rev ${version} | jq -r .hash) + +cat > pin.json << EOF +{ + "version": "$version", + "srcHash": "$src_hash", + "yarnHash": "$yarn_hash", + "cargoHash": "0000000000000000000000000000000000000000000000000000" +} +EOF + +cargo_hash=$(nix-prefetch "{ sha256 }: (import ../../../../../.. {}).element-desktop.seshat.cargoDeps") + +cat > pin.json << EOF +{ + "version": "$version", + "srcHash": "$src_hash", + "yarnHash": "$yarn_hash", + "cargoHash": "$cargo_hash" +} +EOF +