From 91ebbda18ddf221d8818fe17a469bb6762b7d6f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A5=B6=E8=8C=B6=E8=AF=B4?= Date: Wed, 29 Apr 2026 12:09:26 +0800 Subject: [PATCH 1/3] Create Nix expression for Pebble email client Add default.nix for building the Pebble email client. --- default.nix | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 default.nix diff --git a/default.nix b/default.nix new file mode 100644 index 00000000..2c674e64 --- /dev/null +++ b/default.nix @@ -0,0 +1,148 @@ +{ lib +, stdenv +, fetchFromGitHub +, rustPlatform +, pnpm_10 +, fetchPnpmDeps +, nodejs_20 +, cargo +, rustc +, pkg-config +, wrapGAppsHook3 +, at-spi2-atk +, atkmm +, cairo +, gdk-pixbuf +, glib +, gtk3 +, harfbuzz +, librsvg +, libsoup_3 +, pango +, webkitgtk_4_1 +, openssl +, libayatana-appindicator +, dbus +}: + +# Pebble —— Tauri 2 + pnpm + Rust workspace 的桌面邮件客户端。 +# +# 上游的 `pnpm build` 会走 `tauri build`,而 Tauri bundler 在 Nix 沙盒里经常会 +# 因为联网/跨平台 bundle 资源失败;Pebble 自己还把 bundle target 设成了 `nsis`。 +# 这里统一拆成两步: +# 1. `pnpm run build:frontend` 只产出前端 dist/ +# 2. `cargo build -p pebble --release --frozen` 只编译 Tauri 二进制 +# +# Pebble 是 Cargo workspace,`Cargo.toml`/`Cargo.lock` 都在仓库根目录,不在 +# `src-tauri/` 下,所以 Rust vendoring 也必须按 workspace 根目录来配。 + +stdenv.mkDerivation (finalAttrs: { + pname = "pebble"; + version = "0.0.1"; + + src = fetchFromGitHub { + owner = "QingJ01"; + repo = "Pebble"; + rev = "v${finalAttrs.version}"; + hash = "sha256-p5eRtHJ89pTlQHxATd4WyXWT0b3a7eGS05agNo4YFbg="; + }; + + pnpmDeps = fetchPnpmDeps { + inherit (finalAttrs) pname version src; + fetcherVersion = 2; + hash = "sha256-jp+OGytRpHFUbfclDAW1V8dwLpaInw3KTAQMXvqcsEA="; + }; + + cargoDeps = rustPlatform.importCargoLock { + lockFile = "${finalAttrs.src}/Cargo.lock"; + }; + + nativeBuildInputs = [ + nodejs_20 + pnpm_10.configHook + rustPlatform.cargoSetupHook + cargo + rustc + pkg-config + wrapGAppsHook3 + ]; + + buildInputs = [ + at-spi2-atk + atkmm + cairo + gdk-pixbuf + glib + gtk3 + harfbuzz + librsvg + libsoup_3 + pango + webkitgtk_4_1 + openssl + libayatana-appindicator + dbus + ]; + + buildPhase = '' + runHook preBuild + + export HOME=$(mktemp -d) + + substituteInPlace src-tauri/tauri.conf.json \ + --replace-fail '"devUrl": "http://127.0.0.1:1420",' "" + + pnpm run build:frontend + + cargo build --package pebble --release --frozen + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + install -Dm755 target/release/pebble $out/bin/pebble + + # 图标 + for size in 32x32 128x128; do + install -Dm644 src-tauri/icons/''${size}.png \ + $out/share/icons/hicolor/''${size}/apps/pebble.png + done + install -Dm644 src-tauri/icons/128x128@2x.png \ + $out/share/icons/hicolor/256x256/apps/pebble.png + + + install -Dm644 /dev/stdin $out/share/applications/pebble.desktop < Date: Wed, 29 Apr 2026 15:14:39 +0800 Subject: [PATCH 2/3] add update script for nix package by passthru.updateScript --- default.nix | 2 + update.sh | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 update.sh diff --git a/default.nix b/default.nix index 2c674e64..97fbcd39 100644 --- a/default.nix +++ b/default.nix @@ -138,6 +138,8 @@ stdenv.mkDerivation (finalAttrs: { ) ''; + passthru.updateScript = ./update.sh; + meta = with lib; { description = "A local-first desktop email client for people who want a calmer, more private inbox."; homepage = "https://github.com/QingJ01/Pebble"; diff --git a/update.sh b/update.sh new file mode 100644 index 00000000..27594da3 --- /dev/null +++ b/update.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i bash -p bash curl jq gnused coreutils nix + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +PACKAGE_NIX="$SCRIPT_DIR/default.nix" + +OWNER="QingJ01" +REPO="Pebble" +PNAME="pebble" + +nix_cmd=( + nix + --extra-experimental-features + "nix-command flakes" +) + +extract_hash() { + local expr="$1" + local output + local hash + + if output="$("${nix_cmd[@]}" build --impure --no-link --expr "$expr" 2>&1)"; then + echo "expected a fixed-output hash mismatch, but the build unexpectedly succeeded" >&2 + return 1 + fi + + hash="$(printf '%s\n' "$output" | sed -n 's/.*got:[[:space:]]*\(sha256-[A-Za-z0-9+/=]\+\).*/\1/p' | tail -n1)" + if [[ -z "$hash" ]]; then + printf '%s\n' "$output" >&2 + echo "failed to parse hash from nix output" >&2 + return 1 + fi + + printf '%s\n' "$hash" +} + +if [[ $# -gt 1 ]]; then + echo "usage: $0 [version-or-tag]" >&2 + exit 1 +fi + +if [[ $# -eq 1 ]]; then + requested="$1" + if [[ "$requested" == v* ]]; then + new_tag="$requested" + else + new_tag="v$requested" + fi +else + new_tag="$( + curl --fail --silent --show-error \ + "https://api.github.com/repos/$OWNER/$REPO/releases/latest" | + jq --raw-output '.tag_name' + )" +fi + +if [[ -z "$new_tag" || "$new_tag" == "null" ]]; then + echo "failed to determine the latest GitHub release tag" >&2 + exit 1 +fi + +if [[ "$new_tag" != v* ]]; then + echo "unexpected release tag format: $new_tag (expected v)" >&2 + exit 1 +fi + +new_version="${new_tag#v}" +current_version="$(sed -n 's/^[[:space:]]*version = "\([^"]*\)";/\1/p' "$PACKAGE_NIX" | head -n1)" + +if [[ "$current_version" == "$new_version" ]]; then + echo "$PNAME is already at $new_version" + exit 0 +fi + +src_expr=$(cat < $new_version" +echo " src.hash = $src_hash" +echo " pnpmDeps.hash = $pnpm_hash" From 52d6d9e9f27c33441a7cda38be1b5af21f610bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A5=B6=E8=8C=B6=E8=AF=B4?= Date: Wed, 29 Apr 2026 21:22:28 +0800 Subject: [PATCH 3/3] remove update.sh and revert nix hash. --- default.nix | 6 +-- update.sh | 125 ---------------------------------------------------- 2 files changed, 3 insertions(+), 128 deletions(-) delete mode 100644 update.sh diff --git a/default.nix b/default.nix index 97fbcd39..6609b0aa 100644 --- a/default.nix +++ b/default.nix @@ -38,19 +38,19 @@ stdenv.mkDerivation (finalAttrs: { pname = "pebble"; - version = "0.0.1"; + version = "0.0.2"; src = fetchFromGitHub { owner = "QingJ01"; repo = "Pebble"; rev = "v${finalAttrs.version}"; - hash = "sha256-p5eRtHJ89pTlQHxATd4WyXWT0b3a7eGS05agNo4YFbg="; + hash = lib.fakeHash; }; pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) pname version src; fetcherVersion = 2; - hash = "sha256-jp+OGytRpHFUbfclDAW1V8dwLpaInw3KTAQMXvqcsEA="; + hash = lib.fakeHash; }; cargoDeps = rustPlatform.importCargoLock { diff --git a/update.sh b/update.sh deleted file mode 100644 index 27594da3..00000000 --- a/update.sh +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env nix-shell -#!nix-shell -i bash -p bash curl jq gnused coreutils nix - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" -PACKAGE_NIX="$SCRIPT_DIR/default.nix" - -OWNER="QingJ01" -REPO="Pebble" -PNAME="pebble" - -nix_cmd=( - nix - --extra-experimental-features - "nix-command flakes" -) - -extract_hash() { - local expr="$1" - local output - local hash - - if output="$("${nix_cmd[@]}" build --impure --no-link --expr "$expr" 2>&1)"; then - echo "expected a fixed-output hash mismatch, but the build unexpectedly succeeded" >&2 - return 1 - fi - - hash="$(printf '%s\n' "$output" | sed -n 's/.*got:[[:space:]]*\(sha256-[A-Za-z0-9+/=]\+\).*/\1/p' | tail -n1)" - if [[ -z "$hash" ]]; then - printf '%s\n' "$output" >&2 - echo "failed to parse hash from nix output" >&2 - return 1 - fi - - printf '%s\n' "$hash" -} - -if [[ $# -gt 1 ]]; then - echo "usage: $0 [version-or-tag]" >&2 - exit 1 -fi - -if [[ $# -eq 1 ]]; then - requested="$1" - if [[ "$requested" == v* ]]; then - new_tag="$requested" - else - new_tag="v$requested" - fi -else - new_tag="$( - curl --fail --silent --show-error \ - "https://api.github.com/repos/$OWNER/$REPO/releases/latest" | - jq --raw-output '.tag_name' - )" -fi - -if [[ -z "$new_tag" || "$new_tag" == "null" ]]; then - echo "failed to determine the latest GitHub release tag" >&2 - exit 1 -fi - -if [[ "$new_tag" != v* ]]; then - echo "unexpected release tag format: $new_tag (expected v)" >&2 - exit 1 -fi - -new_version="${new_tag#v}" -current_version="$(sed -n 's/^[[:space:]]*version = "\([^"]*\)";/\1/p' "$PACKAGE_NIX" | head -n1)" - -if [[ "$current_version" == "$new_version" ]]; then - echo "$PNAME is already at $new_version" - exit 0 -fi - -src_expr=$(cat < $new_version" -echo " src.hash = $src_hash" -echo " pnpmDeps.hash = $pnpm_hash"