From ab496bbf9619fce9a8dac7d86db0daad9c2898e5 Mon Sep 17 00:00:00 2001
From: Yureka <yuka@yuka.dev>
Date: Tue, 7 Sep 2021 18:44:33 +0200
Subject: [PATCH] add Nix flake

---
 flake.lock                  |  26 +++++++++
 flake.nix                   |  29 ++++++++++
 nix/overlay.nix             |  17 ++++++
 nix/schildichat-desktop.nix | 109 ++++++++++++++++++++++++++++++++++++
 nix/schildichat-web.nix     |  75 +++++++++++++++++++++++++
 5 files changed, 256 insertions(+)
 create mode 100644 flake.lock
 create mode 100644 flake.nix
 create mode 100644 nix/overlay.nix
 create mode 100644 nix/schildichat-desktop.nix
 create mode 100644 nix/schildichat-web.nix

diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..7e563d6
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,26 @@
+{
+  "nodes": {
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1630504215,
+        "narHash": "sha256-H5pzwo7z3e7ZatwuwWY25oZSejchO+ZH/XtMi8/PXLw=",
+        "owner": "yu-re-ka",
+        "repo": "nixpkgs",
+        "rev": "979e5916df0e6830a2b1ee999632de9a9d2beb23",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "nixpkgs": "nixpkgs"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..cc71b74
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,29 @@
+{
+  description = "The SchildiChat Matrix client";
+
+  inputs.nixpkgs.url = github:NixOS/nixpkgs;
+
+  outputs = { self, nixpkgs }: let
+    systems = [ "x86_64-linux" "i686-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
+    forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
+
+    overlay = import ./nix/overlay.nix;
+
+    # Memoize nixpkgs for different platforms for efficiency.
+    nixpkgsFor = forAllSystems (system:
+      import nixpkgs {
+        inherit system;
+        overlays = [ overlay ];
+      });
+  in {
+    inherit overlay;
+
+    packages = builtins.mapAttrs (system: pkgs: {
+      inherit (pkgs)
+        schildichat-web
+        schildichat-desktop
+        schildichat-desktop-wayland
+      ;
+    }) nixpkgsFor;
+  };
+}
diff --git a/nix/overlay.nix b/nix/overlay.nix
new file mode 100644
index 0000000..7261941
--- /dev/null
+++ b/nix/overlay.nix
@@ -0,0 +1,17 @@
+final: prev: {
+  cleanSchildichatDesktopSource = src: with final.lib; cleanSourceWith {
+    filter = name: type: cleanSourceFilter name type
+      && !(hasInfix "/node_modules/" name)
+      && !(hasInfix "/nix/" name && hasSuffix ".nix" name)
+    ;
+    inherit src;
+  };
+  schildichat-web = final.callPackage ./schildichat-web.nix {};
+  schildichat-desktop = final.callPackage ./schildichat-desktop.nix {
+    inherit (final.darwin.apple_sdk.frameworks) Security AppKit CoreServices;
+  };
+  schildichat-desktop-wayland = final.callPackage ./schildichat-desktop.nix {
+    inherit (final.darwin.apple_sdk.frameworks) Security AppKit CoreServices;
+    useWayland = true;
+  };
+}
diff --git a/nix/schildichat-desktop.nix b/nix/schildichat-desktop.nix
new file mode 100644
index 0000000..ab1daa4
--- /dev/null
+++ b/nix/schildichat-desktop.nix
@@ -0,0 +1,109 @@
+{ lib
+, stdenv
+, fetchFromGitHub
+, makeWrapper
+, makeDesktopItem
+, mkYarnPackage
+, electron
+, element-desktop # for native modules
+, schildichat-web
+, callPackage
+, Security
+, AppKit
+, CoreServices
+
+, useWayland ? false
+
+, cleanSchildichatDesktopSource
+, schildichat-desktop-src ? ../.
+}:
+
+let
+  packageJSON = schildichat-desktop-src + "/element-desktop/package.json";
+  yarnLock = schildichat-desktop-src + "/element-desktop/yarn.lock";
+
+  package = builtins.fromJSON (builtins.readFile packageJSON);
+
+  pname = "schildichat-desktop";
+  version = package.version;
+
+  executableName = pname;
+
+  electron_exec = if stdenv.isDarwin then "${electron}/Applications/Electron.app/Contents/MacOS/Electron" else "${electron}/bin/electron";
+
+in mkYarnPackage rec {
+  inherit pname version packageJSON;
+
+  src = cleanSchildichatDesktopSource (schildichat-desktop-src + "/element-desktop");
+
+  nativeBuildInputs = [ makeWrapper ];
+
+  inherit (element-desktop) seshat keytar;
+
+  buildPhase = ''
+    runHook preBuild
+
+    export HOME=$(mktemp -d)
+    pushd deps/schildichat-desktop/
+    npx tsc
+    yarn run i18n
+    node ./scripts/copy-res.js
+    popd
+    rm -rf node_modules/matrix-seshat node_modules/keytar
+    ln -s $keytar node_modules/keytar
+    ln -s $seshat node_modules/matrix-seshat
+
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+
+    # resources
+    mkdir -p "$out/share/element"
+    ln -s '${schildichat-web}' "$out/share/element/webapp"
+    cp -r './deps/schildichat-desktop' "$out/share/element/electron"
+    cp -r './deps/schildichat-desktop/res/img' "$out/share/element"
+    rm "$out/share/element/electron/node_modules"
+    cp -r './node_modules' "$out/share/element/electron"
+    cp $out/share/element/electron/lib/i18n/strings/en_EN.json $out/share/element/electron/lib/i18n/strings/en-us.json
+    ln -s $out/share/element/electron/lib/i18n/strings/en{-us,}.json
+
+    # icons
+    for icon in $out/share/element/electron/build/icons/*.png; do
+      mkdir -p "$out/share/icons/hicolor/$(basename $icon .png)/apps"
+      ln -s "$icon" "$out/share/icons/hicolor/$(basename $icon .png)/apps/element.png"
+    done
+
+    # desktop item
+    mkdir -p "$out/share"
+    ln -s "${desktopItem}/share/applications" "$out/share/applications"
+
+    # executable wrapper
+    makeWrapper '${electron_exec}' "$out/bin/${executableName}" \
+      --add-flags "$out/share/element/electron${lib.optionalString useWayland " --enable-features=UseOzonePlatform --ozone-platform=wayland"}"
+
+    runHook postInstall
+  '';
+
+  # Do not attempt generating a tarball for element-web again.
+  # note: `doDist = false;` does not work.
+  distPhase = ''
+    true
+  '';
+
+  # The desktop item properties should be kept in sync with data from upstream:
+  # https://github.com/vector-im/element-desktop/blob/develop/package.json
+  desktopItem = makeDesktopItem {
+    name = "schildichat-desktop";
+    exec = "${executableName} %u";
+    icon = "schildichat";
+    desktopName = "SchildiChat";
+    genericName = "Matrix Client";
+    categories = "Network;InstantMessaging;Chat;";
+    extraEntries = ''
+      StartupWMClass=schildichat
+      MimeType=x-scheme-handler/element;
+    '';
+  };
+}
diff --git a/nix/schildichat-web.nix b/nix/schildichat-web.nix
new file mode 100644
index 0000000..e10071c
--- /dev/null
+++ b/nix/schildichat-web.nix
@@ -0,0 +1,75 @@
+{ stdenv
+, mkYarnModules
+, nodejs
+, cleanSchildichatDesktopSource
+, schildichat-desktop-src ? ../.
+, ...
+}:
+
+let
+  packageJSON = schildichat-desktop-src + "/element-web/package.json";
+  yarnLock = schildichat-desktop-src + "/element-web/yarn.lock";
+
+  package = builtins.fromJSON (builtins.readFile packageJSON);
+
+  pname = "schildichat-web";
+  version = package.version;
+
+  modules = mkYarnModules {
+    name = "${pname}-modules-${version}";
+    inherit pname version packageJSON yarnLock;
+  };
+
+in stdenv.mkDerivation {
+  inherit pname version;
+
+  src = cleanSchildichatDesktopSource schildichat-desktop-src;
+
+  buildInputs = [ nodejs ];
+
+  postPatch = ''
+    patchShebangs .
+  '';
+
+  configurePhase = ''
+    runHook preConfigure
+
+    cp configs/sc/config.json element-web/
+    cp -r ${modules}/node_modules node_modules
+    chmod u+rwX -R node_modules
+    rm -rf node_modules/matrix-react-sdk
+    ln -s $PWD/matrix-react-sdk node_modules/
+    ln -s $PWD/node_modules matrix-react-sdk/
+    ln -s $PWD/node_modules element-web/
+
+    runHook postConfigure
+  '';
+
+  buildPhase = ''
+    runHook preBuild
+
+    pushd matrix-react-sdk
+    node_modules/.bin/reskindex -h ../element-web/src/header
+    popd
+
+    pushd element-web
+    node scripts/copy-res.js
+    node_modules/.bin/reskindex -h ../element-web/src/header
+    node_modules/.bin/webpack --progress --mode production
+    popd
+
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+
+    cp -r element-web/webapp $out
+
+    runHook postInstall
+  '';
+
+  passthru = {
+    inherit modules;
+  };
+}