diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 1aabd9c..4153848 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -265,7 +265,7 @@ function themeConfigEnglish() { text: "Dev Environments on NixOS", items: [ { - text: "nix develop & pkgs.mkShell", + text: "nix shell, nix develop & pkgs.runCommand", link: "/development/intro.md", }, { @@ -455,7 +455,7 @@ function themeConfigChinese() { text: "在 NixOS 上进行开发工作", items: [ { - text: "nix develop 与 pkgs.mkShell", + text: "nix shell, nix develop & pkgs.runCommand", link: "/zh/development/intro.md", }, { diff --git a/docs/development/intro.md b/docs/development/intro.md index b7d976f..f2044ee 100644 --- a/docs/development/intro.md +++ b/docs/development/intro.md @@ -8,8 +8,42 @@ You should NOT install the development environment of each language in the globa In the following sections, we'll introduce how the development environment works in NixOS. +## Createing a Custom Shell Environment with `nix shell` + +The simplest way to create a development environment is to use `nix shell`. `nix shell` will create a shell environment with the specified Nix package installed. + +Here's an example: + +```shell +# hello is not available +› hello +hello: command not found + +# Enter an environment with the 'hello' and `cowsay` package +› nix shell nixpkgs#hello nixpkgs#cowsay + +# hello is now available +› hello +Hello, world! + +# ponysay is also available +› cowsay "Hello, world!" + _______ +< hello > + ------- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || +``` + +`nix shell` is very useful when you just want to try out some packages or quickly create a clean environment. + ## Creating a Development Environment +`nix shell` is simple and easy to use, but it's not very flexible, for a more complex development environment, we need to use `pkgs.mkShell` and `nix develop`. + We can create a development environment using `pkgs.mkShell { ... }` and open an interactive Bash shell of this development environment using `nix develop`. To see how `pkgs.mkShell` works, let's take a look at [its source code](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/build-support/mkshell/default.nix). @@ -112,7 +146,7 @@ Here is a `flake.nix` that defines a development environment with Node.js 18 ins } ``` -Create an empty folder, save the above configuration as `flake.nix`, and then execute `nix develop` (or more precisely, you can use `nix develop .#default`), you will find that you have entered a nodejs 18 development environment, you can use `node` `npm` `pnpm` `yarn` and other commands. And when you just entered, `shellHook` was also executed, outputting the current version of nodejs. +Create an empty folder, save the above configuration as `flake.nix`, and then execute `nix develop` (or more precisely, you can use `nix develop .#default`), the current version of nodejs will be outputed, and now you can use `node` `pnpm` `yarn` seamlessly. ## Using zsh/fish/... instead of bash @@ -168,6 +202,66 @@ Here is an example: With the above configuration, `nix develop` will enter the REPL environment of nushell. +## Creating a Development Environment with `pkgs.runCommand` + +The derivation created by `pkgs.mkShell` cannot be used directly, but must be accessed via `nix develop`. + +It is actually possible to create a shell wrapper containing the required packages via `pkgs.stdenv.mkDerivation`, which can then be run directly into the environment by executing the wrapper. + +Using `mkDerivation` directly is a bit cumbersome, and Nixpkgs provides some simpler functions to help us create such wrappers, such as `pkgs.runCommand`. + +Example: + +```nix +{ + description = "A Nix-flake-based Node.js development environment"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11"; + }; + + outputs = { self , nixpkgs ,... }: let + # system should match the system you are running on + # system = "x86_64-linux"; + system = "x86_64-darwin"; + in { + packages."${system}".dev = let + pkgs = import nixpkgs { + inherit system; + overlays = [ + (self: super: rec { + nodejs = super.nodejs_20; + pnpm = super.nodePackages.pnpm; + }) + ]; + }; + packages = with pkgs; [ + nodejs + pnpm + nushell + ]; + in pkgs.runCommand "dev-shell" { + # Dependencies that should exist in the runtime environment + buildInputs = packages; + # Dependencies that should only exist in the build environment + nativeBuildInputs = [ pkgs.makeWrapper ]; + } '' + mkdir -p $out/bin/ + ln -s ${pkgs.nushell}/bin/nu $out/bin/dev-shell + wrapProgram $out/bin/dev-shell --prefix PATH : ${pkgs.lib.makeBinPath packages} + ''; + }; +} +``` + +Then execute `nix run .#dev`, you will enter a nushell session, where you can use the `node` `pnpm` command normally, and the node version is 20. + +Related source code: + +- [pkgs/build-support/trivial-builders/default.nix - runCommand](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/trivial-builders/default.nix#L21-L49) +- [pkgs/build-support/build-support/setup-hooks/make-wrapper.sh](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/setup-hooks/make-wrapper.sh) + + ## Enter the build environment of any Nix package Now let's take a look at `nix develop`, first read the help document output by `nix develop --help`: diff --git a/docs/other-usage-of-flakes/the-new-cli.md b/docs/other-usage-of-flakes/the-new-cli.md index e32de95..e22beb6 100644 --- a/docs/other-usage-of-flakes/the-new-cli.md +++ b/docs/other-usage-of-flakes/the-new-cli.md @@ -13,12 +13,23 @@ The `nix shell` command allows you to enter an environment with the specified Ni › hello hello: command not found -# Enter an environment with the 'hello' package -› nix shell nixpkgs#hello +# Enter an environment with the 'hello' and `cowsay` package +› nix shell nixpkgs#hello nixpkgs#cowsay # hello is now available › hello Hello, world! + +# ponysay is also available +› cowsay "Hello, world!" + _______ +< hello > + ------- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || ``` ## `nix run` diff --git a/docs/zh/development/intro.md b/docs/zh/development/intro.md index 0211ba6..9bd57cf 100644 --- a/docs/zh/development/intro.md +++ b/docs/zh/development/intro.md @@ -10,8 +10,44 @@ 在本章中我们先学习一下 Nix Flakes 开发环境的实现原理,后面的章节再按使用场景介绍一些更具体的内容。 + +## 通过 `nix shell` 创建开发环境 + +在 NixOS 上,最简单的创建开发环境的方法是使用 `nix shell`,它会创建一个含有指定 Nix 包的 shell 环境。 + +示例: + +```shell +# hello 不存在 +› hello +hello: command not found + +# 进入到一个含有 hello 与 cowsay 的 shell 环境 +# 可以指定多个包,用空格分隔 +› nix shell nixpkgs#hello nixpkgs#cowsay + +# hello 可以用了 +› hello +Hello, world! + +# cowsay 也可以用了 +› cowsay "Hello, world!" + _______ +< hello > + ------- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || +``` + +`nix shell` 非常适合用于临时试用一些软件包或者快速创建一个干净的环境。 + ## 创建与使用开发环境 +`nix shell` 用起来非常简单,但它并不够灵活,对于更复杂的开发环境管理,我们需要使用 `pkgs.mkShell` 与 `nix develop`。 + 在 Nix Flakes 中,我们可以通过 `pkgs.mkShell { ... }` 来定义一个项目环境,通过 `nix develop` 来打开一个该开发环境的交互式 Bash Shell. 为了更好的使用上述两个功能,我们先来看看它们的原理。 @@ -116,8 +152,7 @@ stdenv.mkDerivation ({ } ``` -建个空文件夹,将上面的配置保存为 `flake.nix`,然后执行 `nix develop`(或者更精确点,可以用 `nix develop .#default`),你会发现你已经进入了一个 nodejs 18 的开发环境,可以使用 `node` `npm` `pnpm` `yarn` 等命令了。而且刚进入时,`shellHook` 也被执行了,输出了当前 nodejs 的版本。 - +建个空文件夹,将上面的配置保存为 `flake.nix`,然后执行 `nix develop`(或者更精确点,可以用 `nix develop .#default`),首先会打印出当前 nodejs 的版本,之后 `node` `pnpm` `yarn` 等命令就都能正常使用了。 ## 在开发环境中使用 zsh/fish 等其他 shell @@ -171,6 +206,66 @@ stdenv.mkDerivation ({ 使用上面的 `flake.nix` 配置,`nix develop` 将进入一个 nodejs 18 的开发环境,同时使用 `nushell` 作为交互式 shell. +## 通过 `pkgs.runCommand` 创建开发环境 + +`pkgs.mkShell` 创建的 derivation 不能直接使用,必须通过 `nix develop` 进入到该环境中。 + +实际上我们也可以通过 `pkgs.stdenv.mkDerivation` 来创建一个包含所需软件包的 shell wrapper, 这样就能直接通过执行运行该 wrapper 来进入到该环境中。 + +直接使用 `mkDerivation` 略显繁琐,Nixpkgs 提供了一些更简单的函数来帮助我们创建这类 wrapper,比如 `pkgs.runCommand`. + +示例: + +```nix +{ + description = "A Nix-flake-based Node.js development environment"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11"; + }; + + outputs = { self , nixpkgs ,... }: let + # system should match the system you are running on + # system = "x86_64-linux"; + system = "x86_64-darwin"; + in { + packages."${system}".dev = let + pkgs = import nixpkgs { + inherit system; + overlays = [ + (self: super: rec { + nodejs = super.nodejs_20; + pnpm = super.nodePackages.pnpm; + }) + ]; + }; + packages = with pkgs; [ + nodejs + pnpm + nushell + ]; + in pkgs.runCommand "dev-shell" { + # Dependencies that should exist in the runtime environment + buildInputs = packages; + # Dependencies that should only exist in the build environment + nativeBuildInputs = [ pkgs.makeWrapper ]; + } '' + mkdir -p $out/bin/ + ln -s ${pkgs.nushell}/bin/nu $out/bin/dev-shell + wrapProgram $out/bin/dev-shell --prefix PATH : ${pkgs.lib.makeBinPath packages} + ''; + }; +} +``` + +然后执行 `nix run .#dev`,就能进入一个 nushell session,可以在其中正常使用 `node` `pnpm` 命令,且 node 版本为 20. + +相关源代码: + +- [pkgs/build-support/trivial-builders/default.nix - runCommand](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/trivial-builders/default.nix#L21-L49) +- [pkgs/build-support/build-support/setup-hooks/make-wrapper.sh](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/setup-hooks/make-wrapper.sh) + + ## 进入任何 Nix 包的构建环境 现在再来看看 `nix develop`,先读下 `nix develop --help` 输出的帮助文档: @@ -346,6 +441,6 @@ nix build "nixpkgs#ponysay" - [pkgs.mkShell - nixpkgs manual](https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-mkShell) - [A minimal nix-shell](https://fzakaria.com/2021/08/02/a-minimal-nix-shell.html) - [One too many shell, Clearing up with nix' shells nix shell and nix-shell - Yannik Sander](https://blog.ysndr.de/posts/guides/2021-12-01-nix-shells/) - +- [Shell Scripts - NixOS Wiki](https://nixos.wiki/wiki/Shell_Scripts) [New Nix Commands]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix.html diff --git a/docs/zh/other-usage-of-flakes/the-new-cli.md b/docs/zh/other-usage-of-flakes/the-new-cli.md index 1aa6c36..d059034 100644 --- a/docs/zh/other-usage-of-flakes/the-new-cli.md +++ b/docs/zh/other-usage-of-flakes/the-new-cli.md @@ -12,14 +12,28 @@ › hello hello: command not found -# 进入到一个含有 hello 的 shell 环境 -› nix shell nixpkgs#hello +# 进入到一个含有 hello 与 cowsay 的 shell 环境 +# 可以指定多个包,用空格分隔 +› nix shell nixpkgs#hello nixpkgs#cowsay # hello 可以用了 › hello Hello, world! + +# cowsay 也可以用了 +› cowsay "Hello, world!" + _______ +< hello > + ------- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || ``` +`nix shell` 非常适合用于临时试用一些软件包或者快速创建一个干净的环境。 + ## `nix run` `nix run` 则是创建一个含有指定 Nix 包的环境,并在该环境中直接运行该 Nix 包(临时运行该程序,不将它安装到系统环境中):