Merge pull request #86 from ryan4yin/refactor-nixos-with-flakes-enabled

refactor: nixos with flakes enabled
This commit is contained in:
Ryan Yin 2024-02-15 16:05:34 +08:00 committed by GitHub
commit da12af9d53
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 716 additions and 356 deletions

View File

@ -74,8 +74,8 @@ In your system's `flake.nix`, add a new outputs named `colmena`. A simple exampl
}; };
}; };
# Host name = "nixos-test" # Host name = "my-nixos"
"nixos-test" = { name, nodes, ... }: { "my-nixos" = { name, nodes, ... }: {
# Parameters related to remote deployment # Parameters related to remote deployment
deployment.targetHost = "192.168.5.42"; # Remote host's IP address deployment.targetHost = "192.168.5.42"; # Remote host's IP address
deployment.targetUser = "root"; # Remote host's username deployment.targetUser = "root"; # Remote host's username
@ -103,14 +103,14 @@ For more advanced usage, refer to colmena's official documentation at <https://c
Using `nixos-rebuild` for remote deployment has the advantage of being similar to deploying to a local host. It only requires a few additional parameters to specify the remote host's IP address, username, and other details. Using `nixos-rebuild` for remote deployment has the advantage of being similar to deploying to a local host. It only requires a few additional parameters to specify the remote host's IP address, username, and other details.
For instance, to deploy the configuration defined in the `nixosConfigurations.nixos-test` of your flake to a remote host, use the following command: For instance, to deploy the configuration defined in the `nixosConfigurations.my-nixos` of your flake to a remote host, use the following command:
```bash ```bash
nixos-rebuild switch --flake .#nixos-text \ nixos-rebuild switch --flake .#nixos-text \
--target-host root@192.168.4.1 --build-host localhost --verbose --target-host root@192.168.4.1 --build-host localhost --verbose
``` ```
The above command will build and deploy the configuration of `nixos-test` to a server with IP `192.168.4.1`. The system build process will occur locally. The above command will build and deploy the configuration of `my-nixos` to a server with IP `192.168.4.1`. The system build process will occur locally.
If you prefer to build the configuration on the remote host, replace `--build-host localhost` with `--build-host root@192.168.4.1`. If you prefer to build the configuration on the remote host, replace `--build-host localhost` with `--build-host root@192.168.4.1`.
@ -133,7 +133,7 @@ Host aquamarine
With this setup, you can use host aliases for deployment: With this setup, you can use host aliases for deployment:
```bash ```bash
nixos-rebuild switch --flake .#nixos-test --target-host root@aquamarine --build-host root@aquamarine --verbose nixos-rebuild switch --flake .#my-nixos --target-host root@aquamarine --build-host root@aquamarine --verbose
``` ```
This offers a more convenient way to deploy using the defined host aliases. This offers a more convenient way to deploy using the defined host aliases.

View File

@ -141,7 +141,7 @@ sudo nixos-rebuild switch --option substituters "https://nix-community.cachix.or
Choose one of the above three methods for configuration and deployment. After a successful deployment, all subsequent packages will preferentially search for caches from domestic mirror sources. Choose one of the above three methods for configuration and deployment. After a successful deployment, all subsequent packages will preferentially search for caches from domestic mirror sources.
> If your system hostname is not `nixos-test`, you need to modify the name of `nixosConfigurations` in `flake.nix` or use `--flake /etc/nixos#nixos-test` to specify the configuration name. > If your system hostname is not `my-nixos`, you need to modify the name of `nixosConfigurations` in `flake.nix` or use `--flake /etc/nixos#my-nixos` to specify the configuration name.
### The `extra-` Prefix for Nix Options Parameters ### The `extra-` Prefix for Nix Options Parameters

View File

@ -28,7 +28,7 @@ Here's an example of how you can add multiple nixpkgs inputs, each using a diffe
... ...
}: { }: {
nixosConfigurations = { nixosConfigurations = {
nixos-test = nixpkgs.lib.nixosSystem rec { my-nixos = nixpkgs.lib.nixosSystem rec {
system = "x86_64-linux"; system = "x86_64-linux";
# The `specialArgs` parameter passes the # The `specialArgs` parameter passes the
@ -51,7 +51,7 @@ Here's an example of how you can add multiple nixpkgs inputs, each using a diffe
}; };
modules = [ modules = [
./hosts/nixos-test ./hosts/my-nixos
# Omit other configurations... # Omit other configurations...
]; ];

View File

@ -107,7 +107,7 @@ A more complicated example, [ryan4yin/nix-config/i3-kickstarter](https://github.
│ ├── msi-rtx4090 # My main machine's configuration │ ├── msi-rtx4090 # My main machine's configuration
│ │ ├── default.nix # This is the old configuration.nix, but most of the content has been split out to modules. │ │ ├── default.nix # This is the old configuration.nix, but most of the content has been split out to modules.
│ │ └── hardware-configuration.nix # hardware & disk related configuration, autogenerated by nixos │ │ └── hardware-configuration.nix # hardware & disk related configuration, autogenerated by nixos
│ └── nixos-test # my test machine's configuration │ └── my-nixos # my test machine's configuration
│ ├── default.nix │ ├── default.nix
│ └── hardware-configuration.nix │ └── hardware-configuration.nix
├── modules # some common NixOS modules that can be reused ├── modules # some common NixOS modules that can be reused
@ -218,7 +218,7 @@ To test the usage of `lib.mkBefore` and `lib.mkAfter`, let's create a simple Fla
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
outputs = {nixpkgs, ...}: { outputs = {nixpkgs, ...}: {
nixosConfigurations = { nixosConfigurations = {
"nixos-test" = nixpkgs.lib.nixosSystem { "my-nixos" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
modules = [ modules = [
@ -262,7 +262,7 @@ The flake above contains the usage of `lib.mkBefore` and `lib.mkAfter` on multil
```bash ```bash
# Example 1: multiline string merging # Example 1: multiline string merging
echo $(nix eval .#nixosConfigurations.nixos-test.config.programs.bash.shellInit) echo $(nix eval .#nixosConfigurations.my-nixos.config.programs.bash.shellInit)
trace: warning: system.stateVersion is not set, defaulting to 23.11. Read why this matters on https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersio trace: warning: system.stateVersion is not set, defaulting to 23.11. Read why this matters on https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersio
n. n.
"echo 'insert before default' "echo 'insert before default'
@ -279,13 +279,13 @@ echo 'insert after default'
" "
# example 2: single-line string merging # example 2: single-line string merging
echo $(nix eval .#nixosConfigurations.nixos-test.config.programs.zsh.shellInit) echo $(nix eval .#nixosConfigurations.my-nixos.config.programs.zsh.shellInit)
"echo 'insert before default'; "echo 'insert before default';
echo 'this is default'; echo 'this is default';
echo 'insert after default';" echo 'insert after default';"
# Example 3: list merging # Example 3: list merging
nix eval .#nixosConfigurations.nixos-test.config.nix.settings.substituters nix eval .#nixosConfigurations.my-nixos.config.nix.settings.substituters
[ "https://nix-community.cachix.org" "https://nix-community.cachix.org" "https://cache.nixos.org/" "https://ryan4yin.cachix.org" ] [ "https://nix-community.cachix.org" "https://nix-community.cachix.org" "https://cache.nixos.org/" "https://ryan4yin.cachix.org" ]
``` ```

View File

@ -1,271 +1,424 @@
# Enabling NixOS with Flakes # Enabling NixOS with Flakes
## Enabling Flakes Support ## Enabling Flakes Support for NixOS {#enable-nix-flakes}
Flakes provide improved reproducibility and a more organized package structure, making it easier to maintain NixOS configurations compared to the traditional approach. Therefore, it is recommended to manage NixOS using Flakes. Compared to the default configuration method currently used in NixOS, Flakes offers better reproducibility. Its clear package structure definition inherently supports dependencies on other Git repositories, facilitating code sharing. Therefore, this book suggests using Flakes to manage system configurations. Currently, Flakes is still an experimental feature and not enabled by default. We need to manually modify the `/etc/nixos/configuration.nix` file to enable the Flakes feature and the accompanying new nix command-line tool:
However, as Flakes is still an experimental feature, it is not enabled by default. To enable Flakes, you need to modify the `/etc/nixos/configuration.nix` file as follows: ```nix{12,16}
```nix{15,18-19}
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running 'nixos-help').
{ config, pkgs, ... }: { config, pkgs, ... }:
{ {
imports = imports = [
[ # Include the results of the hardware scan. # Include the results of the hardware scan.
./hardware-configuration.nix ./hardware-configuration.nix
]; ];
# Omit the previous configuration... # ......
# Enable Flakes and the new command-line tool # Enable the Flakes feature and the accompanying new nix command-line tool
nix.settings.experimental-features = [ "nix-command" "flakes" ]; nix.settings.experimental-features = [ "nix-command" "flakes" ];
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
# Flakes use Git to pull dependencies from data sources # Flakes clones its dependencies through the git command,
# so git must be installed first
git git
vim vim
wget wget
curl curl
]; ];
# Set default editor to vim # Set the default editor to vim
environment.variables.EDITOR = "vim"; environment.variables.EDITOR = "vim";
# Omit the rest of the configuration... # ......
} }
``` ```
To apply the changes, run `sudo nixos-rebuild switch`. After that, you can start writing the configuration for NixOS using Flakes. After making these changes, run `sudo nixos-rebuild switch` to apply the modifications. Then, you can use the Flakes feature to manage your system configuration.
## Switching to `flake.nix` for System Configuration The new nix command-line tool also offers some convenient features. For example, you can now use the `nix repl` command to open a nix interactive environment.
If you're interested, you can use it to review and test all the Nix syntax you've learned before.
After enabling `flakes`, whenever you run `sudo nixos-rebuild switch`, it will first attempt to read the `/etc/nixos/flake.nix` file. If the file is not found, it will fallback to `/etc/nixos/configuration.nix`.
To learn how to write a Flakes configuration, you can refer to the official Flakes templates provided by Nix. To check the available templates, run the following command: ## Switching System Configuration to `flake.nix` {#switch-to-flake-nix}
After enabling the Flakes feature, the `sudo nixos-rebuild switch` command will prioritize reading the `/etc/nixos/flake.nix` file, and if it's not found, it will attempt to use `/etc/nixos/configuration.nix`.
You can start by using the official templates to learn how to write a flake.
First, check what templates are available:
```bash ```bash
nix flake show templates nix flake show templates
``` ```
The `templates#full` template contains examples covering various use cases. Let's take a look at them: Among them, the `templates#full` template demonstrates all possible usage. Take a look at its content:
```bash ```bash
nix flake init -t templates#full nix flake init -t templates#full
cat flake.nix cat flake.nix
``` ```
After reviewing the example, create a file named `/etc/nixos/flake.nix` and copy the content of the example into it. From now on, all system modifications will be managed by Flakes using `/etc/nixos/flake.nix`. Referencing this template, create the file `/etc/nixos/flake.nix` and write the configuration content. All subsequent system modifications will be taken over by Nix Flakes.
Here's an example of the content:
Note that the copied template cannot be used directly. You need to modify it to make it work. Here's an example of `/etc/nixos/flake.nix`:
```nix ```nix
{ {
description = "Ryan's NixOS Flake"; description = "A simple NixOS flake";
# This is the standard format for flake.nix.
# `inputs` are the dependencies of the flake,
# and `outputs` function will return all the build results of the flake.
# Each item in `inputs` will be passed as a parameter to
# the `outputs` function after being pulled and built.
inputs = { inputs = {
# There are many ways to reference flake inputs. # NixOS official package source, using the nixos-23.11 branch here
# The most widely used is `github:owner/name/reference`,
# which represents the GitHub repository URL + branch/commit-id/tag.
# Official NixOS package source, using nixos-23.11 branch here
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
# home-manager, used for managing user configuration
home-manager = {
url = "github:nix-community/home-manager/release-23.11";
# The `follows` keyword in inputs is used for inheritance.
# Here, `inputs.nixpkgs` of home-manager is kept consistent with
# the `inputs.nixpkgs` of the current flake,
# to avoid problems caused by different versions of nixpkgs.
inputs.nixpkgs.follows = "nixpkgs";
}; };
};
# `outputs` are all the build result of the flake.
#
# A flake can have many use cases and different types of outputs.
#
# parameters in function `outputs` are defined in `inputs` and
# can be referenced by their names. However, `self` is an exception,
# this special parameter points to the `outputs` itself(self-reference)
#
# The `@` syntax here is used to alias the attribute set of the
# inputs's parameter, making it convenient to use inside the function.
outputs = { self, nixpkgs, ... }@inputs: { outputs = { self, nixpkgs, ... }@inputs: {
nixosConfigurations = { # Please replace my-nixos with your hostname
# By default, NixOS will try to refer the nixosConfiguration with nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
# its hostname, so the system named `nixos-test` will use this one.
# However, the configuration name can also be specified using:
# sudo nixos-rebuild switch --flake /path/to/flakes/directory#<name>
#
# The `nixpkgs.lib.nixosSystem` function is used to build this
# configuration, the following attribute set is its parameter.
#
# Run the following command in the flake's directory to
# deploy this configuration on any NixOS system:
# sudo nixos-rebuild switch --flake .#nixos-test
"nixos-test" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
# The Nix module system can modularize configuration,
# improving the maintainability of configuration.
#
# Each parameter in the `modules` is a Nixpkgs Module, and
# there is a partial introduction to it in the nixpkgs manual:
# <https://nixos.org/manual/nixpkgs/unstable/#module-system-introduction>
# It is said to be partial because the documentation is not
# complete, only some simple introductions.
# such is the current state of Nix documentation...
#
# A Nixpkgs Module can be an attribute set, or a function that
# returns an attribute set. By default, if a Nixpkgs Module is a
# function, this function has the following default parameters:
#
# lib: the nixpkgs function library, which provides many
# useful functions for operating Nix expressions:
# https://nixos.org/manual/nixpkgs/stable/#id-1.4
# config: all config options of the current flake, very useful
# options: all options defined in all NixOS Modules
# in the current flake
# pkgs: a collection of all packages defined in nixpkgs,
# plus a set of functions related to packaging.
# you can assume its default value is
# `nixpkgs.legacyPackages."${system}"` for now.
# can be customed by `nixpkgs.pkgs` option
# modulesPath: the default path of nixpkgs's modules folder,
# used to import some extra modules from nixpkgs.
# this parameter is rarely used,
# you can ignore it for now.
#
# The default parameters mentioned above are automatically
# generated by Nixpkgs.
# However, if you need to pass other non-default parameters
# to the submodules,
# you'll have to manually configure these parameters using
# `specialArgs`.
# you must use `specialArgs` by uncommenting the following line:
#
# specialArgs = {...}; # pass custom arguments into all submodules.
modules = [ modules = [
# Import the configuration.nix here, so that the # Import the previous configuration.nix we used, so the old configuration file still takes effect
# old configuration file can still take effect.
# Note: configuration.nix itself is also a Nixpkgs Module,
./configuration.nix ./configuration.nix
]; ];
}; };
}; };
};
} }
``` ```
We defined a NixOS system called `nixos-test` with a configuration file at `./configuration.nix`, which is the classic configuration we modified before. Therefore, we can still make use of it. Here we defined a system named `my-nixos`, with its configuration file located at `/etc/nixos/` as `./configuration.nix`. This means we are still using the old configuration.
To apply the configuration to a system with hostname `nixos-test`, run `sudo nixos-rebuild switch --flake /etc/nixos#nixos-test`. No changes will be made to the system because we imported the old configuration file in `/etc/nixos/flake.nix`, so the actual state we declared remains unchanged. Now, when you execute `sudo nixos-rebuild switch` to apply the configuration, the system should not change at all because we have simply switched to using Nix Flakes, and the configuration content remains consistent with before.
The comments in the above code are already quite detailed, but let's emphasize a few points here: After the switch, we can manage the system through the Flakes feature.
1. Default parameters like `lib`, `pkgs`, `config`, and others are automatically generated by Nixpkgs and can be automatically injected into submodules without the need for additional declarations here. Currently, our flake includes these files:
2. In `specialArgs = {...};`, the content of the attribute set is omitted here. Its contents are automatically injected into submodules through name matching. - `/etc/nixos/flake.nix`: The entrypoint for the flake, which is recognized and deployed when `sudo nixos-rebuild switch` is executed.
- `/etc/nixos/flake.lock`: The automatically generated version lock file, which records the data sources, hash values, and version numbers of all inputs in the entire flake, ensuring system reproducibility.
- `/etc/nixos/configuration.nix`: This is our previous configuration file, which is imported as a module in `flake.nix`. Currently, all system configurations are written in this file.
- `/etc/nixos/hardware-configuration.nix`: This is the system hardware configuration file, generated by NixOS, which describes the system's hardware information.
1. A common usage, for instance, is to directly write `specialArgs = inputs;`, enabling all data sources from the `inputs` attribute set to be used in the submodules. Up to this point, `/etc/nixos/flake.nix` has merely been a thin wrapper around `/etc/nixos/configuration.nix`, offering no new functionality and introducing no disruptive changes. In the content of the book that follows, we will gradually see the benefits that such a wrapper brings.
2. If you do not want to get all the data sources in `inputs` mixed with the defaults, use `specialArgs = {inherit inputs;};`(akin to `specialArgs = {inputs = inputs;};`) instead.
## Managing System Packages with Flakes > Note: The configuration management method described in this book is NOT "Everything in a single file". It is recommended to categorize configuration content into different nix files, then introduce these configuration files in the `modules` list of `flake.nix`, and manage them with Git.
>
> The benefits of this approach are better organization of configuration files and improved maintainability of the configuration. The section [Modularizing NixOS Configuration](./modularize-the-configuration.md) will explain in detail how to modularize your NixOS configuration, and [Other Useful Tips - Managing NixOS Configuration with Git](./other-useful-tips.md) will introduce several best practices for managing NixOS configuration with Git.
After the switch, we can manage the system using Flakes. One common requirement is installing packages. We have previously seen how to install packages using `environment.systemPackages` from the official `nixpkgs` repository.
Now let's learn how to install packages from other sources using Flakes. This is really useful when you want to use a newer version of some package that is not added into Nixpkgs yet. ## `flake.nix` Configuration Explained {#flake-nix-configuration-explained}
Let's use [Helix](https://github.com/helix-editor/helix) editor as an example. Above, we created a `flake.nix` file to manage system configurations, but you might still be unclear about its structure. Let's explain the content of this file in detail.
First, we need to add Helix as an input in `flake.nix`: ### 1. Flake Inputs
```nix{10,20} First, let's look at the `inputs` attribute. It is an attribute set that defines all the dependencies of this flake. These dependencies will be passed as arguments to the `outputs` function after they are fetched:
```nix{2-5,7}
{ {
description = "NixOS configuration of Ryan Yin"; inputs = {
# NixOS official package source, using the nixos-23.11 branch here
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
};
# ... outputs = { self, nixpkgs, ... }@inputs: {
# Omitting previous configurations......
};
}
```
Dependencies in `inputs` has many types and definitions.
It can be another flake, a regular Git repository, or a local path.
The section [Other Usage of Flakes - Flake Inputs](../other-usage-of-flakes/inputs.md) describes common types of dependencies and their definitions in detail.
Here we only define a dependency named `nixpkgs`, which is the most common way to reference in a flake, i.e., `github:owner/name/reference`. The `reference` here can be a branch name, commit-id, or tag.
After `nixpkgs` is defined in `inputs`, you can use it in the parameters of the subsequent `outputs` function, which is exactly what our example does.
### 2. Flake Outputs
Now let's look at `outputs`.
It is a function that takes the dependencies from `inputs` as its parameters, and its return value is an attribute set, which represents the build results of the flake:
```nix{11-19}
{
description = "A simple NixOS flake";
inputs = { inputs = {
# ... # NixOS official package source, here using the nixos-23.11 branch
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
};
# Helix editor, the master branch # The `self` parameter is special, it refers to
# the attribute set returned by the `outputs` function itself.
outputs = { self, nixpkgs, ... }@inputs: {
# The host with the hostname `my-nixos` will use this configuration
nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
];
};
};
}
```
Flakes can have various purposes and can have different types of outputs. The section [Flake Outputs](../other-usage-of-flakes/outputs.md) provides a more detailed introduction.
Here, we are only using the `nixosConfigurations` type of outputs, which is used to configure NixOS systems.
When we run the `sudo nixos-rebuild switch` command, it looks for the `nixosConfigurations.my-nixos` attribute (where `my-nixos` will be the hostname of your current system) in the attribute set returned by the `outputs` function of `/etc/nixos/flake.nix` and uses the definition there to configure your NixOS system.
Actually, we can also customize the location of the flake and the name of the NixOS configuration instead of using the defaults.
This can be done by adding the `--flake` parameter to the `nixos-rebuild` command. Here's an example:
```nix
sudo nixos-rebuild switch --flake /path/to/your/flake#your-hostname
```
A brief explanation of the `--flake /path/to/your/flake#your-hostname` parameter:
1. `/path/to/your/flake` is the location of the target flake. The default path is `/etc/nixos/`.
2. `#` is a separator, and `your-hostname` is the name of the NixOS configuration. `nixos-rebuild` will default to using the hostname of your current system as the configuration name to look for.
You can even directly reference a remote GitHub repository as your flake source, for example:
```nix
sudo nixos-rebuild switch --flake github:owner/repo#your-hostname
```
### 3. Simple Introduction to `nixpkgs.lib.nixosSystem` Function {#simple-introduction-to-nixpkgs-lib-nixos-system}
By default, a flake will look for a `flake.nix` file in the root directory of each of its dependencies and execute its `outputs` function.
The attribute set returned by this function is then passed as a parameter to the flake's own `outputs` function, allowing us to use the content provided by each dependency in our outputs.
In the example in this section, [nixpkgs/flake.nix] will be executed when we run `sudo nixos-rebuild switch`. We can see from its source code that its `outputs` definition includes the `lib` attribute, which is used in our example:
```nix{8-13}
{
inputs = {
# NixOS official package source, here using the nixos-23.11 branch
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
};
outputs = { self, nixpkgs, ... }@inputs: {
nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
];
};
};
}
```
The attribute set following `nixpkgs.lib.nixosSystem` is the function's parameter. We have only set two parameters here:
1. `system`: This is straightforward, it's the system architecture parameter.
2. `modules`: This is a list of modules, where the actual NixOS system configuration is defined.
The `/etc/nixos/configuration.nix` configuration file itself is a Nixpkgs Module, so it can be directly added to the `modules` list for use.
Understanding these basics is sufficient for beginners. Exploring the `nixpkgs.lib.nixosSystem` function in detail requires a grasp of the Nixpkgs module system.
Readers who have completed the [Modularizing NixOS Configuration](./modularize-the-configuration.md) section can return to [nixpkgs/flake.nix] to find the definition of `nixpkgs.lib.nixosSystem`, trace its source code, and study its implementation.
## Nixpkgs Module Structure Explained {#simple-introduction-to-nixpkgs-module-structure}
> The detailed workings of this module system will be introduced in the following [Modularizing NixOS Configuration](./modularize-the-configuration.md) section. Here, we'll just cover some basic knowledge.
You might be wondering why the `/etc/nixos/configuration.nix` configuration file adheres to the Nixpkgs Module definition and can be referenced directly within the `flake.nix`.
This is because the Nixpkgs repository contains a significant amount of NixOS implementation source code, primarily written in Nix. To manage and maintain such a large volume of Nix code and to allow users to customize various functions of their NixOS systems, a modular system for Nix code is essential.
This modular system for Nix code is also implemented within the Nixpkgs repository and is primarily used for modularizing NixOS system configurations. However, it is also widely used in other contexts, such as nix-darwin and home-manager.
Since NixOS is built on this modular system, it is only natural that its configuration files, including `/etc/nixos/configuration.nix`, are Nixpkgs Modules.
Before delving into the subsequent content, it's essential to have a basic understanding of how this module system operates.
Here's a simplified structure of a Nixpkgs Module:
```nix
{lib, config, options, pkgs, ...}:
{
# Importing other Modules
imports = [
# ...
./xxx.nix
];
for.bar.enable = true;
# Other option declarations
# ...
}
```
The definition is actually a Nix function, and it has five **automatically generated, automatically injected, and declaration-free parameters** provided by the module system:
1. `lib`: A built-in function library included with nixpkgs, offering many practical functions for operating Nix expressions.
- For more information, see <https://nixos.org/manual/nixpkgs/stable/#id-1.4>.
2. `config`: A set of all config values in the current environment, which may sometimes be used.
3. `options`: A set of all options defined in all Modules in the current environment.
4. `pkgs`: A collection containing all nixpkgs packages, along with several related utility functions.
- At the beginner stage, you can consider its default value to be `nixpkgs.legacyPackages."${system}"`, and the value of `nixpkgs.pkgs` can be customized through the `nixpkgs.pkgs` option.
5. `modulesPath`: A parameter available only in NixOS, which is a path pointing to [nixpkgs/nixos/modules](https://github.com/NixOS/nixpkgs/tree/nixos-23.11/nixos/modules).
- It is defined in [nixpkgs/nixos/lib/eval-config-minimal.nix#L43](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/lib/eval-config-minimal.nix#L43).
- It is typically used to import additional NixOS modules and can be found in most NixOS auto-generated `hardware-configuration.nix` files.
## Passing Non-default Parameters to Submodules {#pass-non-default-parameters-to-submodules}
If you need to pass other non-default parameters to submodules, you will need to use some special methods to manually specify these non-default parameters.
The Nixpkgs module system provides two ways to pass non-default parameters:
1. The `specialArgs` parameter of the `nixpkgs.lib.nixosSystem` function
2. Using the `_module.args` option in any module to pass parameters
The official documentation for these two parameters is buried deep and is vague and hard to understand. If readers are interested, I will include the links here:
1. `specialArgs`: There are scattered mentions related to it in the NixOS Manual and the Nixpkgs Manual.
1. Nixpkgs Manual: [Module System - Nixpkgs]
1. NixOS Manual: [nixpkgs/nixos-23.11/nixos/doc/manual/development/option-types.section.md#L237-L244]
1. `_module.args`: Its only official documentation is in the source code below.
1. [nixpkgs/nixos-23.11/lib/modules.nix - _module.args]
In short, `specialArgs` and `_module.args` both require an attribute set as their value, and they serve the same purpose, passing all parameters in the attribute set to all submodules. The difference between them is:
1. The `_module.args` option can be used in any module to pass parameters to each other, which is more flexible than `specialArgs`, which can only be used in the `nixpkgs.lib.nixosSystem` function.
1. `_module.args` is declared within a module, so it must be evaluated after all modules have been evaluated before it can be used. This means that if you use the parameters passed through `_module.args` in `imports = [ ... ];`, it will result in an `infinite recursion` error. In this case, you must use `specialArgs` instead.
The NixOS community generally recommends prioritizing the use of the `_module.args` option and resorting to `specialArgs` only when `_module.args` cannot be used.
Suppose you want to pass a certain dependency to a submodule for use. You can use the `specialArgs` parameter to pass the `inputs` to all submodules:
```nix{13}
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
another-input.url = "github:username/repo-name/branch-name";
};
outputs = inputs@{ self, nixpkgs, another-input, ... }: {
nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
# Set all inputs parameters as special arguments for all submodules,
# so you can directly use all dependencies in inputs in submodules
specialArgs = { inherit inputs; };
modules = [
./configuration.nix
];
};
};
}
```
Or you can achieve the same effect using the `_module.args` option:
```nix{14}
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
another-input.url = "github:username/repo-name/branch-name";
};
outputs = inputs@{ self, nixpkgs, another-input, ... }: {
nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
{
# Set all inputs parameters as special arguments for all submodules,
# so you can directly use all dependencies in inputs in submodules
_module.args = { inherit inputs; };
}
];
};
};
}
```
Choose one of the two methods above to modify your configuration, and then you can use the `inputs` parameter in `/etc/nixos/configuration.nix`. The module system will automatically match the `inputs` defined in `specialArgs` and inject it into all submodules that require this parameter:
```nix{4}
# Nix will match by name and automatically inject the inputs
# from specialArgs/_module.args into the third parameter of this function
{ config, pkgs, inputs, ... }:
{
# ...
}
```
The next section will demonstrate how to use `specialArgs`/`_module.args` to install system software from other flake sources.
## Installing System Software from Other Flake Sources {#install-system-packages-from-other-flakes}
The most common requirement for managing a system is to install software, and we have already seen in the previous section how to install packages from the official nixpkgs repository using `environment.systemPackages`. These packages all come from the official nixpkgs repository.
Now, we will learn how to install software packages from other flake sources, which is much more flexible than installing directly from nixpkgs. The main use case is to install the latest version of a software that is not yet added or updated in Nixpkgs.
Taking the Helix editor as an example, here's how to compile and install the master branch of Helix directly.
First, add the helix input data source to `flake.nix`:
```nix{6,12,18}
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
# helix editor, use the master branch
helix.url = "github:helix-editor/helix/master"; helix.url = "github:helix-editor/helix/master";
}; };
outputs = inputs@{ self, nixpkgs, ... }: { outputs = inputs@{ self, nixpkgs, ... }: {
nixosConfigurations = { nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
nixos-test = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
specialArgs = { inherit inputs; };
# Set all input parameters as specialArgs of all sub-modules
# so that we can use the `helix`(an attribute in inputs) in
# sub-modules directly.
specialArgs = inputs;
modules = [ modules = [
./configuration.nix ./configuration.nix
# This module works the same as the `specialArgs` parameter we used above
# chose one of the two methods to use
# { _module.args = { inherit inputs; };}
]; ];
}; };
}; };
};
} }
``` ```
Next, update `configuration.nix` to install `helix` from the `helix` input: Next, you can reference this flake input data source in `configuration.nix`:
```nix{3,14-15}
# Nix will automatically inject `helix` from specialArgs
# into the third parameter of this function through name matching
{ config, pkgs, helix, ... }:
```nix{3,12}
{ config, pkgs, inputs, ... }:
{ {
# Omit other configurations... # ...
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
git git
vim vim
wget wget
curl curl
# Here, the helix package is installed from the helix input data source
# Install Helix from the `helix` input inputs.helix.packages."${pkgs.system}".helix
helix.packages."${pkgs.system}".helix
]; ];
# ...
# Omit other configurations...
} }
``` ```
To deploy the changes, run `sudo nixos-rebuild switch`, this will take a while to compile the latest Helix. Make the necessary changes and deploy with `sudo nixos-rebuild switch`. The deployment will take much longer this time because Nix will compile the entire Helix program from source.
After that, you can start the Helix editor by running the `hx` command. After deployment, you can directly test and verify the installation using the `hx` command in the terminal.
> If your system's hostname is not `nixos-test`, you need to modify the name of `nixosConfigurations` in `flake.nix`, or use `--flake /etc/nixos#nixos-test` to specify the configuration name. > If you encounter any errors during deployment, you can try adding the `--show-trace -L` parameters to the `nixos-rebuild` command to get detailed error information.
> You can always try to add `--show-trace -L` to the `nixos-rebuild` command to get the detailed error message if you encounter any errors during the deployment. Additionally, if you just want to try out the latest version of Helix and decide whether to install it on your system later, there is a simpler way to do it in one command (but as mentioned earlier, compiling from source will take a long time):
Furthermore, if you merely want to experiment with the latest version of Helix before deciding whether to install it system-wide, there's a simpler way just a single command:
> Similarly, if you wish to use the latest version, compiling from source is usually unavoidable and may take some time.
```bash ```bash
nix run github:helix-editor/helix/master nix run github:helix-editor/helix/master
``` ```
We will introduce `nix run` in detail at [Usage of the New CLI](/other-usage-of-flakes/the-new-cli.md) We will go into more detail on the usage of `nix run` in the following section [Usage of the New CLI](../other-usage-of-flakes/the-new-cli.md).
## Leveraging Features from Other Flakes Packages ## Leveraging Features from Other Flakes Packages
In fact, this is the primary functionality of Flakes — a Flake can depend on other Flakes, allowing it to utilize the features they provide. It's akin to how we incorporate functionalities from other libraries when writing programs in TypeScript, Go, Rust, and other programming languages. In fact, this is the primary functionality of Flakes — a flake can depend on other flakes, allowing it to utilize the features they provide. It's akin to how we incorporate functionalities from other libraries when writing programs in TypeScript, Go, Rust, and other programming languages.
The example above, using the latest version from the official Helix Flake, illustrates this functionality. More use cases will be discussed later, and here are a few examples referenced for future mention: The example above, using the latest version from the official Helix Flake, illustrates this functionality. More use cases will be discussed later, and here are a few examples referenced for future mention:
- [Getting Started with Home Manager](./start-using-home-manager.md): This introduces the community's Home-Manager as a dependency, enabling direct utilization of the features provided by this Flake. - [Getting Started with Home Manager](./start-using-home-manager.md): This introduces the community's Home-Manager as a dependency, enabling direct utilization of the features provided by this Flake.
- [Downgrading or Upgrading Packages](./downgrade-or-upgrade-packages.md): Here, different versions of Nixpkgs are introduced as dependencies, allowing for flexible selection of packages from various versions of Nixpkgs. - [Downgrading or Upgrading Packages](./downgrade-or-upgrade-packages.md): Here, different versions of Nixpkgs are introduced as dependencies, allowing for flexible selection of packages from various versions of Nixpkgs.
[nixpkgs/flake.nix]: https://github.com/NixOS/nixpkgs/tree/nixos-23.11/flake.nix
[nixpkgs/nixos/lib/eval-config.nix]: https://github.com/NixOS/nixpkgs/tree/nixos-23.11/nixos/lib/eval-config.nix
[Module System - Nixpkgs]: https://github.com/NixOS/nixpkgs/blob/23.11/doc/module-system/module-system.chapter.md
[nixpkgs/nixos-23.11/lib/modules.nix - _module.args]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/lib/modules.nix#L122-L184
[nixpkgs/nixos-23.11/nixos/doc/manual/development/option-types.section.md#L237-L244]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-types.section.md?plain=1#L237-L244

View File

@ -35,9 +35,9 @@ Another approach is to delete `/etc/nixos` directly and specify the configuratio
sudo mv /etc/nixos /etc/nixos.bak sudo mv /etc/nixos /etc/nixos.bak
cd ~/nixos-config cd ~/nixos-config
# `--flake .#nixos-test` deploys the flake.nix located in # `--flake .#my-nixos` deploys the flake.nix located in
# the current directory, and the nixosConfiguration's name is `nixos-test` # the current directory, and the nixosConfiguration's name is `my-nixos`
sudo nixos-rebuild switch --flake .#nixos-test sudo nixos-rebuild switch --flake .#my-nixos
``` ```
Choose the method that suits you best. Afterward, system rollback becomes simple. Just switch to the previous commit and deploy it: Choose the method that suits you best. Afterward, system rollback becomes simple. Just switch to the previous commit and deploy it:
@ -47,8 +47,8 @@ cd ~/nixos-config
# Switch to the previous commit # Switch to the previous commit
git checkout HEAD^1 git checkout HEAD^1
# Deploy the flake.nix located in the current directory, # Deploy the flake.nix located in the current directory,
# with the nixosConfiguration's name `nixos-test` # with the nixosConfiguration's name `my-nixos`
sudo nixos-rebuild switch --flake .#nixos-test sudo nixos-rebuild switch --flake .#my-nixos
``` ```
More advanced Git operations are not covered here, but in general, rollback can be performed directly using Git. Only in cases of complete system crashes would you need to restart into the bootloader and boot the system from a previous historical version. More advanced Git operations are not covered here, but in general, rollback can be performed directly using Git. Only in cases of complete system crashes would you need to restart into the bootloader and boot the system from a previous historical version.

View File

@ -180,15 +180,22 @@ After adjusting the parameters, the content of `/etc/nixos/flake.nix` is as foll
description = "NixOS configuration"; description = "NixOS configuration";
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11";
home-manager.url = "github:nix-community/home-manager"; # home-manager, used for managing user configuration
home-manager.inputs.nixpkgs.follows = "nixpkgs"; home-manager = {
url = "github:nix-community/home-manager/release-23.11";
# The `follows` keyword in inputs is used for inheritance.
# Here, `inputs.nixpkgs` of home-manager is kept consistent with
# the `inputs.nixpkgs` of the current flake,
# to avoid problems caused by different versions of nixpkgs.
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = inputs@{ nixpkgs, home-manager, ... }: { outputs = inputs@{ nixpkgs, home-manager, ... }: {
nixosConfigurations = { nixosConfigurations = {
# TODO please change the hostname to your own # TODO please change the hostname to your own
nixos-test = nixpkgs.lib.nixosSystem { my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
modules = [ modules = [
./configuration.nix ./configuration.nix
@ -214,7 +221,7 @@ After adjusting the parameters, the content of `/etc/nixos/flake.nix` is as foll
Then run `sudo nixos-rebuild switch` to apply the configuration, and home-manager will be installed automatically. Then run `sudo nixos-rebuild switch` to apply the configuration, and home-manager will be installed automatically.
> If your system's hostname is not `nixos-test`, you need to modify the name of `nixosConfigurations` in `flake.nix`, or use `--flake /etc/nixos#nixos-test` to specify the configuration name. > If your system's hostname is not `my-nixos`, you need to modify the name of `nixosConfigurations` in `flake.nix`, or use `--flake /etc/nixos#my-nixos` to specify the configuration name.
After the installation, all user-level packages and configuration can be managed through `/etc/nixos/home.nix`. When running `sudo nixos-rebuild switch`, the configuration of home-manager will be applied automatically. (**It's not necessary to run `home-manager switch` manually**!) After the installation, all user-level packages and configuration can be managed through `/etc/nixos/home.nix`. When running `sudo nixos-rebuild switch`, the configuration of home-manager will be applied automatically. (**It's not necessary to run `home-manager switch` manually**!)

View File

@ -76,7 +76,7 @@ One example of importing the above configuration as a NixOS module is as follows
outputs = inputs@{ nixpkgs, ... }: { outputs = inputs@{ nixpkgs, ... }: {
nixosConfigurations = { nixosConfigurations = {
nixos-test = nixpkgs.lib.nixosSystem { my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
modules = [ modules = [
./configuration.nix ./configuration.nix

View File

@ -236,22 +236,26 @@ The Nixpkgs module system provides a series of functions similar to `lib.mkIf` f
1. `lib.mkIf`: Already introduced. 1. `lib.mkIf`: Already introduced.
2. `lib.mkOverride` / `lib.mkDefault` / `lib.mkForce`: Previously discussed in [Modularizing NixOS Configuration](../nixos-with-flakes/modularize-the-configuration.md). 2. `lib.mkOverride` / `lib.mkDefault` / `lib.mkForce`: Previously discussed in [Modularizing NixOS Configuration](../nixos-with-flakes/modularize-the-configuration.md).
3. `lib.mkOrder`, `lib.mkBefore`, and `lib.mkAfter`: As mentioned above. 3. `lib.mkOrder`, `lib.mkBefore`, and `lib.mkAfter`: As mentioned above.
4. Check [Option Definitions - NixOS][Option Definitions - NixOS] for more functions related to option assignment (definition). 4. Check [Option Definitions - NixOS] for more functions related to option assignment (definition).
## Option Declaration and Type Checking ## Option Declaration and Type Checking
While assignment is the most commonly used feature of the module system, if you need to customize some `options`, you also need to delve into option declaration and type checking. I find this part relatively straightforward; it's much simpler than assignment, and you can understand the basics by directly referring to the official documentation. I won't go into detail here. While assignment is the most commonly used feature of the module system, if you need to customize some `options`, you also need to delve into option declaration and type checking. I find this part relatively straightforward; it's much simpler than assignment, and you can understand the basics by directly referring to the official documentation. I won't go into detail here.
- [Option Declarations - NixOS][Option Declarations - NixOS] - [Option Declarations - NixOS]
- [Options Types - NixOS][Options Types - NixOS] - [Options Types - NixOS]
## Passing Non-default Parameters to the Module System
We have already introduced how to use `specialArgs` and `_module.args` to pass additional parameters to other Modules functions in [Managing Your NixOS with Flakes](../nixos-with-flakes/nixos-with-flakes-enabled.md#pass-non-default-parameters-to-submodules). No further elaboration is needed here.
## References ## References
- [Best resources for learning about the NixOS module system? - Discourse](https://discourse.nixos.org/t/best-resources-for-learning-about-the-nixos-module-system/1177/4) - [Best resources for learning about the NixOS module system? - Discourse](https://discourse.nixos.org/t/best-resources-for-learning-about-the-nixos-module-system/1177/4)
- [NixOS modules - NixOS Wiki](https://nixos.wiki/wiki/NixOS_modules) - [NixOS modules - NixOS Wiki](https://nixos.wiki/wiki/NixOS_modules)
- [NixOS: config argument - NixOS Wiki](https://nixos.wiki/wiki/NixOS:config_argument) - [NixOS: config argument - NixOS Wiki](https://nixos.wiki/wiki/NixOS:config_argument)
- [Module System - Nixpkgs][Module System - Nixpkgs] - [Module System - Nixpkgs]
- [Writing NixOS Modules - Nixpkgs][Writing NixOS Modules - Nixpkgs] - [Writing NixOS Modules - Nixpkgs]
[lib/modules.nix]: https://github.com/NixOS/nixpkgs/blob/23.11/lib/modules.nix#L995 [lib/modules.nix]: https://github.com/NixOS/nixpkgs/blob/23.11/lib/modules.nix#L995

View File

@ -73,8 +73,8 @@ ssh-add ~/.ssh/your-private-key
}; };
}; };
# 主机名 = "nixos-test" # 主机名 = "my-nixos"
"nixos-test" = { name, nodes, ... }: { "my-nixos" = { name, nodes, ... }: {
# 与远程部署相关的参数 # 与远程部署相关的参数
deployment.targetHost = "192.168.5.42"; # 远程主机的 IP 地址 deployment.targetHost = "192.168.5.42"; # 远程主机的 IP 地址
deployment.targetUser = "root"; # 远程主机的用户名 deployment.targetUser = "root"; # 远程主机的用户名
@ -102,14 +102,14 @@ nix run nixpkgs#colmena apply
`nixos-rebuild` 进行远程部署的好处在于,它的工作方式与部署到本地主机完全相同,只需要多传几个参数,指定下远程主机的 IP 地址、用户名等信息即可。 `nixos-rebuild` 进行远程部署的好处在于,它的工作方式与部署到本地主机完全相同,只需要多传几个参数,指定下远程主机的 IP 地址、用户名等信息即可。
例如,使用以下命令将 flake 中的 `nixosConfigurations.nixos-test` 这份配置部署到远程主机: 例如,使用以下命令将 flake 中的 `nixosConfigurations.my-nixos` 这份配置部署到远程主机:
```bash ```bash
nixos-rebuild switch --flake .#nixos-text \ nixos-rebuild switch --flake .#nixos-text \
--target-host root@192.168.4.1 --build-host localhost --verbose --target-host root@192.168.4.1 --build-host localhost --verbose
``` ```
上述命令将会构建并部署 nixos-test 的配置到 IP 为 `192.168.4.1` 的服务器,系统构建过程将在本机执行。 上述命令将会构建并部署 my-nixos 的配置到 IP 为 `192.168.4.1` 的服务器,系统构建过程将在本机执行。
如果你希望在远程主机上构建系统,只需要将 `--build-host localhost` 替换为 `--build-host root@192.168.4.1` 如果你希望在远程主机上构建系统,只需要将 `--build-host localhost` 替换为 `--build-host root@192.168.4.1`
@ -132,6 +132,6 @@ Host aquamarine
然后就可以直接使用主机别名进行部署了: 然后就可以直接使用主机别名进行部署了:
```bash ```bash
nixos-rebuild switch --flake .#nixos-test --target-host root@aquamarine --build-host root@aquamarine --verbose nixos-rebuild switch --flake .#my-nixos --target-host root@aquamarine --build-host root@aquamarine --verbose
``` ```

View File

@ -144,7 +144,7 @@ sudo nixos-rebuild switch --option substituters "https://nix-community.cachix.or
选择上述三种方案的任一一种进行配置并部署,部署成功之后,后续所有的包都会优先从国内镜像源查找缓存。 选择上述三种方案的任一一种进行配置并部署,部署成功之后,后续所有的包都会优先从国内镜像源查找缓存。
> 如果你的系统 Hostname 不是 `nixos-test`,你需要在 `flake.nix` 中修改 `nixosConfigurations` 的名称,或者使用 `--flake /etc/nixos#nixos-test` 来指定配置名称。 > 如果你的系统 Hostname 不是 `my-nixos`,你需要在 `flake.nix` 中修改 `nixosConfigurations` 的名称,或者使用 `--flake /etc/nixos#my-nixos` 来指定配置名称。
### Nix options 参数的 `extra-` 前缀 ### Nix options 参数的 `extra-` 前缀

View File

@ -30,7 +30,7 @@
... ...
}: { }: {
nixosConfigurations = { nixosConfigurations = {
nixos-test = nixpkgs.lib.nixosSystem rec { my-nixos = nixpkgs.lib.nixosSystem rec {
system = "x86_64-linux"; system = "x86_64-linux";
# 核心参数是这个,将非默认的 nixpkgs 数据源传到其他 modules 中 # 核心参数是这个,将非默认的 nixpkgs 数据源传到其他 modules 中
@ -52,7 +52,7 @@
}; };
}; };
modules = [ modules = [
./hosts/nixos-test ./hosts/my-nixos
# 省略其他模块配置... # 省略其他模块配置...
]; ];

View File

@ -14,7 +14,7 @@ $ tree
下面分别说明下这四个文件的功能: 下面分别说明下这四个文件的功能:
- `flake.lock`: 自动生成的版本锁文件,它记录了整个 flake 所有输入的数据源、hash 值、版本号,确保系统可复现。 - `flake.lock`: 自动生成的版本锁文件,它记录了整个 flake 所有输入的数据源、hash 值、版本号,确保系统可复现。
- `flake.nix`: 入口文件,执行 `sudo nixos-rebuild switch` 时会识别并部署它。 - `flake.nix`: flake 的入口文件,执行 `sudo nixos-rebuild switch` 时会识别并部署它。
- `configuration.nix`: 在 flake.nix 中被作为系统模块导入,目前所有系统级别的配置都写在此文件中。 - `configuration.nix`: 在 flake.nix 中被作为系统模块导入,目前所有系统级别的配置都写在此文件中。
- 此配置文件中的所有配置项,参见官方文档 [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration) - 此配置文件中的所有配置项,参见官方文档 [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration)
- `home.nix`: 在 flake.nix 中被 home-manager 作为 ryan 用户的配置导入,也就是说它包含了 ryan 这个用户的所有 Home Manager 配置,负责管理其 Home 文件夹。 - `home.nix`: 在 flake.nix 中被 home-manager 作为 ryan 用户的配置导入,也就是说它包含了 ryan 这个用户的所有 Home Manager 配置,负责管理其 Home 文件夹。
@ -80,7 +80,7 @@ $ tree
│ ├── msi-rtx4090 # PC 主机的配置 │ ├── msi-rtx4090 # PC 主机的配置
│ │ ├── default.nix # 这就是之前的 configuration.nix不过大部分内容都拆出到 modules 了 │ │ ├── default.nix # 这就是之前的 configuration.nix不过大部分内容都拆出到 modules 了
│ │ └── hardware-configuration.nix # 与系统硬件相关的配置,安装 nixos 时自动生成的 │ │ └── hardware-configuration.nix # 与系统硬件相关的配置,安装 nixos 时自动生成的
│ └── nixos-test # 测试用的虚拟机配置 │ └── my-nixos # 测试用的虚拟机配置
│ ├── default.nix │ ├── default.nix
│ └── hardware-configuration.nix │ └── hardware-configuration.nix
├── modules # 从 configuration.nix 中拆分出的一些通用配置 ├── modules # 从 configuration.nix 中拆分出的一些通用配置
@ -197,7 +197,7 @@ Nix Flakes 对目录结构没有任何要求,你可以参考上面的例子,
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
outputs = {nixpkgs, ...}: { outputs = {nixpkgs, ...}: {
nixosConfigurations = { nixosConfigurations = {
"nixos-test" = nixpkgs.lib.nixosSystem { "my-nixos" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
modules = [ modules = [
@ -241,7 +241,7 @@ Nix Flakes 对目录结构没有任何要求,你可以参考上面的例子,
```bash ```bash
# 示例一:多行字符串合并 # 示例一:多行字符串合并
echo $(nix eval .#nixosConfigurations.nixos-test.config.programs.bash.shellInit) echo $(nix eval .#nixosConfigurations.my-nixos.config.programs.bash.shellInit)
trace: warning: system.stateVersion is not set, defaulting to 23.11. Read why this matters on https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersio trace: warning: system.stateVersion is not set, defaulting to 23.11. Read why this matters on https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersio
n. n.
"echo 'insert before default' "echo 'insert before default'
@ -258,13 +258,13 @@ echo 'insert after default'
" "
# 示例二:单行字符串合并 # 示例二:单行字符串合并
echo $(nix eval .#nixosConfigurations.nixos-test.config.programs.zsh.shellInit) echo $(nix eval .#nixosConfigurations.my-nixos.config.programs.zsh.shellInit)
"echo 'insert before default'; "echo 'insert before default';
echo 'this is default'; echo 'this is default';
echo 'insert after default';" echo 'insert after default';"
# 示例三:列表合并 # 示例三:列表合并
nix eval .#nixosConfigurations.nixos-test.config.nix.settings.substituters nix eval .#nixosConfigurations.my-nixos.config.nix.settings.substituters
[ "https://nix-community.cachix.org" "https://nix-community.cachix.org" "https://cache.nixos.org/" "https://ryan4yin.cachix.org" ] [ "https://nix-community.cachix.org" "https://nix-community.cachix.org" "https://cache.nixos.org/" "https://ryan4yin.cachix.org" ]
``` ```

View File

@ -2,14 +2,11 @@
## 启用 NixOS 的 Flakes 支持 {#enable-nix-flakes} ## 启用 NixOS 的 Flakes 支持 {#enable-nix-flakes}
与 NixOS 默认的配置方式相比,Nix Flakes 提供了更好的可复现性,同时它清晰的包结构定义原生支持了以其他 Git 仓库为依赖,便于代码分享,因此更建议使用 Nix Flakes 来管理系统配置。 与 NixOS 当前默认的配置方式相比Flakes 提供了更好的可复现性,同时它清晰的包结构定义原生支持了以其他 Git 仓库为依赖,便于代码分享,因此本书更建议使用 Flakes 来管理系统配置。
但是目前 Nix Flakes 作为一个实验性的功能,仍未被默认启用。所以我们需要手动启用它,修改 `/etc/nixos/configuration.nix` 文件,在函数块中启用 flakes 与 nix-command 功能 目前 Flakes 作为一个实验特性,仍未被默认启用,我们需要手动修改 `/etc/nixos/configuration.nix` 文件,启用 Flakes 特性以及配套的船新 nix 命令行工具
```nix{15,18-19} ```nix{12,15}
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running nixos-help).
{ config, pkgs, ... }: { config, pkgs, ... }:
{ {
@ -18,13 +15,13 @@
./hardware-configuration.nix ./hardware-configuration.nix
]; ];
# 省略掉前面的配置...... # ......
# 启用 Nix Flakes 功能,以及配套的新 nix-command 命令行工具 # 启用 Flakes 特性以及配套的船新 nix 命令行工具
nix.settings.experimental-features = [ "nix-command" "flakes" ]; nix.settings.experimental-features = [ "nix-command" "flakes" ];
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
git # Nix Flakes 通过 git 命令从数据源拉取依赖,所以必须先安装好 git # Flakes 通过 git 命令拉取其依赖项,所以必须先安装好 git
git
vim vim
wget wget
curl curl
@ -32,17 +29,17 @@
# 将默认编辑器设置为 vim # 将默认编辑器设置为 vim
environment.variables.EDITOR = "vim"; environment.variables.EDITOR = "vim";
# 省略其他配置...... # ......
} }
``` ```
然后运行 `sudo nixos-rebuild switch` 应用修改后,即可使用 Nix Flakes 来管理系统配置。 然后运行 `sudo nixos-rebuild switch` 应用修改后,即可使用 Flakes 特性来管理系统配置。
额外还有个好处就是,现在你可以通过 `nix repl` 打开一个 nix 交互式环境,有兴趣的话,可以使用它复习测试一遍前面学过的所有 Nix 语法。 nix 的新命令行工具还提供了一些方便的功能,比如说你现在可以使用 `nix repl` 命令打开一个 nix 交互环境,有兴趣的话,可以使用它复习测试一遍前面学过的所有 Nix 语法。
## 将系统配置切换到 flake.nix {#switch-to-flake-nix} ## 将系统配置切换到 flake.nix {#switch-to-flake-nix}
在启用了 Nix Flakes 特性后,`sudo nixos-rebuild switch` 命令会优先读取 `/etc/nixos/flake.nix` 文件,如果找不到再尝试使用 `/etc/nixos/configuration.nix` 在启用了 Flakes 特性后,`sudo nixos-rebuild switch` 命令会优先读取 `/etc/nixos/flake.nix` 文件,如果找不到再尝试使用 `/etc/nixos/configuration.nix`
可以首先使用官方提供的模板来学习 flake 的编写,先查下有哪些模板: 可以首先使用官方提供的模板来学习 flake 的编写,先查下有哪些模板:
@ -61,138 +58,324 @@ cat flake.nix
```nix ```nix
{ {
description = "Ryan's NixOS Flake"; description = "A simple NixOS flake";
# 这是 flake.nix 的标准格式inputs 是 flake 的依赖outputs 是 flake 的输出
# inputs 中的每一项依赖都会在被拉取、构建后,作为参数传递给 outputs 函数
inputs = { inputs = {
# flake inputs 有很多种引用方式,应用最广泛的格式是:
# github:owner/name/reference
# 即 github 仓库地址 + branch/commit-id/tag
# NixOS 官方软件源,这里使用 nixos-23.11 分支 # NixOS 官方软件源,这里使用 nixos-23.11 分支
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
# home-manager用于管理用户配置
home-manager = {
url = "github:nix-community/home-manager/release-23.11";
# `follows` 是 inputs 中的继承语法
# 这里使 sops-nix 的 `inputs.nixpkgs` 与当前 flake 的
# `inputs.nixpkgs` 保持一致,避免依赖的 nixpkgs 版本不一致导致问题
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
# outputs 即 flake 的所有输出,其中的 nixosConfigurations 即 NixOS 系统配置
# flake 有很多用途,也可以有很多不同的 outputsnixosConfigurations 只是其中一种
#
# outputs 是一个函数,它的参数都在 inputs 中定义,可以通过 inputs 中定义的
# 名称来引用。
# 比如这里的输入参数 `nixpkgs`,就是上面 inputs 中的 `nixpkgs`
# 不过 self 是个例外,这个特殊参数指向 outputs 自身(自引用),以及 flake 根目录
# 这里的 @ 语法将函数的参数 attribute set 取了个别名,方便在内部使用
outputs = { self, nixpkgs, ... }@inputs: { outputs = { self, nixpkgs, ... }@inputs: {
# 名为 nixosConfigurations 的 outputs 会在执行 # 因此请将下面的 my-nixos 替换成你的主机名称
# `sudo nixos-rebuild switch` 时被使用 nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
# 默认情况下上述命令会使用与主机 hostname 同名的 nixosConfigurations
# 但是也可以通过 `--flake /path/to/flake/direcotry#nixos-test` 来指定
# 在 flakes 配置文件夹中执行如下命令即可部署此配置:
# sudo nixos-rebuild switch --flake .#nixos-test
# 其中 --flake 后的参数简要说明如下:
# 1. `.` 表示使用当前文件夹的 Flakes 配置,
# 2. `#` 后面的内容则是 nixosConfigurations 的名称
nixosConfigurations = {
# hostname 为 nixos-test 的主机会使用这个配置
# 这里使用了 nixpkgs.lib.nixosSystem 函数来构建配置,
# 后面的 attributes set 是它的参数,在 nixos 系统上使用如下命令即可部署此配置:
# nixos-rebuild switch --flake .#nixos-test
"nixos-test" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
# Nix 模块系统可将配置模块化,提升配置的可维护性
#
# modules 中每个参数,都是一个 Nixpkgs Module
# nixpkgs manual 中有半份介绍它的文档:
# <https://nixos.org/manual/nixpkgs/unstable/#module-system-introduction>
# 说半份是因为它的文档不全只有一些简单的介绍Nix 文档现状...
#
# Nixpkgs Module 可以是一个 attribute set
# 也可以是一个返回 attribute set 的函数,如果是函数,
# 那么它的参数就是当前的 NixOS Module 的参数.
#
# 根据 Nix Wiki 对 Nix modules 的描述,默认情况下,
# Nixpkgs Module 函数的默认参数有几个:
#
# lib: nixpkgs 自带的函数库,提供了许多操作 Nix 表达式的实用函数
# 详见 https://nixos.org/manual/nixpkgs/stable/#id-1.4
# config: 当前 flake 的所有 config 参数的集合,比较常用
# options: 当前 flake 中所有 NixOS Modules 中定义的所有参数的集合
# pkgs: 一个包含所有 nixpkgs 包的集合,它也提供了许多相关的工具函数
# 入门阶段可以认为它的默认值为 `nixpkgs.legacyPackages."${system}"`
# 可通过 `nixpkgs.pkgs` 这个 option 来自定义 pkgs 的值
# modulesPath: 默认 nixpkgs 的内置 Modules 文件夹路径,
# 常用于从 nixpkgs 中导入一些额外的模块
# 这个参数通常都用不到,我只在制作 iso 镜像时用到过
#
# 上述默认参数都由 Nixpkgs 自动生成。而如果你需要将其他非默认参数传递到
# 子模块,就得使用 specialArgs 手动设定这些参数,
# 你可以取消注释如下这行来启用该参数:
#
# specialArgs = {...}; # 将 inputs 中的参数传入所有子模块
modules = [ modules = [
# 这里导入之前我们使用的 configuration.nix这样旧的配置文件仍然能生效 # 这里导入之前我们使用的 configuration.nix这样旧的配置文件仍然能生效
# 注: configuration.nix 本身也是一个 Nixpkgs Module因此可以直接在这里导入
./configuration.nix ./configuration.nix
]; ];
}; };
}; };
};
} }
``` ```
这里我们定义了一个名为 `nixos-test` 的系统,它的配置文件为 `./configuration.nix`,这个文件就是我们之前的配置文件,这样我们仍然可以沿用旧的配置。 这里我们定义了一个名为 `my-nixos` 的系统,它的配置文件为 `/etc/nixos/` 文件夹下的 `./configuration.nix`,也就是说我们仍然沿用了旧的配置。
现在执行 `sudo nixos-rebuild switch --flake /etc/nixos#nixos-test` 应用配置,系统应该没有任何变化,因为我们仅仅是切换到了 Nix Flakes配置内容与之前还是一致的。 现在执行 `sudo nixos-rebuild switch` 应用配置,系统应该没有任何变化,因为我们仅仅是切换到了 Nix Flakes配置内容与之前还是一致的。
上述代码的注释已经非常详细了,这里再着重说明几点: 切换完毕后,我们就可以通过 Flakes 特性来管理系统了。
1. `lib` `pkgs` `config` 等默认参数都由 Nixpkgs 自动生成,并可被自动注入到子模块,无需在此处额外声明。 目前我们的 flake 包含这几个文件:
1. `specialArgs = {...};` 这里省略了 attribute set 的内容,其中的内容会被通过名称匹配的方式自动注入到子模块中。
1. 常见用法比如直接写 `specialArgs = inputs;`,这样所有 inputs 中的 flake 数据源就都可以在子模块中使用了。
2. 如果你不希望把默认参数与 `inputs` 中的数据源混合到一起,可以改用 `specialArgs = {inherit inputs;};`(即 `specialArgs = {inputs = inputs;};`.
## 通过 Flakes 来管理系统软件 {#manage-system-software-with-flakes} - `/etc/nixos/flake.nix`: flake 的入口文件,执行 `sudo nixos-rebuild switch` 时会识别并部署它。
- `/etc/nixos/flake.lock`: 自动生成的版本锁文件,它记录了整个 flake 所有输入的数据源、hash 值、版本号,确保系统可复现。
- `/etc/nixos/configuration.nix`: 这是我们之前的配置文件,在 `flake.nix` 中被作为模块导入,目前所有系统配置都写在此文件中。
- `/etc/nixos/hardware-configuration.nix`: 这是系统硬件配置文件,由 NixOS 生成,描述了系统的硬件信息
切换完毕后,我们就可以通过 Flakes 来管理系统了。管系统最常见的需求就是装软件,我们在前面已经见识过如何通过 `environment.systemPackages` 来安装 `pkgs` 中的包,这些包都来自官方的 nixpkgs 仓库。 到这里为止, `/etc/nixos/flake.nix` 仅仅是 `/etc/nixos/configuration.nix` 的一个 thin wrapper它自身并没有提供任何新的功能也没有引入任何破坏性的变更。
在本书后面的内容中,我们会逐渐看到这样一个 wrapper 带来了哪些好处。
现在我们学习下如何通过 Flakes 安装其他来源的软件包,这比直接安装 nixpkgs 要灵活很多,最主要的用途是用来使用 Nixpkgs 中还未添加的某个包的新版本。 > 注意:**本书描述的配置管理方式并非「Everything in a single file」更推荐将配置内容分门别类地存放到不同的 nix 文件中**,然后在 `flake.nix``modules` 参数列表中引入这些配置文件,并通过 Git 管理它们。
> 这样做的好处是,可以更好地组织配置文件,提高配置的可维护性。后面的 [模块化 NixOS 配置](./modularize-the-configuration.md) 一节将会详细介绍如何模块化你的 NixOS 配置,[其他实用技巧 - 使用 Git 管理 NixOS 配置](./other-useful-tips.md) 将会介绍几种使用 Git 管理 NixOS 配置的最佳实践。
以 [helix](https://github.com/helix-editor/helix) 编辑器为例,我们首先需要在 `flake.nix` 中添加 helix 这个 inputs 数据源: ## `flake.nix` 配置详解 {#flake-nix-configuration-explained}
```nix{10,20} 上面我们创建了一个 `flake.nix` 文件并通过它来管理系统配置,
但你对它的结构还是一头雾水,
下面我们来详细解释一下这个文件的内容。
### 1. flake inputs
首先看看其中的 `inputs` 属性,它是一个 attribute set其中定义了这个 flake 的所有依赖项,这些依赖项会在被拉取后,作为参数传递给 `outputs` 函数:
```nix{2-5,7}
{ {
description = "NixOS configuration of Ryan Yin"; inputs = {
# NixOS 官方软件源,这里使用 nixos-23.11 分支
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
};
# ...... outputs = { self, nixpkgs, ... }@inputs: {
# 省略掉前面的配置......
};
}
```
`inputs` 中的每一项依赖有许多类型与定义方式,可以是另一个 flake也可以是一个普通的 Git 仓库,又或者一个本地路径。
[Flakes 的其他玩法 - Flake 的 inputs](../other-usage-of-flakes/inputs.md) 中详细介绍了常见的依赖项类型与定义方式。
这里我们只定义了 `nixpkgs` 这一个依赖项,使用的是 flake 中最常见的引用方式,即 `github:owner/name/reference`,这里的 `reference` 可以是分支名、commit-id 或 tag。
`nixpkgs``inputs` 中被定义后,就可以在后面的 `outputs` 函数的参数中使用此依赖项中的内容了,我们的示例中正是这么干的。
### 2. flake outputs
再来看看 `outputs`,它是一个以 `inputs` 中的依赖项为参数的函数,函数的返回值是一个 attribute set这个返回的 attribute set 即为该 flake 的构建结果:
```nix{10-18}
{
description = "A simple NixOS flake";
inputs = { inputs = {
# NixOS 官方软件源,这里使用 nixos-23.11 分支
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
};
# 这里的 `self` 是个特殊参数,它指向 `outputs` 函数返回的 attribute set 自身,即自引用
outputs = { self, nixpkgs, ... }@inputs: {
# hostname 为 my-nixos 的主机会使用这个配置
nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
];
};
};
}
```
flake 有很多的用途,也可以有很多不同类型的 outputs[Flake 的 outputs](../other-usage-of-flakes/outputs.md) 一节有更详细的介绍。
这里我们只用到了 `nixosConfigurations` 这一类型的 outputs它用于配置 NixOS 系统。
在我们运行 `sudo nixos-rebuild switch` 命令时,它会从 `/etc/nixos/flake.nix``outputs` 函数返回值中查找 `nixosConfigurations.my-nixos` (其中的 `my-nixos` 将会是你当前系统的 hostname这一属性并使用其中的定义来配置你的 NixOS 系统。
实际我们也可以自定义 flake 的位置与 NixOS 配置的名称,而不是使用默认值。
只需要在 `nixos-rebuild` 命令后面添加 `--flake` 参数即可,一个例子:
```nix
sudo nixos-rebuild switch --flake /path/to/your/flake#your-hostname
```
上述命令中的 `--flake /path/to/your/flake#your-hostname` 参数简要说明如下:
1. `/path/to/your/flake` 为目标 flake 的位置,默认会使用 `/etc/nixos/` 这个路径。
2. `#` 是一个分隔符,其后的 `your-hostname` 则是 NixOS 配置的名称。`nixos-rebuild` 默认会以你当前系统的 hostname 为配置名称进行查找。
你甚至能直接引用一个远程的 GitHub 仓库作为你的 flake 来源,示例如下:
```nix
sudo nixos-rebuild switch --flake github:owner/repo#your-hostname
```
### 3. `nixpkgs.lib.nixosSystem` 函数的简单介绍 {#simple-introduction-to-nixpkgs-lib-nixos-system}
默认情况下flake 会在其每个依赖项的根目录下寻找 `flake.nix` 文件并执行它的 `outputs` 函数,并将该函数返回的 attribute set 作为参数传递给它自身的 `outputs` 函数,这样我们就能在 outputs 中使用各依赖项提供的内容了。
在我们这一节的例子中,[nixpkgs/flake.nix] 会在我们执行 `sudo nixos-rebuild swtich` 时被执行,我们能从其源码中看到它 outputs 的定义中有 `lib` 这个属性,我们的例子中就使用了 `lib` 属性中的 `nixosSystem` 这个函数:
```nix{8-13}
{
inputs = {
# NixOS 官方软件源,这里使用 nixos-23.11 分支
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
};
outputs = { self, nixpkgs, ... }@inputs: {
nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
];
};
};
}
```
`nixpkgs.lib.nixosSystem` 后面跟的 attribute set 就是该函数的参数,我们这里只设置了两个参数:
1. `system`: 这个很好懂,就是系统架构参数。
2. `modules`: 此函数是一个 modules 的列表NixOS 的实际系统配置都定义在这些 modules 中。
`/etc/nixos/configuration.nix` 这个配置文件本身就是一个 Nixpkgs Module因此可以直接将其添加到 `modules` 列表中使用。
新手阶段了解这些就足够了,探究 `nixpkgs.lib.nixosSystem` 函数的具体实现需要对 Nixpkgs 的模块系统有一定的了解。
读者可以在学习了 [模块化 NixOS 配置](./modularize-the-configuration.md) 一节后,再回过头来从 [nixpkgs/flake.nix] 中找到 `nixpkgs.lib.nixosSystem` 的定义,跟踪它的源码,研究其实现方式。
## Nixpkgs Module 结构的简单介绍 {#simple-introduction-to-nixpkgs-module-structure}
> 在后面的 [模块化 NixOS 配置](./modularize-the-configuration.md) 一节中会详细介绍这套模块系统的工作方式,这里只介绍些基础知识。
为什么 `/etc/nixos/configuration.nix` 这个配置文件会符合 Nixpkgs Module 定义,从而能直接在 `flake.nix` 中引用它呢?
可能会有读者觉得这有点出乎意料。
这实际是因为 Nixpkgs 中包含了大量 NixOS 的实现源码,这些源码大都使用 Nix 语言编写。
为了编写维护如此多的 Nix 代码,并且使用户能灵活地自定义其 NixOS 系统的各项功能,就必须要有一套 Nix 代码的模块化系统。
这套 Nix 代码的模块系统的实现也同样在 Nixpkgs 仓库中,它主要被用于 NixOS 系统配置的模块化,但也有其他的应用,比如 nix-darwin 跟 home-manager 都大量使用了这套模块系统。
既然 NixOS 是基于这套模块系统构建的,那它的配置文件(包括 `/etc/nixos/configuration.nix`)是一个 Nixpkgs Module也就显得非常自然了。
在学习后面的内容之前,我们需要先简单了解下这套模块系统的工作方式。
一个简化的 Nixpkgs Module 结构如下:
```nix
{lib, config, options, pkgs, ...}:
{
# 导入其他 Modules
imports = [
# ...... # ......
# ./xxx.nix
];
for.bar.enable = true;
# other options declarations
# ...
}
```
可以看到它的定义实际是一个 Nix 函数,该函数有 5 个**由模块系统自动生成、自动注入、无需额外声明的参数**
1. `lib`: **nixpkgs 自带的函数库,提供了许多操作 Nix 表达式的实用函数**
- 详见 <https://nixos.org/manual/nixpkgs/stable/#id-1.4>
2. `config`: 当前环境中所有 config 值的集合,有时候会用到
3. `options`: 当前环境中所有 Modules 中定义的所有 options 的集合
4. `pkgs`: **一个包含所有 nixpkgs 包的集合,它也提供了许多相关的工具函数**
- 入门阶段可以认为它的默认值为 `nixpkgs.legacyPackages."${system}"`,可通过 `nixpkgs.pkgs` 这个 option 来自定义 pkgs 的值
5. `modulesPath`: 一个只在 NixOS 中可用的参数,是一个 Path指向 [nixpkgs/nixos/modules](https://github.com/NixOS/nixpkgs/tree/nixos-23.11/nixos/modules)
- 它在 [nixpkgs/nixos/lib/eval-config-minimal.nix#L43](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/lib/eval-config-minimal.nix#L43) 中被定义
- 通常被用于导入一些额外的 NixOS 模块NixOS 自动生成的 `hardware-configuration.nix` 中基本都能看到它
## 传递非默认参数到模块系统中 {#pass-non-default-parameters-to-submodules}
而如果你需要将其他非默认参数传递到子模块,就需要使用一些特殊手段手动指定这些非默认参数。
Nixpkgs 的模块系统提供了两种方式来传递非默认参数:
1. `nixpkgs.lib.nixosSystem` 函数的 `specialArgs` 参数
1. 在任一 Module 中使用 `_module.args` 这个 option 来传递参数
这两个参数的官方文档藏得很深,而且语焉不详、晦涩难懂。读者感兴趣的话我把链接放在这里:
1. `specialArgs`: NixOS Manual 跟 Nixpkgs Manual 中分别有与它有关的只言片语
1. Nixpkgs Manual: [Module System - Nixpkgs]
1. NixOS Manual: [nixpkgs/nixos-23.11/nixos/doc/manual/development/option-types.section.md#L237-L244]
1. `_module.args`: 它唯一的官方文档在如下这份源码中
1. [nixpkgs/nixos-23.11/lib/modules.nix - _module.args]
总之,`specialArgs` 与 `_module.args` 需要的值都是一个 attribute set它们的功能也相同都是将其 attribute set 中的所有参数传递到所有子模块中。
这两者的区别在于:
1. 在任何 Module 中都能使用 `_module.args` 这个 option通过它互相传递参数这要比只能在 `nixpkgs.lib.nixosSystem` 函数中使用的 `specialArgs` 更灵活。
1. `_module.args` 是在 Module 中声明使用的,因此必须在所有 Modules 都已经被求值后,才能使用它。这导致如果你在 `imports = [ ... ];` 中使用 `_module.args` 传递的参数,会报错 `infinite recursion`,这种场景下你必须改用 `specialArgs` 才行。
NixOS 社区比较推荐优先使用 `_module.args` 这个 options仅在无法使用 `_module.args` 时才改用 `specialArgs`
假设你想将某个依赖项传递到子模块中使用,可以使用 `specialArgs` 参数将 `inputs` 传递到所有子模块中:
```nix{13}
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
another-input.url = "github:username/repo-name/branch-name";
};
outputs = inputs@{ self, nixpkgs, another-input, ... }: {
nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
# 将所有 inputs 参数设为所有子模块的特殊参数,
# 这样就能直接在子模块中使用 inputs 中的所有依赖项了
specialArgs = { inheirt inputs;};
modules = [
./configuration.nix
];
};
};
}
```
或者使用 `_module.args` 这个 option 也能达成同样的效果:
```nix{15}
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
another-input.url = "github:username/repo-name/branch-name";
};
outputs = inputs@{ self, nixpkgs, another-input, ... }: {
nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
{
# 将所有 inputs 参数设为所有子模块的特殊参数,
# 这样就能直接在子模块中使用 inputs 中的所有依赖项了
_module.args = { inherit inputs; };
}
];
};
};
}
```
选择上述两种方式之一修改你的配置,然后在 `/etc/nixos/configuration.nix` 中就可以使用 `inputs` 这个参数了,模块系统会自动匹配到 `specialArgs` 中定义的 `inputs`,并将其注入到所有需要该参数的子模块中:
```nix{3}
# Nix 会通过名称匹配,
# 自动将 specialArgs/_module.args 中的 inputs 注入到此函数的第三个参数
{ config, pkgs, inputs, ... }:
# 然后我们就能在这下面使用 inputs 这个参数了
{
# ......
}
```
下一节将演示如何使用 `specialArgs`/`_module.args` 来从其他 flake 来源安装系统软件。
## 从其他 flake 来源安装系统软件 {#install-system-packages-from-other-flakes}
管系统最常见的需求就是装软件,我们在上一节已经见识过如何通过 `environment.systemPackages` 来安装 `pkgs` 中的包,这些包都来自官方的 nixpkgs 仓库。
现在我们学习下如何安装其他 flake 来源的软件包,这比直接从 nixpkgs 安装要灵活很多,最主要的用途是安装 Nixpkgs 中还未添加或未更新的某软件的最新版本。
以 [helix](https://github.com/helix-editor/helix) 编辑器为例,这里演示下如何直接编译安装 helix 的 master 分支。
首先在 `flake.nix` 中添加 helix 这个 inputs 数据源:
```nix{6,12,18}
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
# helix editor, use the master branch # helix editor, use the master branch
helix.url = "github:helix-editor/helix/master"; helix.url = "github:helix-editor/helix/master";
}; };
outputs = inputs@{ self, nixpkgs, ... }: { outputs = inputs@{ self, nixpkgs, ... }: {
nixosConfigurations = { nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
nixos-test = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
specialArgs = { inheirt inputs;};
# 将所有 inputs 参数设为所有子模块的特殊参数,
# 这样就能直接在子模块中使用 inputs 中的 helix 了
specialArgs = inputs;
modules = [ modules = [
./configuration.nix ./configuration.nix
# 如下 Module 与前面的 `specialArgs` 参数功能完全一致
# 选择其中一种即可
# { _module.args = { inherit inputs; };}
]; ];
};
}; };
}; };
} }
@ -200,22 +383,22 @@ cat flake.nix
接下来在 `configuration.nix` 中就能引用这个 flake input 数据源了: 接下来在 `configuration.nix` 中就能引用这个 flake input 数据源了:
```nix{3,14-15} ```nix{3,15}
# Nix 会通过名称匹配, # Nix 会通过名称匹配,
# 自动将 specialArgs 中的 helix 注入到此函数的第三个参数 # 自动将 specialArgs 中的 inputs 作为函数参数注入到此函数中
{ config, pkgs, helix, ... }: { config, pkgs, inputs, ... }:
{ {
# 省略掉前面的配置...... # 省略无关配置......
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
git # Nix Flakes 通过 git 命令从数据源拉取依赖,所以必须先安装好 git git
vim vim
wget wget
curl curl
# 这里从 helix 这个 inputs 数据源安装了 helix 程序 # 这里从 helix 这个 inputs 数据源安装了 helix 程序
helix.packages."${pkgs.system}".helix inputs.helix.packages."${pkgs.system}".helix
]; ];
# 省略其他配置...... # 省略其他配置......
@ -223,23 +406,19 @@ cat flake.nix
``` ```
改好后再 `sudo nixos-rebuild switch` 部署,就能安装好 Helix 程序了。 改好后再 `sudo nixos-rebuild switch` 部署,就能安装好 Helix 程序了。
这次部署用时会比以往长挺多,主要是 Nix 会需要使用 master 分支的源码编译整个 Helix. 这次部署用时会比以往长挺多,因为 Nix 会从源码编译整个 Helix 程序。
部署完毕后,可直接在终端使用 `hx` 命令测试验证。 部署完毕后,可直接在终端使用 `hx` 命令测试验证。
> 如果你的系统 Hostname 不是 `nixos-test`,你需要在 `flake.nix` 中修改 `nixosConfigurations` 的名称,或者使用 `--flake /etc/nixos#nixos-test` 来指定配置名称 > 如果你在部署配置时遇到了任何错误,都可以尝试在 `nixos-rebuild` 命令后面添加 `--show-trace -L` 参数来获取详细的错误信息
> 如果你在部署配置时遇到了任何错误,都可以尝试在 `nixos-rebuild` 命令后面添加 `--show-trace -L` 参数来获取详细的错误信息。举例如下: 另外,如果你只是想尝试一下 Helix 的最新版本,再决定要不要真正地将它安装到系统里,有更简单的办法,一行命令就行(但如前所述,源码编译会很费时间):
另外,如果你只是想尝试一下 Helix 的最新版本,再决定要不要真正地将它安装到系统里,有更简单的办法,一行命令就行:
> 同样,想使用最新版本的话,源码编译基本是免不了的,这会需要一些时间。
```bash ```bash
nix run github:helix-editor/helix/master nix run github:helix-editor/helix/master
``` ```
我们会在后面的 [新一代 Nix 命令行工具的使用](/zh/other-usage-of-flakes/the-new-cli.md) 中详细介绍 `nix run` 的用法。 我们会在后面的 [新一代 Nix 命令行工具的使用](../other-usage-of-flakes/the-new-cli.md) 中详细介绍 `nix run` 的用法。
## 使用其他 Flakes 包提供的功能 ## 使用其他 Flakes 包提供的功能
@ -250,3 +429,9 @@ nix run github:helix-editor/helix/master
- [Getting Started with Home Manager](./start-using-home-manager.md): 这里引入了社区的 Home-Manager 作为依赖项,从而能直接使用该 Flake 提供的功能。 - [Getting Started with Home Manager](./start-using-home-manager.md): 这里引入了社区的 Home-Manager 作为依赖项,从而能直接使用该 Flake 提供的功能。
- [Downgrading or Upgrading Packages](./downgrade-or-upgrade-packages.md): 这里引入了不同版本的 Nixpkgs 作为依赖项,从而能很灵活地选用不同版本的 Nixpkgs 中的包。 - [Downgrading or Upgrading Packages](./downgrade-or-upgrade-packages.md): 这里引入了不同版本的 Nixpkgs 作为依赖项,从而能很灵活地选用不同版本的 Nixpkgs 中的包。
[nixpkgs/flake.nix]: https://github.com/NixOS/nixpkgs/tree/nixos-23.11/flake.nix
[nixpkgs/nixos/lib/eval-config.nix]: https://github.com/NixOS/nixpkgs/tree/nixos-23.11/nixos/lib/eval-config.nix
[Module System - Nixpkgs]: https://github.com/NixOS/nixpkgs/blob/23.11/doc/module-system/module-system.chapter.md
[nixpkgs/nixos-23.11/lib/modules.nix - _module.args]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/lib/modules.nix#L122-L184
[nixpkgs/nixos-23.11/nixos/doc/manual/development/option-types.section.md#L237-L244]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-types.section.md?plain=1#L237-L244

View File

@ -34,9 +34,9 @@ sudo ln -s ~/nixos-config/ /etc/nixos
sudo mv /etc/nixos /etc/nixos.bak # 备份原来的配置 sudo mv /etc/nixos /etc/nixos.bak # 备份原来的配置
cd ~/nixos-config cd ~/nixos-config
# 通过 --flake .#nixos-test 参数指定使用当前文件夹的 flake.nix # 通过 --flake .#my-nixos 参数指定使用当前文件夹的 flake.nix
# 使用的 nixosConfiguraitons 名称为 nixos-test # 使用的 nixosConfiguraitons 名称为 my-nixos
sudo nixos-rebuild switch --flake .#nixos-test sudo nixos-rebuild switch --flake .#my-nixos
``` ```
两种方式都可以,看个人喜好。搞定之后,系统的回滚也变得非常简单,只需要切换到上一个 commit 即可: 两种方式都可以,看个人喜好。搞定之后,系统的回滚也变得非常简单,只需要切换到上一个 commit 即可:
@ -46,7 +46,7 @@ cd ~/nixos-config
# 回滚到上一个 commit # 回滚到上一个 commit
git checkout HEAD^1 git checkout HEAD^1
# 部署 # 部署
sudo nixos-rebuild switch --flake .#nixos-test sudo nixos-rebuild switch --flake .#my-nixos
``` ```
Git 的更多操作这里就不介绍了,总之一般情况下的回滚都能直接通过 Git 完成,只在系统完全崩溃的情况下,才需要通过重启进入 grub从上一个历史版本启动系统。 Git 的更多操作这里就不介绍了,总之一般情况下的回滚都能直接通过 Git 完成,只在系统完全崩溃的情况下,才需要通过重启进入 grub从上一个历史版本启动系统。

View File

@ -180,15 +180,22 @@ nix flake new example -t github:nix-community/home-manager#nixos
description = "NixOS configuration"; description = "NixOS configuration";
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11";
home-manager.url = "github:nix-community/home-manager"; # home-manager, used for managing user configuration
home-manager.inputs.nixpkgs.follows = "nixpkgs"; home-manager = {
url = "github:nix-community/home-manager/release-23.11";
# The `follows` keyword in inputs is used for inheritance.
# Here, `inputs.nixpkgs` of home-manager is kept consistent with
# the `inputs.nixpkgs` of the current flake,
# to avoid problems caused by different versions of nixpkgs.
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = inputs@{ nixpkgs, home-manager, ... }: { outputs = inputs@{ nixpkgs, home-manager, ... }: {
nixosConfigurations = { nixosConfigurations = {
# 这里的 nixos-test 替换成你的主机名称 # 这里的 my-nixos 替换成你的主机名称
nixos-test = nixpkgs.lib.nixosSystem { my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
modules = [ modules = [
./configuration.nix ./configuration.nix
@ -217,7 +224,7 @@ nix flake new example -t github:nix-community/home-manager#nixos
然后执行 `sudo nixos-rebuild switch` 应用配置,即可完成 home-manager 的安装。 然后执行 `sudo nixos-rebuild switch` 应用配置,即可完成 home-manager 的安装。
> 如果你的系统 Hostname 不是 `nixos-test`,你需要在 `flake.nix` 中修改 `nixosConfigurations` 的名称,或者使用 `--flake /etc/nixos#nixos-test` 来指定配置名称。 > 如果你的系统 Hostname 不是 `my-nixos`,你需要在 `flake.nix` 中修改 `nixosConfigurations` 的名称,或者使用 `--flake /etc/nixos#my-nixos` 来指定配置名称。
安装完成后,所有用户级别的程序、配置,都可以通过 `/etc/nixos/home.nix` 管理,并且执行 `sudo nixos-rebuild switch` 时也会自动应用 home-manager 的配置。 安装完成后,所有用户级别的程序、配置,都可以通过 `/etc/nixos/home.nix` 管理,并且执行 `sudo nixos-rebuild switch` 时也会自动应用 home-manager 的配置。

View File

@ -79,7 +79,7 @@
outputs = inputs@{ nixpkgs ... }: { outputs = inputs@{ nixpkgs ... }: {
nixosConfigurations = { nixosConfigurations = {
nixos-test = nixpkgs.lib.nixosSystem { my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
modules = [ modules = [
./configuration.nix ./configuration.nix

View File

@ -10,11 +10,11 @@
而上述 NixOS Modules 跟 Home Manager Modules 的基础,是 Nixpkgs 中实现的一套通用模块系统 [lib/modules.nix][lib/modules.nix],这套模块系统的官方文档如下(即使是对熟练使用 NixOS 的用户而言,要看懂这玩意儿也不是件容易的事... 而上述 NixOS Modules 跟 Home Manager Modules 的基础,是 Nixpkgs 中实现的一套通用模块系统 [lib/modules.nix][lib/modules.nix],这套模块系统的官方文档如下(即使是对熟练使用 NixOS 的用户而言,要看懂这玩意儿也不是件容易的事...
- [Module System - Nixpkgs][Module System - Nixpkgs] - [Module System - Nixpkgs]
因为 Nixpkgs 的模块系统文档没人写,文档中直接建议读另一份专门针对 NixOS 模块系统的编写指南,确实写得清晰一些,但也很难说它对新手有多友好: 因为 Nixpkgs 的模块系统文档没人写,文档中直接建议读另一份专门针对 NixOS 模块系统的编写指南,确实写得清晰一些,但也很难说它对新手有多友好:
- [Writing NixOS Modules - Nixpkgs][Writing NixOS Modules - Nixpkgs] - [Writing NixOS Modules - Nixpkgs]
总之,模块系统是由 Nixpkgs 实现的,并不是 Nix 包管理器的一部分,因此它的文档也不在 Nix 包管理器的文档中。 总之,模块系统是由 Nixpkgs 实现的,并不是 Nix 包管理器的一部分,因此它的文档也不在 Nix 包管理器的文档中。
另外 NixOS 与 Home Manager 都是基于 Nixpkgs 的模块系统实现的。 另外 NixOS 与 Home Manager 都是基于 Nixpkgs 的模块系统实现的。
@ -256,6 +256,10 @@ Nixpkgs 中的模块系统提供了一系列类似 `lib.mkIf` 的函数,用于
- [Option Declarations - NixOS][Option Declarations - NixOS] - [Option Declarations - NixOS][Option Declarations - NixOS]
- [Options Types - NixOS][Options Types - NixOS] - [Options Types - NixOS][Options Types - NixOS]
## 传递非默认参数到模块系统中
我们在 [使用 Flakes 来管理你的 NixOS](../nixos-with-flakes/nixos-with-flakes-enabled.md#pass-non-default-parameters-to-submodules) 中已经介绍了如何使用 `specialArgs``_module.args` 来传递额外的参数给其他 Modules 函数,这里不再赘述。
## References ## References
- [Best resources for learning about the NixOS module system? - Discourse](https://discourse.nixos.org/t/best-resources-for-learning-about-the-nixos-module-system/1177/4) - [Best resources for learning about the NixOS module system? - Discourse](https://discourse.nixos.org/t/best-resources-for-learning-about-the-nixos-module-system/1177/4)