From 40abcaabb0ae7167b11d95f469970304acf24912 Mon Sep 17 00:00:00 2001 From: Amadej Kastelic Date: Sun, 27 Apr 2025 21:23:20 +0200 Subject: [PATCH] Implement support for flake.nix: nix develop --- README.md | 6 +++-- package-lock.json | 4 +-- package.json | 9 +++++-- src/main/config.cljs | 3 ++- src/main/ext/actions.cljs | 3 ++- src/main/ext/nix_env.cljs | 54 ++++++++++++++++++++++++++++++++------- src/main/main.cljs | 7 ++--- 7 files changed, 66 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 4e0c3f5..92f026d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Hi folks, My name is Roman Valihura. I'm the author of this extension. I'm Ukrainian. I was born in Ukraine. I'm living here at the moment. -As you all know Russia invaded my country. +As you all know Russia invaded my country. Russia has already killed thousands of civilians and continues the war and terror in Ukraine. I have the luck that my region is pretty far from the frontline. But even here, I'm living in the air-alarm reality. The reality where you should wake up in the middle of the night and go into the shelter. Because a rocket flies over your region. @@ -49,7 +49,7 @@ However, this process can quickly become tedious. - Install [Nix package manager](https://nixos.org/nix/). - Restart VS Code (to make sure that `nix-shell` is in the PATH) - [Install the extension](https://marketplace.visualstudio.com/items?itemName=arrterian.nix-env-selector). -- Create the Nix environment config (like `default.nix` or `shell.nix`) in +- Create the Nix environment config (like `default.nix` or `shell.nix` or `flake.nix`) in the root of your project's workspace. - Open Command Palette (Ctrl + Shift + P) and run `Nix-Env: Select Environment` command. @@ -111,6 +111,8 @@ file (located in the root of the workspace). Here are the configuration settings | `nixEnvSelector.packages` | [] | List packages using as `-p` nix-shell args | | `nixEnvSelector.args` | null | Custom args string for nix-shell. EX: `-A --pure` | | `nixEnvSelector.nixShellPath` | null | Custom path for nix-shell executable | +| `nixEnvSelector.useFlakes` | false | Enable support for `flake.nix` | + ## Supported Platforms diff --git a/package-lock.json b/package-lock.json index c3f6d0b..acead81 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nix-env-selector", - "version": "1.0.11", + "version": "1.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nix-env-selector", - "version": "1.0.11", + "version": "1.1.0", "license": "MIT", "devDependencies": { "@types/vscode": "^1.97.0", diff --git a/package.json b/package.json index db51864..bc91265 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nix-env-selector", "displayName": "Nix Environment Selector", "description": "Allows switch environment for Visual Studio Code and extensions based on Nix config file.", - "version": "1.0.12", + "version": "1.1.0", "keywords": [ "nix", "nix-env", @@ -69,7 +69,12 @@ "type": "string", "deprecationMessage": "[DEPRECATED] Use 'args' instead", "description": "Attribute path (nix-shell -A)" - } + }, + "nixEnvSelector.useFlakes": { + "type": "boolean", + "default": false, + "description": "Enable support for Nix flakes" + } } }, "commands": [ diff --git a/src/main/config.cljs b/src/main/config.cljs index 67a52e8..1cf190e 100644 --- a/src/main/config.cljs +++ b/src/main/config.cljs @@ -16,6 +16,7 @@ :nix-args (-> (workspace/config-get vscode-config :nix-env-selector/args) (#(when %1 (render-workspace %1 workspace-root)))) :nix-shell-path (-> (workspace/config-get vscode-config :nix-env-selector/nix-shell-path) - (#(when %1 (render-workspace %1 workspace-root))))}))) + (#(when %1 (render-workspace %1 workspace-root)))) + :use-flakes (workspace/config-get vscode-config :nix-env-selector/use-flakes)}))) (workspace/on-config-change update-config!) diff --git a/src/main/ext/actions.cljs b/src/main/ext/actions.cljs index 42c5f23..20d0024 100644 --- a/src/main/ext/actions.cljs +++ b/src/main/ext/actions.cljs @@ -47,7 +47,8 @@ status) (->> (env/get-nix-env-async {:nix-config nix-path :args (:nix-args @config) - :nix-shell-path (:nix-shell-path @config)} + :nix-shell-path (:nix-shell-path @config) + :use-flakes (:use-flakes @config)} log-channel) (p/map (fn [env-vars] (when env-vars diff --git a/src/main/ext/nix_env.cljs b/src/main/ext/nix_env.cljs index a04ee05..087acbb 100644 --- a/src/main/ext/nix_env.cljs +++ b/src/main/ext/nix_env.cljs @@ -8,6 +8,13 @@ (defn ^:private list-to-args [pref-arg list] (s/join " " (map #(str pref-arg " " %1) list))) +(defn ^:private has-flake? [dir] + (let [fs (js/require "fs")] + (try + (.existsSync fs (str dir "/flake.nix")) + (catch js/Error _ + false)))) + (defn ^:private get-shell-env-cmd [{:keys [packages nix-shell-path nix-config @@ -29,6 +36,17 @@ (when args (str " " args)))) +(defn ^:private get-flake-env-cmd [{:keys [nix-path dir args]}] + (str (if (empty? nix-path) + "nix" + (s/replace nix-path #" " "\\ ")) + " develop " + (when dir + (str "\"" dir "\"")) + " --command env" + (when args + (str " " args)))) + (defn ^:private parse-exported-vars [output] (->> (s/split output #"declare -x") (filter not-empty) @@ -39,25 +57,43 @@ (catch js/Error _ nil))])))) (filter not-empty))) -(defn get-nix-env-sync [options log-channel] - (let [cmd (get-shell-env-cmd options)] +(defn ^:private parse-env-vars [output] + (->> (s/split output #"\n") + (filter not-empty) + (map #(s/split %1 #"=" 2)) + (filter #(= (count %) 2)) + (map (fn [[name value]] + [name value])))) + +(defn get-nix-env-sync [{:keys [use-flakes] :as options} log-channel] + (let [dir (dirname (:nix-config options)) + is-flake (and use-flakes (has-flake? dir)) + cmd (if is-flake + (get-flake-env-cmd (assoc options :dir dir)) + (get-shell-env-cmd options)) + parser (if is-flake parse-env-vars parse-exported-vars)] (w/write-log log-channel (str "Running command synchronously: " cmd)) - (-> (execSync (clj->js cmd {:cwd (dirname (:nix-config options))})) + (-> (execSync (clj->js cmd {:cwd dir})) (.toString) - (parse-exported-vars)))) + (parser)))) -(defn get-nix-env-async [options log-channel] +(defn get-nix-env-async [{:keys [use-flakes] :as options} log-channel] (let [env-result (p/deferred) - cmd (get-shell-env-cmd options)] - (w/write-log log-channel (str "Running command asynchronously: " cmd)) - (exec (clj->js cmd {:cwd (dirname (:nix-config options))}) + dir (dirname (:nix-config options)) + is-flake (and use-flakes (has-flake? dir)) + cmd (if is-flake + (get-flake-env-cmd (assoc options :dir dir)) + (get-shell-env-cmd options)) + parser (if is-flake parse-env-vars parse-exported-vars)] + (w/write-log log-channel (str "Running command " (if is-flake "with flake" "with nix-shell") ": " cmd)) + (exec (clj->js cmd {:cwd dir}) (fn [err result stderr] (if (nil? err) (p/resolve! env-result result) (do (w/write-log log-channel (str "Error applying environment: " stderr)) (p/reject! env-result err))))) - (p/map parse-exported-vars env-result))) + (p/map parser env-result))) (defn set-current-env [env-vars] (mapv (fn [[name value]] diff --git a/src/main/main.cljs b/src/main/main.cljs index e2d00a7..b7aa8d4 100644 --- a/src/main/main.cljs +++ b/src/main/main.cljs @@ -19,9 +19,10 @@ (if (or (not-empty (:nix-file @config)) (not-empty (:nix-packages @config))) (try (-> (env/get-nix-env-sync {:nix-config (:nix-file @config) - :packages (:nix-packages @config) - :args (:nix-args @config) - :nix-shell-path (:nix-shell-path @config)} + :packages (:nix-packages @config) + :args (:nix-args @config) + :nix-shell-path (:nix-shell-path @config) + :use-flakes (:use-flakes @config)} log-channel) (env/set-current-env)) (->> status-bar