devpod-desktop: refactor

- combine the frontent derivation into the main derivation
- use cargo-tauri.hook
- patch out sidecar file logic
- patch out schema registering logic
- add glib-networking for image loading
- add darwin support
- add myself as a maintainer

TomaSajt 110c476b efcf17a6

-12
pkgs/development/tools/devpod/add-tauri-updater-feature.patch
···
-
diff --git a/Cargo.toml b/Cargo.toml
-
index 03f64e53..9e2ddcb6 100644
-
--- a/Cargo.toml
-
+++ b/Cargo.toml
-
@@ -15,6 +15,7 @@ serde_json = "1.0"
-
serde = { version = "1.0", features = ["derive"] }
-
# Tauri
-
tauri = { version = "1.2.4", features = [
-
+ "updater",
-
"dialog-save",
-
"process-relaunch",
-
"window-close",
+110 -132
pkgs/development/tools/devpod/default.nix
···
{
lib,
+
stdenv,
buildGoModule,
-
copyDesktopItems,
-
darwin,
-
desktopToDarwinBundle,
+
rustPlatform,
fetchFromGitHub,
fetchYarnDeps,
-
gtk3,
+
+
cargo-tauri_1,
+
desktop-file-utils,
installShellFiles,
-
jq,
+
makeBinaryWrapper,
+
nodejs,
+
pkg-config,
+
yarnConfigHook,
+
wrapGAppsHook3,
+
+
glib-networking,
libayatana-appindicator,
libsoup_2_4,
-
makeDesktopItem,
-
mkYarnPackage,
openssl,
-
pkg-config,
-
rust,
-
rustPlatform,
-
stdenv,
+
webkitgtk_4_0,
+
testers,
-
webkitgtk_4_0,
}:
let
-
pname = "devpod";
version = "0.5.20";
src = fetchFromGitHub {
owner = "loft-sh";
-
repo = pname;
-
rev = "v${version}";
-
sha256 = "sha256-8LbqrOKC1als3Xm6ZuU2AySwT0UWjLN2xh+/CvioYew=";
+
repo = "devpod";
+
tag = "v${version}";
+
hash = "sha256-8LbqrOKC1als3Xm6ZuU2AySwT0UWjLN2xh+/CvioYew=";
};
-
meta = with lib; {
+
meta = {
description = "Codespaces but open-source, client-only and unopinionated: Works with any IDE and lets you use any cloud, kubernetes or just localhost docker";
mainProgram = "devpod";
homepage = "https://devpod.sh";
-
license = licenses.mpl20;
-
maintainers = with maintainers; [ maxbrunet ];
+
license = lib.licenses.mpl20;
+
maintainers = with lib.maintainers; [
+
maxbrunet
+
tomasajt
+
];
};
-
in
-
rec {
-
devpod = buildGoModule {
-
inherit
-
version
-
src
-
pname
-
meta
-
;
+
+
devpod = buildGoModule (finalAttrs: {
+
pname = "devpod";
+
inherit version src meta;
vendorHash = null;
···
'';
passthru.tests.version = testers.testVersion {
-
package = devpod;
+
package = finalAttrs.finalPackage;
command = "devpod version";
version = "v${version}";
};
-
};
+
});
-
devpod-desktop =
-
let
-
frontend-build = mkYarnPackage {
-
inherit version;
-
pname = "devpod-frontend";
-
-
src = "${src}/desktop";
-
-
offlineCache = fetchYarnDeps {
-
yarnLock = "${src}/desktop/yarn.lock";
-
hash = "sha256-vUV4yX+UvEKrP0vHxjGwtW2WyONGqHVmFor+WqWbkCc=";
-
};
-
-
packageJSON = ./package.json;
-
-
buildPhase = ''
-
export HOME=$(mktemp -d)
-
yarn --offline run build
+
devpod-desktop = rustPlatform.buildRustPackage {
+
pname = "devpod-desktop";
+
inherit version src;
-
cp -r deps/devpod/dist $out
-
'';
+
sourceRoot = "${src.name}/desktop";
-
doDist = false;
-
dontInstall = true;
-
};
+
offlineCache = fetchYarnDeps {
+
yarnLock = "${src}/desktop/yarn.lock";
+
hash = "sha256-vUV4yX+UvEKrP0vHxjGwtW2WyONGqHVmFor+WqWbkCc=";
+
};
-
rustTargetPlatformSpec = stdenv.hostPlatform.rust.rustcTarget;
-
in
-
rustPlatform.buildRustPackage {
-
inherit version src;
-
pname = "devpod-desktop";
+
cargoRoot = "src-tauri";
+
buildAndTestSubdir = "src-tauri";
-
sourceRoot = "${src.name}/desktop/src-tauri";
+
useFetchCargoVendor = true;
+
cargoHash = "sha256-HD9b7OWilltL5Ymj28zoZwv5TJV3HT3LyCdagMqLH6E=";
-
useFetchCargoVendor = true;
-
cargoHash = "sha256-HD9b7OWilltL5Ymj28zoZwv5TJV3HT3LyCdagMqLH6E=";
+
patches = [
+
# don't create a .desktop file automatically registered to open the devpod:// URI scheme
+
# we edit the in-store .desktop file in postInstall to support opening the scheme,
+
# but users will have to configure the default handler manually
+
./dont-auto-register-scheme.patch
-
# Workaround:
-
# The `tauri` dependency features on the `Cargo.toml` file does not match the allowlist defined under `tauri.conf.json`.
-
# Please run `tauri dev` or `tauri build` or add the `updater` feature.
-
# Upstream is not interested in fixing that: https://github.com/loft-sh/devpod/pull/648
-
patches = [ ./add-tauri-updater-feature.patch ];
+
# disable the button that symlinks the `devpod-cli` binary to ~/.local/bin/devpod
+
# and don't show popup where it prompts you to press the above mentioned button
+
# we'll symlink it manually to $out/bin/devpod in postInstall
+
./dont-copy-sidecar-out-of-store.patch
+
];
-
postPatch =
-
''
-
ln -s ${devpod}/bin/devpod bin/devpod-cli-${rustTargetPlatformSpec}
-
cp -r ${frontend-build} frontend-build
+
postPatch =
+
''
+
ln -s ${lib.getExe devpod} src-tauri/bin/devpod-cli-${stdenv.hostPlatform.rust.rustcTarget}
+
''
+
+ lib.optionalString stdenv.hostPlatform.isLinux ''
+
substituteInPlace $cargoDepsCopy/libappindicator-sys-*/src/lib.rs \
+
--replace-fail "libayatana-appindicator3.so.1" "${libayatana-appindicator}/lib/libayatana-appindicator3.so.1"
+
'';
-
substituteInPlace tauri.conf.json --replace '"distDir": "../dist",' '"distDir": "frontend-build",'
-
''
-
+ lib.optionalString stdenv.hostPlatform.isLinux ''
-
substituteInPlace $cargoDepsCopy/libappindicator-sys-*/src/lib.rs \
-
--replace "libayatana-appindicator3.so.1" "${libayatana-appindicator}/lib/libayatana-appindicator3.so.1"
+
nativeBuildInputs =
+
[
+
cargo-tauri_1.hook
+
nodejs
+
yarnConfigHook
+
]
+
++ lib.optionals stdenv.hostPlatform.isLinux [
+
desktop-file-utils
+
pkg-config
+
wrapGAppsHook3
+
]
+
++ lib.optionals stdenv.hostPlatform.isDarwin [
+
makeBinaryWrapper
+
];
-
# Since `cargo build` is used instead of `tauri build`, configs are merged manually.
-
jq --slurp '.[0] * .[1]' tauri.conf.json tauri-linux.conf.json >tauri.conf.json.merged
-
mv tauri.conf.json.merged tauri.conf.json
-
'';
+
buildInputs = lib.optionals stdenv.hostPlatform.isLinux [
+
glib-networking
+
libayatana-appindicator
+
libsoup_2_4
+
openssl
+
webkitgtk_4_0
+
];
-
nativeBuildInputs =
-
[
-
copyDesktopItems
-
pkg-config
-
]
-
++ lib.optionals stdenv.hostPlatform.isLinux [
-
jq
-
]
-
++ lib.optionals stdenv.hostPlatform.isDarwin [
-
desktopToDarwinBundle
-
];
+
postInstall =
+
lib.optionalString stdenv.hostPlatform.isDarwin ''
+
# replace sidecar binary with symlink
+
ln -sf ${lib.getExe devpod} "$out/Applications/DevPod.app/Contents/MacOS/devpod-cli"
-
buildInputs =
-
[
-
libsoup_2_4
-
openssl
-
]
-
++ lib.optionals stdenv.hostPlatform.isLinux [
-
gtk3
-
libayatana-appindicator
-
webkitgtk_4_0
-
]
-
++ lib.optionals stdenv.hostPlatform.isDarwin [
-
darwin.apple_sdk.frameworks.Carbon
-
darwin.apple_sdk.frameworks.Cocoa
-
darwin.apple_sdk.frameworks.WebKit
-
];
+
makeWrapper "$out/Applications/DevPod.app/Contents/MacOS/DevPod" "$out/bin/dev-pod"
+
''
+
+ lib.optionalString stdenv.hostPlatform.isLinux ''
+
# replace sidecar binary with symlink
+
ln -sf ${lib.getExe devpod} "$out/bin/devpod-cli"
-
desktopItems = [
-
(makeDesktopItem {
-
name = "DevPod";
-
categories = [ "Development" ];
-
comment = "Spin up dev environments in any infra";
-
desktopName = "DevPod";
-
exec = "DevPod %U";
-
icon = "DevPod";
-
terminal = false;
-
type = "Application";
-
mimeTypes = [ "x-scheme-handler/devpod" ];
-
})
-
];
+
# set up scheme handling
+
desktop-file-edit "$out/share/applications/dev-pod.desktop" \
+
--set-key="Exec" --set-value="dev-pod %u" \
+
--set-key="MimeType" --set-value="x-scheme-handler/devpod"
+
''
+
+ ''
+
# propagate the `devpod` command
+
ln -s ${lib.getExe devpod} "$out/bin/devpod"
+
'';
-
postInstall = ''
-
ln -sf ${devpod}/bin/devpod $out/bin/devpod-cli
-
mv $out/bin/devpod-desktop $out/bin/DevPod
+
# we only want to wrap the main binary
+
dontWrapGApps = true;
-
mkdir -p $out/share/icons/hicolor/{256x256@2,128x128,32x32}/apps
-
cp icons/128x128@2x.png $out/share/icons/hicolor/256x256@2/apps/DevPod.png
-
cp icons/128x128.png $out/share/icons/hicolor/128x128/apps/DevPod.png
-
cp icons/32x32.png $out/share/icons/hicolor/32x32/apps/DevPod.png
-
'';
+
postFixup = lib.optionalString stdenv.hostPlatform.isLinux ''
+
wrapGApp "$out/bin/dev-pod"
+
'';
-
meta = meta // {
-
mainProgram = "DevPod";
-
# darwin does not build
-
# https://github.com/h4llow3En/mac-notification-sys/issues/28
-
platforms = lib.platforms.linux;
-
};
+
meta = meta // {
+
mainProgram = "dev-pod";
+
platforms = lib.platforms.linux ++ lib.platforms.darwin;
};
+
};
+
in
+
{
+
inherit devpod devpod-desktop;
}
+13
pkgs/development/tools/devpod/dont-auto-register-scheme.patch
···
+
diff --git a/src-tauri/src/custom_protocol.rs b/src-tauri/src/custom_protocol.rs
+
index b6ed6e7..5434337 100644
+
--- a/src-tauri/src/custom_protocol.rs
+
+++ b/src-tauri/src/custom_protocol.rs
+
@@ -162,7 +162,7 @@ impl CustomProtocol {
+
pub fn setup(&self, app: AppHandle) {
+
let app_handle = app.clone();
+
+
- let result = tauri_plugin_deep_link::register(APP_URL_SCHEME, move |url_scheme| {
+
+ let result = tauri_plugin_deep_link::listen(move |url_scheme| {
+
tauri::async_runtime::block_on(async {
+
info!("App opened with URL: {:?}", url_scheme.to_string());
+
+25
pkgs/development/tools/devpod/dont-copy-sidecar-out-of-store.patch
···
+
diff --git a/src/client/client.ts b/src/client/client.ts
+
index 3e1747e..a842534 100644
+
--- a/src/client/client.ts
+
+++ b/src/client/client.ts
+
@@ -250,6 +250,7 @@ class Client {
+
}
+
+
public async isCLIInstalled(): Promise<Result<boolean>> {
+
+ return Return.Value(true);
+
try {
+
// we're in a flatpak, we need to check in other paths.
+
if (import.meta.env.TAURI_IS_FLATPAK === "true") {
+
diff --git a/src/components/useInstallCLI.tsx b/src/components/useInstallCLI.tsx
+
index ba3be79..ad25f3f 100644
+
--- a/src/components/useInstallCLI.tsx
+
+++ b/src/components/useInstallCLI.tsx
+
@@ -77,7 +77,7 @@ export function useInstallCLI() {
+
variant="outline"
+
isLoading={isLoading}
+
onClick={() => addBinaryToPath({})}
+
- isDisabled={status === "success"}>
+
+ isDisabled={true}>
+
Add CLI to Path
+
</Button>
+
<AlertDialog isOpen={isOpen} onClose={onClose} leastDestructiveRef={cancelRef}>
-66
pkgs/development/tools/devpod/package.json
···
-
{
-
"name": "devpod",
-
"private": true,
-
"version": "0.0.0",
-
"type": "module",
-
"scripts": {
-
"dev": "vite",
-
"build": "tsc && vite build",
-
"preview": "vite preview",
-
"tauri": "tauri",
-
"desktop:dev": "tauri dev --config src-tauri/tauri-dev.conf.json",
-
"desktop:dev:debug": "export DEBUG=true; yarn desktop:dev",
-
"desktop:build:dev": "DEBUG=true tauri build --config src-tauri/tauri-dev.conf.json",
-
"desktop:build:debug": "tauri build --debug",
-
"desktop:build": "tauri build --features enable-updater",
-
"format:check": "prettier --check .",
-
"format:fix": "prettier --write .",
-
"types:check": "tsc -p ./tsconfig.json --noEmit"
-
},
-
"dependencies": {
-
"@chakra-ui/icons": "2.1.1",
-
"@chakra-ui/react": "2.8.1",
-
"@emotion/react": "11.11.1",
-
"@emotion/styled": "11.11.0",
-
"@headlessui/react": "1.7.17",
-
"@tanstack/react-query": "4.36.1",
-
"@tanstack/react-query-devtools": "4.36.1",
-
"@tanstack/react-table": "8.10.7",
-
"@tauri-apps/api": "1.5.3",
-
"dayjs": "1.11.10",
-
"framer-motion": "10.16.9",
-
"markdown-to-jsx": "7.3.2",
-
"react": "18.2.0",
-
"react-dom": "18.2.0",
-
"react-hook-form": "7.48.2",
-
"react-icons": "4.12.0",
-
"react-router": "6.20.0",
-
"react-router-dom": "6.20.0",
-
"tauri-plugin-store-api": "https://github.com/tauri-apps/tauri-plugin-store#v1",
-
"uuid": "9.0.1",
-
"xterm": "5.3.0",
-
"xterm-addon-fit": "0.7.0"
-
},
-
"devDependencies": {
-
"@tanstack/eslint-plugin-query": "4.36.1",
-
"@tauri-apps/cli": "1.5.11",
-
"@types/node": "18.15.3",
-
"@types/react": "18.2.28",
-
"@types/react-dom": "18.2.13",
-
"@types/uuid": "9.0.5",
-
"@typescript-eslint/eslint-plugin": "5.59.11",
-
"@typescript-eslint/parser": "5.59.11",
-
"@vitejs/plugin-react": "4.1.0",
-
"eslint": "8.44.0",
-
"eslint-config-prettier": "8.8.0",
-
"eslint-config-react-app": "7.0.1",
-
"eslint-plugin-react": "7.34.1",
-
"eslint-plugin-react-hooks": "4.6.0",
-
"prettier": "3.0.3",
-
"typescript": "5.0.4",
-
"vite": "4.4.9"
-
},
-
"resolutions": {
-
"lodash": "4.17.21"
-
}
-
}