1{
2 lib,
3 stdenv,
4 cacert,
5 cargo-tauri,
6 cmake,
7 curl,
8 desktop-file-utils,
9 fetchFromGitHub,
10 git,
11 glib-networking,
12 jq,
13 libgit2,
14 makeBinaryWrapper,
15 moreutils,
16 nix-update-script,
17 nodejs,
18 openssl,
19 pkg-config,
20 pnpm_9,
21 rust,
22 rustPlatform,
23 turbo,
24 webkitgtk_4_1,
25 wrapGAppsHook4,
26 yq,
27}:
28
29let
30 excludeSpec = spec: [
31 "--exclude"
32 spec
33 ];
34in
35
36rustPlatform.buildRustPackage rec {
37 pname = "gitbutler";
38 version = "0.14.19";
39
40 src = fetchFromGitHub {
41 owner = "gitbutlerapp";
42 repo = "gitbutler";
43 tag = "release/${version}";
44 hash = "sha256-NopuZbgF2jdwuf/p/JzubS0IM5xBnlkh9Tj234auBnE=";
45 };
46
47 # Let Tauri know what version we're building
48 #
49 # Remove references to non-existent workspaces in `gix` crates
50 #
51 # Deactivate the built-in updater
52 postPatch = ''
53 tauriConfRelease="crates/gitbutler-tauri/tauri.conf.release.json"
54 jq '.version = "${version}" | .bundle.createUpdaterArtifacts = false' "$tauriConfRelease" | sponge "$tauriConfRelease"
55
56 tomlq -ti 'del(.lints) | del(.workspace.lints)' "$cargoDepsCopy"/gix*/Cargo.toml
57
58 substituteInPlace apps/desktop/src/lib/backend/tauri.ts \
59 --replace-fail 'checkUpdate = check;' 'checkUpdate = () => null;'
60 '';
61
62 cargoHash = "sha256-wzSRUZeB5f9Z/D+Sa5Nl77jh7GDnnUehcmwanPcaSKM=";
63
64 pnpmDeps = pnpm_9.fetchDeps {
65 inherit pname version src;
66 fetcherVersion = 1;
67 hash = "sha256-5NtfstUuIYyntt09Mu9GAFAOImfO6VMmJ7g15kvGaLE=";
68 };
69
70 nativeBuildInputs = [
71 cacert # Required by turbo
72 cargo-tauri.hook
73 cmake # Required by `zlib-sys` crate
74 desktop-file-utils
75 jq
76 moreutils
77 nodejs
78 pkg-config
79 pnpm_9.configHook
80 turbo
81 wrapGAppsHook4
82 yq # For `tomlq`
83 ]
84 ++ lib.optional stdenv.hostPlatform.isDarwin makeBinaryWrapper;
85
86 buildInputs = [
87 libgit2
88 openssl
89 ]
90 ++ lib.optional stdenv.hostPlatform.isDarwin curl
91 ++ lib.optionals stdenv.hostPlatform.isLinux [
92 glib-networking
93 webkitgtk_4_1
94 ];
95
96 tauriBuildFlags = [
97 "--config"
98 "crates/gitbutler-tauri/tauri.conf.release.json"
99 ];
100
101 nativeCheckInputs = [ git ];
102
103 # `gitbutler-git`'s checks do not support release mode
104 checkType = "debug";
105 cargoTestFlags = [
106 "--workspace"
107 ]
108 ++ lib.concatMap excludeSpec [
109 # Requires Git directories
110 "but-core"
111 "but-rebase"
112 "but-workspace"
113 # Fails due to the issues above and below
114 "but-hunk-dependency"
115 # Errors with "Lazy instance has previously been poisoned"
116 "gitbutler-branch-actions"
117 "gitbutler-stack"
118 # `Expecting driver to be located at "../../target/debug/gitbutler-cli" - we also assume a certain crate location`
119 # We're not (usually) building in debug mode and always have a different target directory, so...
120 "gitbutler-edit-mode"
121 ];
122
123 env = {
124 # Make sure `crates/gitbutler-tauri/inject-git-binaries.sh` can find our
125 # target dir
126 # https://github.com/gitbutlerapp/gitbutler/blob/56b64d778042d0e93fa362f808c35a7f095ab1d1/crates/gitbutler-tauri/inject-git-binaries.sh#L10C10-L10C26
127 TRIPLE_OVERRIDE = rust.envVars.rustHostPlatformSpec;
128
129 # `pnpm`'s `fetchDeps` and `configHook` uses a specific version of pnpm, not upstream's
130 COREPACK_ENABLE_STRICT = 0;
131
132 # We depend on nightly features
133 RUSTC_BOOTSTRAP = 1;
134
135 # We also need to have `tracing` support in `tokio` for `console-subscriber`
136 RUSTFLAGS = "--cfg tokio_unstable";
137
138 TUBRO_BINARY_PATH = lib.getExe turbo;
139
140 OPENSSL_NO_VENDOR = true;
141 LIBGIT2_NO_VENDOR = 1;
142 };
143
144 postInstall =
145 lib.optionalString stdenv.hostPlatform.isDarwin ''
146 makeBinaryWrapper $out/Applications/GitButler.app/Contents/MacOS/gitbutler-tauri $out/bin/gitbutler-tauri
147 ''
148 + lib.optionalString stdenv.hostPlatform.isLinux ''
149 desktop-file-edit \
150 --set-comment "A Git client for simultaneous branches on top of your existing workflow." \
151 --set-key="Keywords" --set-value="git;" \
152 --set-key="StartupWMClass" --set-value="GitButler" \
153 $out/share/applications/GitButler.desktop
154 '';
155
156 passthru = {
157 updateScript = nix-update-script {
158 extraArgs = [
159 "--version-regex"
160 "release/(.*)"
161 ];
162 };
163 };
164
165 meta = {
166 description = "Git client for simultaneous branches on top of your existing workflow";
167 homepage = "https://gitbutler.com";
168 changelog = "https://github.com/gitbutlerapp/gitbutler/releases/tag/release/${version}";
169 license = lib.licenses.fsl11Mit;
170 maintainers = with lib.maintainers; [
171 getchoo
172 techknowlogick
173 ];
174 mainProgram = "gitbutler-tauri";
175 platforms = lib.platforms.linux ++ lib.platforms.darwin;
176 };
177}