chore: automatically collapse all lines(max width = 100) (#126)

This commit is contained in:
Ryan Yin 2024-03-16 19:29:05 +08:00 committed by GitHub
parent 9e6982f10b
commit 87a650439e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
83 changed files with 3218 additions and 1356 deletions

View file

@ -1,8 +1,9 @@
LICENSE.md
dist
dist/
pnpm-lock.yaml
flake.lock
vercel.json
cache
temp
.temp
.github/

View file

@ -1,5 +1,6 @@
# https://prettier.io/docs/en/options
semi: false
singleQuote: false
printWidth: 80
printWidth: 90
proseWrap: always # always change wrapping in markdown text
trailingComma: es5

View file

@ -2,60 +2,88 @@
# NixOS & Flakes Book :hammer_and_wrench: :heart:
Want to know NixOS & Flakes in detail? Looking for a beginner-friendly tutorial? Then you've come to the right place!
Want to know NixOS & Flakes in detail? Looking for a beginner-friendly tutorial? Then
you've come to the right place!
An unofficial and opinionated NixOS & Flakes :book: for beginners: https://nixos-and-flakes.thiscute.world/
An unofficial and opinionated NixOS & Flakes :book: for beginners:
https://nixos-and-flakes.thiscute.world/
中文版: https://nixos-and-flakes.thiscute.world/zh/
> If you're using macOS, [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter) may be a good starting point for you,
> you can learn how to use Nix with this book and take nix-darwin-kickstarter as a start point to build your own Nix configuration.
> If you're using macOS,
> [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter)
> may be a good starting point for you, you can learn how to use Nix with this book and
> take nix-darwin-kickstarter as a start point to build your own Nix configuration.
## Feedback and Discussion
Im not an expert on NixOS, and Ive only been using NixOS for less than 9 months until now(2024-02),
so there must be some misconceptions or inappropriate examples in the book.
If anyone finds anything incorrect or have any questions / suggestions, just let me know about it by open an issue or join the discussion on [GitHub Discussions](https://github.com/ryan4yin/nixos-and-flakes-book/discussions), I'm glad continue to optimize the content of this book.
Im not an expert on NixOS, and Ive only been using NixOS for less than 9 months until
now(2024-02), so there must be some misconceptions or inappropriate examples in the book.
If anyone finds anything incorrect or have any questions / suggestions, just let me know
about it by open an issue or join the discussion on
[GitHub Discussions](https://github.com/ryan4yin/nixos-and-flakes-book/discussions), I'm
glad continue to optimize the content of this book.
The reason why I wrote this little book was only because no one in the community did it for me, who was a beginner at the time, so I chose to do it myself.
Even though I knew I could make mistakes, it's much better than do nothing.
The reason why I wrote this little book was only because no one in the community did it
for me, who was a beginner at the time, so I chose to do it myself. Even though I knew I
could make mistakes, it's much better than do nothing.
My hope is that this book can help more people, enabling them to experience the joys of NixOS.
Hope you like it!
My hope is that this book can help more people, enabling them to experience the joys of
NixOS. Hope you like it!
## Introduction to Flakes
The flakes experimental feature is a major development for Nix, it introduces a policy for managing dependencies between Nix expressions, it improves reproducibility, composability and usability in the Nix ecosystem. Although it's still an experimental feature, flakes have been widely used by the Nix community.[^1]
The flakes experimental feature is a major development for Nix, it introduces a policy for
managing dependencies between Nix expressions, it improves reproducibility, composability
and usability in the Nix ecosystem. Although it's still an experimental feature, flakes
have been widely used by the Nix community.[^1]
Flakes is one of the most significant changes the nix project has ever seen.[^2]
## A Word of Caution about Flakes
The benefits of Flakes are evident, and the entire NixOS community has embraced it wholeheartedly. Currently, more than half of the users utilize Flakes[^3], providing assurance that Flakes will not be deprecated.
The benefits of Flakes are evident, and the entire NixOS community has embraced it
wholeheartedly. Currently, more than half of the users utilize Flakes[^3], providing
assurance that Flakes will not be deprecated.
:warning: However, it's important to note that **Flakes is still an experimental feature**. Some issues persist, and there is a possibility of introducing breaking changes during the stabilization process. The extent of these breaking changes remains uncertain.
:warning: However, it's important to note that **Flakes is still an experimental
feature**. Some issues persist, and there is a possibility of introducing breaking changes
during the stabilization process. The extent of these breaking changes remains uncertain.
Overall, I strongly recommend everyone to use Flakes, especially since this book revolves around NixOS and Flakes. However, it's crucial to be prepared for potential problems that may arise due to forthcoming breaking changes.
Overall, I strongly recommend everyone to use Flakes, especially since this book revolves
around NixOS and Flakes. However, it's crucial to be prepared for potential problems that
may arise due to forthcoming breaking changes.
## Contribution
> _A real community, however, exists only when its members interact in a meaningful way that deepens their understanding of each other and leads to learning._
> _A real community, however, exists only when its members interact in a meaningful way
> that deepens their understanding of each other and leads to learning._
If you find something which doesn't make sense, or something doesn't seem right, please make a pull request and please add valid and well-reasoned explanations about your changes or comments.
If you find something which doesn't make sense, or something doesn't seem right, please
make a pull request and please add valid and well-reasoned explanations about your changes
or comments.
Before adding a pull request, please see the [contributing guidelines](/.github/CONTRIBUTING.md).
Before adding a pull request, please see the
[contributing guidelines](/.github/CONTRIBUTING.md).
Thank you to [all the people](https://github.com/ryan4yin/nixos-and-flakes-book/graphs/contributors) who already contributed to this project!
Thank you to
[all the people](https://github.com/ryan4yin/nixos-and-flakes-book/graphs/contributors)
who already contributed to this project!
## References
- The cover is based on the image from anime "[The Rolling Girls](https://en.wikipedia.org/wiki/The_Rolling_Girls)"
- The cover is based on the image from anime
"[The Rolling Girls](https://en.wikipedia.org/wiki/The_Rolling_Girls)"
- The NixOS logo is from [NixOS](https://nixos.org/)
## License
[NixOS & Flakes Book](https://github.com/ryan4yin/nixos-and-flakes-book) © 2023 by Ryan Yin is licensed under [CC BY-SA 4.0](./LICENSE.md)
[NixOS & Flakes Book](https://github.com/ryan4yin/nixos-and-flakes-book) © 2023 by Ryan
Yin is licensed under [CC BY-SA 4.0](./LICENSE.md)
[^1]: [Flakes - NixOS Wiki](https://nixos.wiki/index.php?title=Flakes)
[^2]: [Flakes are such an obviously good thing](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/)
[^3]: [Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9)
[^2]:
[Flakes are such an obviously good thing](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/)
[^3]:
[Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9)

View file

@ -26,9 +26,7 @@ export default defineConfig({
return {
frontmatter: {
...pageData.frontmatter,
head: [
["script", { type: "application/ld+json" }, getJSONLD(pageData)],
],
head: [["script", { type: "application/ld+json" }, getJSONLD(pageData)]],
},
}
},
@ -42,16 +40,14 @@ export default defineConfig({
"meta",
{
name: "og:image",
content:
"https://nixos-and-flakes.thiscute.world/nixos-and-flakes-book.webp",
content: "https://nixos-and-flakes.thiscute.world/nixos-and-flakes-book.webp",
},
],
[
"meta",
{
name: "twitter:image",
content:
"https://nixos-and-flakes.thiscute.world/nixos-and-flakes-book.webp",
content: "https://nixos-and-flakes.thiscute.world/nixos-and-flakes-book.webp",
},
],
@ -101,8 +97,7 @@ export default defineConfig({
},
editLink: {
pattern:
"https://github.com/ryan4yin/nixos-and-flakes-book/edit/main/docs/:path",
pattern: "https://github.com/ryan4yin/nixos-and-flakes-book/edit/main/docs/:path",
},
socialLinks: [
@ -301,15 +296,11 @@ function themeConfigEnglish() {
},
{
text: "Advanced Topics",
items: [
{ text: "Advanced Topics", link: "/advanced-topics/index.md" },
],
items: [{ text: "Advanced Topics", link: "/advanced-topics/index.md" }],
},
{
text: "Frequently Asked Questions",
items: [
{ text: "Frequently Asked Questions", link: "/faq/index.md" },
],
items: [{ text: "Frequently Asked Questions", link: "/faq/index.md" }],
},
],
},
@ -498,9 +489,7 @@ function themeConfigChinese() {
},
{
text: "其他进阶话题",
items: [
{ text: "其他进阶话题", link: "/zh/advanced-topics/index.md" },
],
items: [{ text: "其他进阶话题", link: "/zh/advanced-topics/index.md" }],
},
{
text: "常见问题 FAQ",

View file

@ -1,47 +1,92 @@
# Advanced Topics
Once you have become familiar with NixOS, you can explore advanced topics and dive deeper into the Nix ecosystem. Here are some resources and community projects that can help you expand your knowledge:
Once you have become familiar with NixOS, you can explore advanced topics and dive deeper
into the Nix ecosystem. Here are some resources and community projects that can help you
expand your knowledge:
## Community
- [Nix Official - Community](https://nixos.org/community/): Contains information about the Nix community, forums, realtime chat, meetups, RFCs, the official team architecture, etc.
- [Nix Official - Community](https://nixos.org/community/): Contains information about the
Nix community, forums, realtime chat, meetups, RFCs, the official team architecture,
etc.
- [Nix Channel Status](https://status.nixos.org/): The build status of each Nix channel.
- [nix-community/NUR](https://github.com/nix-community/NUR): Although Nixpkgs contains a large number of packages, some packages are not included in Nixpkgs due to reasons such as review speed and licensing agreements. NUR is a decentralized Nix package repository where anyone can create their own Nix repository and add it to NUR for others to use. If you want to use a package that is not in Nixpkgs, you can try to find it here. If you want to share your own Nix package with others, you can create and share your own Nix repository according to the README of NUR.
- [nix-community/NUR](https://github.com/nix-community/NUR): Although Nixpkgs contains a
large number of packages, some packages are not included in Nixpkgs due to reasons such
as review speed and licensing agreements. NUR is a decentralized Nix package repository
where anyone can create their own Nix repository and add it to NUR for others to use. If
you want to use a package that is not in Nixpkgs, you can try to find it here. If you
want to share your own Nix package with others, you can create and share your own Nix
repository according to the README of NUR.
## Documentation and Videos
- [Eelco Dolstra - The Purely Functional Software Deployment Model - 2006](https://edolstra.github.io/pubs/phd-thesis.pdf): Eelco Dolstra's seminal PhD thesis about the Nix package manager,
- [Nix Reference Manual](https://nixos.org/manual/nix/stable/package-management/profiles.html): A comprehensive guide to the Nix package manager, covering its design and usage from the command line.
- [nixpkgs Manual](https://nixos.org/manual/nixpkgs/unstable/): The manual for nixpkgs, which introduces its parameters, explains how to use, modify, and package Nix packages.
- [NixOS Manual](https://nixos.org/manual/nixos/unstable/): A user manual for NixOS, providing configuration instructions for system-level components such as Wayland/X11 and GPU.
- [nix-pills](https://nixos.org/guides/nix-pills): "Nix Pills" is a series of guides that provide an in-depth explanation of building software packages with Nix. It offers clear and understandable explanations.
- [nixos-in-production](https://github.com/Gabriella439/nixos-in-production): This is a work-in-progress book hosted on LeanPub about introducing and maintaining NixOS in a production environment.
- [Eelco Dolstra - The Purely Functional Software Deployment Model - 2006](https://edolstra.github.io/pubs/phd-thesis.pdf):
Eelco Dolstra's seminal PhD thesis about the Nix package manager,
- [Nix Reference Manual](https://nixos.org/manual/nix/stable/package-management/profiles.html):
A comprehensive guide to the Nix package manager, covering its design and usage from the
command line.
- [nixpkgs Manual](https://nixos.org/manual/nixpkgs/unstable/): The manual for nixpkgs,
which introduces its parameters, explains how to use, modify, and package Nix packages.
- [NixOS Manual](https://nixos.org/manual/nixos/unstable/): A user manual for NixOS,
providing configuration instructions for system-level components such as Wayland/X11 and
GPU.
- [nix-pills](https://nixos.org/guides/nix-pills): "Nix Pills" is a series of guides that
provide an in-depth explanation of building software packages with Nix. It offers clear
and understandable explanations.
- [nixos-in-production](https://github.com/Gabriella439/nixos-in-production): This is a
work-in-progress book hosted on LeanPub about introducing and maintaining NixOS in a
production environment.
And there are many official videos on the [NixOS Foundation](https://www.youtube.com/@NixOS-Foundation) and [NixCon](https://www.youtube.com/@NixCon) channels on YouTube. Here are a few videos that are highly recommended:
And there are many official videos on the
[NixOS Foundation](https://www.youtube.com/@NixOS-Foundation) and
[NixCon](https://www.youtube.com/@NixCon) channels on YouTube. Here are a few videos that
are highly recommended:
- [Summer of Nix 2022 — Public Lecture Series](https://www.youtube.com/playlist?list=PLt4-_lkyRrOMWyp5G-m_d1wtTcbBaOxZk): A series of public lectures hosted by the NixOS Foundation, presented by core members of the Nix community such as Eelco Dolstra and Armijn Hemel. The content covers the development history of Nix, the history of NixOS, and the future of Nix, among other topics.
- [Summer of Nix 2023 — Nix Developer Dialogues](https://www.youtube.com/playlist?list=PLt4-_lkyRrOPcBuz_tjm6ZQb-6rJjU3cf): A series of dialogues between core members of the Nix community in 2023. The content includes the evolution and architectural challenges of Nixpkgs, exploration of Nix's module system, discussion of the Nix ecosystem, AI applications in Nixpkgs, and the application of Nix in the commercial field and open source economics.
- [Summer of Nix 2022 — Public Lecture Series](https://www.youtube.com/playlist?list=PLt4-_lkyRrOMWyp5G-m_d1wtTcbBaOxZk):
A series of public lectures hosted by the NixOS Foundation, presented by core members of
the Nix community such as Eelco Dolstra and Armijn Hemel. The content covers the
development history of Nix, the history of NixOS, and the future of Nix, among other
topics.
- [Summer of Nix 2023 — Nix Developer Dialogues](https://www.youtube.com/playlist?list=PLt4-_lkyRrOPcBuz_tjm6ZQb-6rJjU3cf):
A series of dialogues between core members of the Nix community in 2023. The content
includes the evolution and architectural challenges of Nixpkgs, exploration of Nix's
module system, discussion of the Nix ecosystem, AI applications in Nixpkgs, and the
application of Nix in the commercial field and open source economics.
## Advanced Techniques and Community Projects
Once you are comfortable with Flakes, you can explore more advanced techniques and community projects. Here are some popular ones to try out:
Once you are comfortable with Flakes, you can explore more advanced techniques and
community projects. Here are some popular ones to try out:
- [flake-parts](https://github.com/hercules-ci/flake-parts): Simplifies the writing and maintenance of configurations using the Module module system.
- [flake-utils-plus](https://github.com/gytis-ivaskevicius/flake-utils-plus): A third-party package that enhances Flake configuration and provides additional powerful features.
- [flake-parts](https://github.com/hercules-ci/flake-parts): Simplifies the writing and
maintenance of configurations using the Module module system.
- [flake-utils-plus](https://github.com/gytis-ivaskevicius/flake-utils-plus): A
third-party package that enhances Flake configuration and provides additional powerful
features.
There are many other valuable community projects worth exploring. Here are a few examples:
- [nix-output-monitor](https://github.com/maralorn/nix-output-monitor): Beautifully displays the build progress of Nix packages, with additional information such as build time and build log.
- [nix-output-monitor](https://github.com/maralorn/nix-output-monitor): Beautifully
displays the build progress of Nix packages, with additional information such as build
time and build log.
- [agenix](https://github.com/ryantm/agenix): A tool for secrets management.
- [colmena](https://github.com/zhaofengli/colmena): Tools for NixOS deployment.
- [nixos-generators](https://github.com/nix-community/nixos-generators): A tool to generate ISO/qcow2/... from NixOS configurations.
- [lanzaboote](https://github.com/nix-community/lanzaboote): Enables secure boot for NixOS.
- [impermanence](https://github.com/nix-community/impermanence): Helps make NixOS stateless and improves system reproducibility.
- [devbox](https://github.com/jetpack-io/devbox): Lightweight, repeatable dev environments without container woes, internally powered by nix, similar to earthly.
- [nixpak](https://github.com/nixpak/nixpak): A tool to sandbox all sorts of Nix-packaged applications, including graphical ones.
- [nixpacks](https://github.com/railwayapp/nixpacks): Nixpacks takes a source directory and produces an OCI compliant image that can be deployed anywhere, similar to buildpacks.
- [nixos-generators](https://github.com/nix-community/nixos-generators): A tool to
generate ISO/qcow2/... from NixOS configurations.
- [lanzaboote](https://github.com/nix-community/lanzaboote): Enables secure boot for
NixOS.
- [impermanence](https://github.com/nix-community/impermanence): Helps make NixOS
stateless and improves system reproducibility.
- [devbox](https://github.com/jetpack-io/devbox): Lightweight, repeatable dev environments
without container woes, internally powered by nix, similar to earthly.
- [nixpak](https://github.com/nixpak/nixpak): A tool to sandbox all sorts of Nix-packaged
applications, including graphical ones.
- [nixpacks](https://github.com/railwayapp/nixpacks): Nixpacks takes a source directory
and produces an OCI compliant image that can be deployed anywhere, similar to
buildpacks.
- ...
These projects offer additional functionality and tools that can enhance your NixOS experience.
These projects offer additional functionality and tools that can enhance your NixOS
experience.
For more information, see the [awesome-nix](https://github.com/nix-community/awesome-nix).

View file

@ -1,14 +1,26 @@
# Accelerating Dotfiles Debugging
When managing our Dotfiles with Home Manager, a common challenge arises each modification to our Dotfiles requires executing `sudo nixos-rebuild switch`(or `home-manager switch` if you use don't integrate home-manager into NixOS) to take effect. However, running this command recalculates the entire system state each time, even though Nix internally employs various caching mechanisms to expedite the process, it can still be cumbersome.
When managing our Dotfiles with Home Manager, a common challenge arises each
modification to our Dotfiles requires executing `sudo nixos-rebuild switch`(or
`home-manager switch` if you use don't integrate home-manager into NixOS) to take effect.
However, running this command recalculates the entire system state each time, even though
Nix internally employs various caching mechanisms to expedite the process, it can still be
cumbersome.
Take my Neovim/Emacs configurations as an example; I frequently make high-frequency modifications to them, sometimes dozens or hundreds of times a day. If each modification necessitates waiting for `nixos-rebuild` to run for several seconds, it becomes a significant time drain.
Take my Neovim/Emacs configurations as an example; I frequently make high-frequency
modifications to them, sometimes dozens or hundreds of times a day. If each modification
necessitates waiting for `nixos-rebuild` to run for several seconds, it becomes a
significant time drain.
Fortunately, with the solution outlined in [Simplifying NixOS Commands using Justfile](./simplify-nixos-related-commands.md), we can expedite testing and verification of frequently modified Dotfiles by adding specific configurations to the `Justfile`.
Fortunately, with the solution outlined in
[Simplifying NixOS Commands using Justfile](./simplify-nixos-related-commands.md), we can
expedite testing and verification of frequently modified Dotfiles by adding specific
configurations to the `Justfile`.
For instance, I've added the following content to my Justfile:
> The latest Justfile I'm using: [ryan4yin/nix-config/Justfile](https://github.com/ryan4yin/nix-config/blob/main/Justfile)
> The latest Justfile I'm using:
> [ryan4yin/nix-config/Justfile](https://github.com/ryan4yin/nix-config/blob/main/Justfile)
```Makefile
###############################################################
@ -23,6 +35,11 @@ nvim-test: nvim-clean
rsync -avz --copy-links --chmod=D2755,F744 home/base/desktop/editors/neovim/astronvim_user/ ${HOME}/.config/astronvim/lua/user
```
Now, when I need to quickly test my Neovim configuration after making changes, I simply run `just nvim-test`. Once testing is complete, I execute `just nvim-clean`, followed by redeploying the configuration using `nixos-rebuild`. This allows for swift testing and seamless restoration of the configuration.
Now, when I need to quickly test my Neovim configuration after making changes, I simply
run `just nvim-test`. Once testing is complete, I execute `just nvim-clean`, followed by
redeploying the configuration using `nixos-rebuild`. This allows for swift testing and
seamless restoration of the configuration.
This method is effective under the condition that your Dotfiles content is not generated by Nix. For instance, my Emacs/Neovim configurations are native and are linked to the appropriate locations solely through Nix Home-Manager's `home.file` or `xdg.configFile`.
This method is effective under the condition that your Dotfiles content is not generated
by Nix. For instance, my Emacs/Neovim configurations are native and are linked to the
appropriate locations solely through Nix Home-Manager's `home.file` or `xdg.configFile`.

View file

@ -2,7 +2,9 @@
## Show detailed error messages
You can always try to add `--show-trace --print-build-logs --verbose` to the `nixos-rebuild` command to get the detailed error message if you encounter any errors during the deployment. e.g.
You can always try to add `--show-trace --print-build-logs --verbose` to the
`nixos-rebuild` command to get the detailed error message if you encounter any errors
during the deployment. e.g.
```bash
cd /etc/nixos
@ -14,9 +16,11 @@ sudo nixos-rebuild switch --flake .#myhost --show-trace -L -v
## Debugging with `nix repl`
> NOTE: If you have disabled `NIX_PATH`, you won't be able to use syntax like `<nixpkgs>`. Instead, you should use `nix repl -f flake:nixpkgs` to load nixpkgs.
> NOTE: If you have disabled `NIX_PATH`, you won't be able to use syntax like `<nixpkgs>`.
> Instead, you should use `nix repl -f flake:nixpkgs` to load nixpkgs.
We have frequently used nix repl `<nixpkgs>` throughout this guide to examine the source code. It is a powerful tool that helps us understand how things work in Nix.
We have frequently used nix repl `<nixpkgs>` throughout this guide to examine the source
code. It is a powerful tool that helps us understand how things work in Nix.
Let's take a closer look at the help message of nix repl:
@ -51,7 +55,8 @@ The following commands are available:
There are a couple of expressions that I frequently use: `:lf <ref>` and `:e <expr>`.
The `:e <expr>` command is very intuitive, so I won't go into detail about it. Instead, let's focus on `:lf <ref>`:
The `:e <expr>` command is very intuitive, so I won't go into detail about it. Instead,
let's focus on `:lf <ref>`:
```nix
# cd into my nix-config repo(you should replace it with your own nix-config repo)
@ -156,7 +161,8 @@ outputs.nixosConfigurations.ai.config.home-manager.users.ryan.home.file..config/
#......
```
As you can see, after loading your Nix flake into the REPL, you can check every attribute of the flake. This capability is very convenient for debugging purposes.
As you can see, after loading your Nix flake into the REPL, you can check every attribute
of the flake. This capability is very convenient for debugging purposes.
## Debugging functions provided by nixpkgs

View file

@ -1,9 +1,15 @@
# Best Practices
Nix is a powerful and flexible tool that offers various approaches to accomplish tasks, which can sometimes make it challenging to determine the most suitable method for a particular job. To assist you in navigating through this vast ecosystem, I have compiled some best practices that I've learned from the community. I hope these practices prove helpful to you.
Nix is a powerful and flexible tool that offers various approaches to accomplish tasks,
which can sometimes make it challenging to determine the most suitable method for a
particular job. To assist you in navigating through this vast ecosystem, I have compiled
some best practices that I've learned from the community. I hope these practices prove
helpful to you.
## References
- [Tips&Tricks for NixOS Desktop - NixOS Discourse][Tips&Tricks for NixOS Desktop - NixOS Discourse]
- [Tips&Tricks for NixOS Desktop - NixOS
Discourse][Tips&Tricks for NixOS Desktop - NixOS Discourse]
[Tips&Tricks for NixOS Desktop - NixOS Discourse]: https://discourse.nixos.org/t/tips-tricks-for-nixos-desktop/28488
[Tips&Tricks for NixOS Desktop - NixOS Discourse]:
https://discourse.nixos.org/t/tips-tricks-for-nixos-desktop/28488

View file

@ -2,31 +2,49 @@
## Introduction to NIX_PATH {#nix-path-introduction}
The Nix search path is controlled by the environment variable `NIX_PATH`, which follows the same format as the Linux `PATH` environment variable, consisting of multiple paths separated by colons.
The Nix search path is controlled by the environment variable `NIX_PATH`, which follows
the same format as the Linux `PATH` environment variable, consisting of multiple paths
separated by colons.
Paths in Nix expressions that look like `<name>` are resolved using the path named `name` from the `NIX_PATH`.
Paths in Nix expressions that look like `<name>` are resolved using the path named `name`
from the `NIX_PATH`.
This usage pattern is no longer recommended under the Flakes feature because it results in Flake builds depending on a mutable environment variable `NIX_PATH`, compromising reproducibility.
This usage pattern is no longer recommended under the Flakes feature because it results in
Flake builds depending on a mutable environment variable `NIX_PATH`, compromising
reproducibility.
However, in certain scenarios, we still need to use `NIX_PATH`, such as when we frequently use the command `nix repl '<nixpkgs>'`, which utilizes the Nixpkgs found through `NIX_PATH` search.
However, in certain scenarios, we still need to use `NIX_PATH`, such as when we frequently
use the command `nix repl '<nixpkgs>'`, which utilizes the Nixpkgs found through
`NIX_PATH` search.
## Introduction to Flakes Registry {#flakes-registry-introduction}
The Flakes Registry is a center for Flake registration that assists us in using shorter IDs instead of lengthy flake repository addresses when using commands like `nix run`, `nix shell`, and more.
The Flakes Registry is a center for Flake registration that assists us in using shorter
IDs instead of lengthy flake repository addresses when using commands like `nix run`,
`nix shell`, and more.
By default, Nix looks up the corresponding GitHub repository address for this ID from <https://github.com/NixOS/flake-registry/blob/master/flake-registry.json>.
By default, Nix looks up the corresponding GitHub repository address for this ID from
<https://github.com/NixOS/flake-registry/blob/master/flake-registry.json>.
For instance, if we execute `nix run nixpkgs#ponysay hello`, Nix will automatically retrieve the GitHub repository address for `nixpkgs` from the aforementioned JSON file. It then downloads the repository, locates the `flake.nix` within, and runs the corresponding `ponysay` package.
For instance, if we execute `nix run nixpkgs#ponysay hello`, Nix will automatically
retrieve the GitHub repository address for `nixpkgs` from the aforementioned JSON file. It
then downloads the repository, locates the `flake.nix` within, and runs the corresponding
`ponysay` package.
## Custom NIX_PATH and Flake Registry {#custom-nix-path-and-flake-registry-1}
> **NOTE: Newcomers should skip this section! Disabling `nix-channel` incorrectly may lead to some headaches.**
> **NOTE: Newcomers should skip this section! Disabling `nix-channel` incorrectly may lead
> to some headaches.**
The roles of `NIX_PATH` and the Flake Registry have been explained earlier.
In daily use, we typically want the `nixpkgs` used in commands like `nix repl '<nixpkgs>'`, `nix run nixpkgs#ponysay hello` to match the system's `nixpkgs`. This requires us to customize the `NIX_PATH` and Flake Registry.
On the other hand, although `nix-channel` can coexist with the Flakes feature, in practice, Flakes can completely replace it, so we can also disable it.
The roles of `NIX_PATH` and the Flake Registry have been explained earlier. In daily use,
we typically want the `nixpkgs` used in commands like `nix repl '<nixpkgs>'`,
`nix run nixpkgs#ponysay hello` to match the system's `nixpkgs`. This requires us to
customize the `NIX_PATH` and Flake Registry. On the other hand, although `nix-channel` can
coexist with the Flakes feature, in practice, Flakes can completely replace it, so we can
also disable it.
In your NixOS configuration, adding the following module will achieve the mentioned requirements:
In your NixOS configuration, adding the following module will achieve the mentioned
requirements:
```nix
{lib, nixpkgs, ...}: {

View file

@ -1,12 +1,26 @@
# Remote Deployment
Nix's inherent design is well-suited for remote deployment, and the Nix community offers several tools tailored for this purpose, such as [NixOps](https://github.com/NixOS/nixops) and [colmena](https://github.com/zhaofengli/colmena). Additionally, the official tool we've used extensively, `nixos-rebuild`, possesses some remote deployment capabilities too.
Nix's inherent design is well-suited for remote deployment, and the Nix community offers
several tools tailored for this purpose, such as [NixOps](https://github.com/NixOS/nixops)
and [colmena](https://github.com/zhaofengli/colmena). Additionally, the official tool
we've used extensively, `nixos-rebuild`, possesses some remote deployment capabilities
too.
In addition, within multi-architecture scenarios, remote deployment can optimally leverage Nix's multi-architecture support. For example, you can cross-compile an aarch64/riscv64 NixOS system on an x86_64 host, followed by remote deployment onto the corresponding hosts via SSH.
In addition, within multi-architecture scenarios, remote deployment can optimally leverage
Nix's multi-architecture support. For example, you can cross-compile an aarch64/riscv64
NixOS system on an x86_64 host, followed by remote deployment onto the corresponding hosts
via SSH.
Recently, I encountered a situation where I cross-compiled a NixOS system image for a RISCV64 SBC on my local machine. Consequently, I already possessed all the compilation caches for building this system locally. However, due to the lack of official binary caches for RISCV64 architecture, executing any uninstalled program directly on the development board (e.g., `nix run nixpkgs#cowsay hello`) triggered extensive compilations. This process consumed hours, which was quite unacceptable.
Recently, I encountered a situation where I cross-compiled a NixOS system image for a
RISCV64 SBC on my local machine. Consequently, I already possessed all the compilation
caches for building this system locally. However, due to the lack of official binary
caches for RISCV64 architecture, executing any uninstalled program directly on the
development board (e.g., `nix run nixpkgs#cowsay hello`) triggered extensive compilations.
This process consumed hours, which was quite unacceptable.
By adopting remote deployment, I could fully harness the computational power of my local high-performance CPU and the extensive compilation caches. This switch vastly improved my experience and significantly mitigated the previously time-consuming compilation issue.
By adopting remote deployment, I could fully harness the computational power of my local
high-performance CPU and the extensive compilation caches. This switch vastly improved my
experience and significantly mitigated the previously time-consuming compilation issue.
Let me briefly guide you through using colmena or `nixos-rebuild` for remote deployment.
@ -14,21 +28,35 @@ Let me briefly guide you through using colmena or `nixos-rebuild` for remote dep
Before embarking on remote deployment, a few preparatory steps are necessary:
1. To prevent remote host's sudo password verification failure, choose one of the following methods:
1. To prevent remote host's sudo password verification failure, choose one of the
following methods:
1. Deploy as the remote host's `root` user.
2. Add `security.sudo.wheelNeedsPassword = false;` to the remote host's configuration and manually deploy once in advance to grant the user passwordless sudo permissions..
1. **This will allow user-level programs to silently obtain sudo permissions, posing a security risk**! Therefore, if you choose this method, it's advisable to create a dedicated user for remote deployment, rather than using your regular user account!
2. Add `security.sudo.wheelNeedsPassword = false;` to the remote host's configuration
and manually deploy once in advance to grant the user passwordless sudo
permissions..
1. **This will allow user-level programs to silently obtain sudo permissions, posing
a security risk**! Therefore, if you choose this method, it's advisable to create
a dedicated user for remote deployment, rather than using your regular user
account!
2. Configure SSH public key authentication for the remote hosts.
1. Use the `users.users.<name>.openssh.authorizedKeys.keys` option to complete this task.
3. Add the remote host's Known Hosts record to your local machine. Otherwise, colmena/nixos-rebuild will fail to deploy due to the inability to verify the remote host's identity.
1. Use the `programs.ssh.knownHosts` option to add the remote host's public key to the Known Hosts record.
4. Manually use the `ssh root@<you-host>` command to verify that you can login to the remote host.
1. Use the `users.users.<name>.openssh.authorizedKeys.keys` option to complete this
task.
3. Add the remote host's Known Hosts record to your local machine. Otherwise,
colmena/nixos-rebuild will fail to deploy due to the inability to verify the remote
host's identity.
1. Use the `programs.ssh.knownHosts` option to add the remote host's public key to the
Known Hosts record.
4. Manually use the `ssh root@<you-host>` command to verify that you can login to the
remote host.
1. If you encounter any issues, resolve them before proceeding.
It's advisable to use the `root` user for deployment as it's more convenient and avoids the complexities of sudo permissions.
It's advisable to use the `root` user for deployment as it's more convenient and avoids
the complexities of sudo permissions.
Assuming we intend to deploy remotely using the root user, the initial step involves configuring SSH public key authentication for the root user on the remote host.
To accomplish this, simply add the following content to any NixOS Module in the remote host's Nix configuration (e.g., `configuration.nix`), then rebuild the system:
Assuming we intend to deploy remotely using the root user, the initial step involves
configuring SSH public key authentication for the root user on the remote host. To
accomplish this, simply add the following content to any NixOS Module in the remote host's
Nix configuration (e.g., `configuration.nix`), then rebuild the system:
```nix{6-9}
# configuration.nix
@ -45,7 +73,8 @@ To accomplish this, simply add the following content to any NixOS Module in the
}
```
Furthermore, you'll need to add the SSH private key to the SSH agent on your local machine for authentication during remote deployment:
Furthermore, you'll need to add the SSH private key to the SSH agent on your local machine
for authentication during remote deployment:
```bash
ssh-add ~/.ssh/your-private-key
@ -53,9 +82,12 @@ ssh-add ~/.ssh/your-private-key
## Deploy through `colmena`
`colmena` doesn't directly use the familiar `nixosConfigurations.xxx` for remote deployment. Instead, it customizes a flake outputs named `colmena`. Although its structure is similar to `nixosConfigurations.xxx`, it's not identical.
`colmena` doesn't directly use the familiar `nixosConfigurations.xxx` for remote
deployment. Instead, it customizes a flake outputs named `colmena`. Although its structure
is similar to `nixosConfigurations.xxx`, it's not identical.
In your system's `flake.nix`, add a new outputs named `colmena`. A simple example is shown below:
In your system's `flake.nix`, add a new outputs named `colmena`. A simple example is shown
below:
```nix{11-34}
{
@ -102,26 +134,34 @@ Now you can deploy your configuration to the device:
nix run nixpkgs#colmena apply
```
For more advanced usage, refer to colmena's official documentation at <https://colmena.cli.rs/unstable/introduction.html>
For more advanced usage, refer to colmena's official documentation at
<https://colmena.cli.rs/unstable/introduction.html>
## Deploy through `nixos-rebuild`
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.my-nixos` 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
nixos-rebuild switch --flake .#nixos-text \
--target-host root@192.168.4.1 --build-host localhost --verbose
```
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.
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`.
To avoid repeatedly using IP addresses, you can define host aliases in your local machine's `~/.ssh/config` or `/etc/ssh/ssh_config`. For example:
To avoid repeatedly using IP addresses, you can define host aliases in your local
machine's `~/.ssh/config` or `/etc/ssh/ssh_config`. For example:
> Generating the SSH configuration entirely through Nix configuration is possible, and this task is left to you.
> Generating the SSH configuration entirely through Nix configuration is possible, and
> this task is left to you.
```bash
cat ~/.ssh/config

View file

@ -1,11 +1,18 @@
# Running Downloaded Binaries on NixOS
Since NixOS does not strictly adhere to the Filesystem Hierarchy Standard (FHS), binaries downloaded from the internet may not work directly on NixOS. However, there are various methods available to make them function properly.
Since NixOS does not strictly adhere to the Filesystem Hierarchy Standard (FHS), binaries
downloaded from the internet may not work directly on NixOS. However, there are various
methods available to make them function properly.
For a comprehensive guide that presents ten different approaches to run downloaded binaries on NixOS, I recommend reading the article [Different methods to run a non-nixos executable on Nixos](https://unix.stackexchange.com/questions/522822/different-methods-to-run-a-non-nixos-executable-on-nixos) and take a look at [nix-alien](https://github.com/thiagokokada/nix-alien).
Or if you are familiar with Docker, running the binary in a Docker container is also a good choice.
For a comprehensive guide that presents ten different approaches to run downloaded
binaries on NixOS, I recommend reading the article
[Different methods to run a non-nixos executable on Nixos](https://unix.stackexchange.com/questions/522822/different-methods-to-run-a-non-nixos-executable-on-nixos)
and take a look at [nix-alien](https://github.com/thiagokokada/nix-alien). Or if you are
familiar with Docker, running the binary in a Docker container is also a good choice.
Among these methods, I personally prefer creating an FHS environment to run the binary, as it proves to be both convenient and easy to use. To set up such an environment, you can add the following code to one of your Nix modules:
Among these methods, I personally prefer creating an FHS environment to run the binary, as
it proves to be both convenient and easy to use. To set up such an environment, you can
add the following code to one of your Nix modules:
```nix
{ config, pkgs, lib, ... }:
@ -42,7 +49,8 @@ Among these methods, I personally prefer creating an FHS environment to run the
}
```
After applying the updated configuration, you can use the `fhs` command to enter the FHS environment, and then execute the binary you downloaded, for example:
After applying the updated configuration, you can use the `fhs` command to enter the FHS
environment, and then execute the binary you downloaded, for example:
```shell
# Activating FHS drops me into a shell that resembles a "normal" Linux environment.
@ -55,7 +63,11 @@ $ fhs
## References
- [Tips&Tricks for NixOS Desktop - NixOS Discourse][Tips&Tricks for NixOS Desktop - NixOS Discourse]: This resource provides a collection of useful tips and tricks for NixOS desktop users.
- [nix-alien](https://github.com/thiagokokada/nix-alien): Run unpatched binaries on Nix/NixOS
- [Tips&Tricks for NixOS Desktop - NixOS
Discourse][Tips&Tricks for NixOS Desktop - NixOS Discourse]: This resource provides a
collection of useful tips and tricks for NixOS desktop users.
- [nix-alien](https://github.com/thiagokokada/nix-alien): Run unpatched binaries on
Nix/NixOS
[Tips&Tricks for NixOS Desktop - NixOS Discourse]: https://discourse.nixos.org/t/tips-tricks-for-nixos-desktop/28488
[Tips&Tricks for NixOS Desktop - NixOS Discourse]:
https://discourse.nixos.org/t/tips-tricks-for-nixos-desktop/28488

View file

@ -1,12 +1,16 @@
# Simplifying NixOS-Related Commands
To simplify NixOS-related commands, I utilize [just](https://github.com/casey/just), which proves to be very convenient.
To simplify NixOS-related commands, I utilize [just](https://github.com/casey/just), which
proves to be very convenient.
Alternatively, you can also use similar tools like Makefile or [cargo-make](https://github.com/sagiegurari/cargo-make) for this purpose. Here, I will provide my approach as a reference.
Alternatively, you can also use similar tools like Makefile or
[cargo-make](https://github.com/sagiegurari/cargo-make) for this purpose. Here, I will
provide my approach as a reference.
Below is an example of how my Justfile looks:
> The latest Justfile I'm using: [ryan4yin/nix-config/Justfile](https://github.com/ryan4yin/nix-config/blob/main/Justfile)
> The latest Justfile I'm using:
> [ryan4yin/nix-config/Justfile](https://github.com/ryan4yin/nix-config/blob/main/Justfile)
```Makefile
# just is a command runner, Justfile is very similar to Makefile, but simpler.
@ -77,6 +81,9 @@ idols: aqua ruby kana
idols-debug: aqua-debug ruby-debug kana-debug
```
By Save this `Justfile` to the root directory of your Nix flake. Then, I can use `just deploy` to deploy the configuration to my local machine, and `just idols` to deploy the configuration to all my remote servers.
By Save this `Justfile` to the root directory of your Nix flake. Then, I can use
`just deploy` to deploy the configuration to my local machine, and `just idols` to deploy
the configuration to all my remote servers.
This approach simplifies the execution of NixOS commands by abstracting them behind target names in the Justfile, providing a more user-friendly and convenient experience.
This approach simplifies the execution of NixOS commands by abstracting them behind target
names in the Justfile, providing a more user-friendly and convenient experience.

View file

@ -1,21 +1,32 @@
# Cross-platform Compilation
On any Linux platform, there are two ways to do cross-platform compilation. For example, to build an `aarch64-linux` program on an `x86_64-linux` host, you can use the following methods:
On any Linux platform, there are two ways to do cross-platform compilation. For example,
to build an `aarch64-linux` program on an `x86_64-linux` host, you can use the following
methods:
1. Use the cross-compilation toolchain to compile the `aarch64` program.
- The disadvantage is that you cannot use the NixOS binary cache, and you need to compile everything yourself (cross-compilation also has a cache, but there is basically nothing in it).
- The advantages are that you don't need to emulate the instruction set, and the performance is high.
2. Use QEMU to emulate the `aarch64` architecture and then compile the program in the emulator.
- The disadvantage is that the instruction set is emulated, and the performance is poor.
- The advantage is that you can use the NixOS binary cache, and you don't need to compile everything yourself.
- The disadvantage is that you cannot use the NixOS binary cache, and you need to
compile everything yourself (cross-compilation also has a cache, but there is
basically nothing in it).
- The advantages are that you don't need to emulate the instruction set, and the
performance is high.
2. Use QEMU to emulate the `aarch64` architecture and then compile the program in the
emulator.
- The disadvantage is that the instruction set is emulated, and the performance is
poor.
- The advantage is that you can use the NixOS binary cache, and you don't need to
compile everything yourself.
If you use method one, you don't need to enable `binfmt_misc`, but you need to execute the compilation through the cross-compilation toolchain.
If you use method one, you don't need to enable `binfmt_misc`, but you need to execute the
compilation through the cross-compilation toolchain.
If you use method two, you need to enable the `binfmt_misc` of the `aarch64` architecture in the NixOS configuration of the building machine.
If you use method two, you need to enable the `binfmt_misc` of the `aarch64` architecture
in the NixOS configuration of the building machine.
## Cross Compilation
`nixpkgs` provides a set of predefined host platforms for cross-compilation called `pkgsCross`. You can explore them in `nix repl`.
`nixpkgs` provides a set of predefined host platforms for cross-compilation called
`pkgsCross`. You can explore them in `nix repl`.
```shell
nix repl '<nixpkgs>'
@ -60,7 +71,8 @@ pkgsCross.mipsel-linux-gnu
pkgsCross.mmix
```
If you want to set `pkgs` to a cross-compilation toolchain globally in a flake, you only need to add a Module in `flake.nix`, as shown below:
If you want to set `pkgs` to a cross-compilation toolchain globally in a flake, you only
need to add a Module in `flake.nix`, as shown below:
```nix{15-20}
{
@ -91,13 +103,18 @@ If you want to set `pkgs` to a cross-compilation toolchain globally in a flake,
}
```
The `nixpkgs.crossSystem` option is used to set `pkgs` to a cross-compilation toolchain, so that all the contents built will be `riscv64-linux` architecture.
The `nixpkgs.crossSystem` option is used to set `pkgs` to a cross-compilation toolchain,
so that all the contents built will be `riscv64-linux` architecture.
## Compile through emulated system
The second method is to cross-compile through the emulated system. This method does not require a cross-compilation toolchain.
The second method is to cross-compile through the emulated system. This method does not
require a cross-compilation toolchain.
To use this method, first your building machine needs to enable the binfmt_misc module in the configuration. If your building machine is NixOS, add the following configuration to your NixOS Module to enable the simulated build system of `aarch64-linux` and `riscv64-linux` architectures:
To use this method, first your building machine needs to enable the binfmt_misc module in
the configuration. If your building machine is NixOS, add the following configuration to
your NixOS Module to enable the simulated build system of `aarch64-linux` and
`riscv64-linux` architectures:
```nix{6}
{ ... }:
@ -111,7 +128,8 @@ To use this method, first your building machine needs to enable the binfmt_misc
}
```
As for `flake.nix`, its setting method is very simple, even simpler than the setting of cross-compilation, as shown below:
As for `flake.nix`, its setting method is very simple, even simpler than the setting of
cross-compilation, as shown below:
```nix{11}
{
@ -134,19 +152,40 @@ As for `flake.nix`, its setting method is very simple, even simpler than the set
```
You do not need to add any additional modules, just specify `system` as `riscv64-linux`.
Nix will automatically detect whether the current system is `riscv64-linux` during the build. If not, it will automatically build through the emulated system(QEMU). For users, these underlying operations are completely transparent.
Nix will automatically detect whether the current system is `riscv64-linux` during the
build. If not, it will automatically build through the emulated system(QEMU). For users,
these underlying operations are completely transparent.
## Linux binfmt_misc
The previous section only provided an introduction on how to use Nix's emulated system, but if you want to understand the underlying details, here's a brief introduction.
The previous section only provided an introduction on how to use Nix's emulated system,
but if you want to understand the underlying details, here's a brief introduction.
`binfmt_misc` is a feature of the Linux kernel, which stands for Kernel Support for miscellaneous Binary Formats. It enables Linux to run programs for almost any CPU architecture, including X86_64, ARM64, RISCV64, and more.
`binfmt_misc` is a feature of the Linux kernel, which stands for Kernel Support for
miscellaneous Binary Formats. It enables Linux to run programs for almost any CPU
architecture, including X86_64, ARM64, RISCV64, and more.
To enable `binfmt_misc` to run programs in various formats, two things are required: a specific identification method for the binary format and the location of the corresponding interpreter. Although `binfmt_misc` sounds powerful, its implementation is surprisingly easy to understand. It works similarly to how the Bash interpreter determines the interpreter to use by reading the first line of a script file (e.g., `#!/usr/bin/env python3`). `binfmt_misc` defines a set of rules, such as reading the magic number at a specific location in the binary file or determining the executable file format based on the file extension (e.g., .exe, .py). It then invokes the corresponding interpreter to execute the program. The default executable file format in Linux is ELF, but `binfmt_misc` expands the execution possibilities by allowing a wide range of binary files to be executed using their respective interpreters.
To enable `binfmt_misc` to run programs in various formats, two things are required: a
specific identification method for the binary format and the location of the corresponding
interpreter. Although `binfmt_misc` sounds powerful, its implementation is surprisingly
easy to understand. It works similarly to how the Bash interpreter determines the
interpreter to use by reading the first line of a script file (e.g.,
`#!/usr/bin/env python3`). `binfmt_misc` defines a set of rules, such as reading the magic
number at a specific location in the binary file or determining the executable file format
based on the file extension (e.g., .exe, .py). It then invokes the corresponding
interpreter to execute the program. The default executable file format in Linux is ELF,
but `binfmt_misc` expands the execution possibilities by allowing a wide range of binary
files to be executed using their respective interpreters.
To register a binary program format, you need to write a line in the format `:name:type:offset:magic:mask:interpreter:flags` to the `/proc/sys/fs/binfmt_misc/register` file. The detailed explanation of the format is beyond the scope of this discussion.
To register a binary program format, you need to write a line in the format
`:name:type:offset:magic:mask:interpreter:flags` to the
`/proc/sys/fs/binfmt_misc/register` file. The detailed explanation of the format is beyond
the scope of this discussion.
Since manually writing the registration information for `binfmt_misc` can be cumbersome, the community provides a container to assist with automatic registration. This container is called `binfmt` and running it will install various `binfmt_misc` emulators. Here's an example:
Since manually writing the registration information for `binfmt_misc` can be cumbersome,
the community provides a container to assist with automatic registration. This container
is called `binfmt` and running it will install various `binfmt_misc` emulators. Here's an
example:
```shell
# Register all architectures
@ -156,13 +195,23 @@ podman run --privileged --rm tonistiigi/binfmt:latest --install all
docker run --privileged --rm tonistiigi/binfmt --install arm64,riscv64,arm
```
The `binfmt_misc` module was introduced in Linux version 2.6.12-rc2 and has undergone several minor changes in functionality since then. In Linux 4.8, the "F" (fix binary) flag was added, allowing the interpreter to be invoked correctly in mount namespaces and chroot environments. To work properly in containers where multiple architectures need to be built, the "F" flag is necessary. Therefore, the kernel version needs to be 4.8 or above.
The `binfmt_misc` module was introduced in Linux version 2.6.12-rc2 and has undergone
several minor changes in functionality since then. In Linux 4.8, the "F" (fix binary) flag
was added, allowing the interpreter to be invoked correctly in mount namespaces and chroot
environments. To work properly in containers where multiple architectures need to be
built, the "F" flag is necessary. Therefore, the kernel version needs to be 4.8 or above.
In summary, `binfmt_misc` provides transparency compared to explicitly calling an interpreter to execute non-native architecture programs. With `binfmt_misc`, users no longer need to worry about which interpreter to use when running a program. It allows programs of any architecture to be executed directly. The configurable "F" flag is an added benefit, as it loads the interpreter program into memory during installation and remains unaffected by subsequent environment changes.
In summary, `binfmt_misc` provides transparency compared to explicitly calling an
interpreter to execute non-native architecture programs. With `binfmt_misc`, users no
longer need to worry about which interpreter to use when running a program. It allows
programs of any architecture to be executed directly. The configurable "F" flag is an
added benefit, as it loads the interpreter program into memory during installation and
remains unaffected by subsequent environment changes.
## Custom build toolchain
Sometimes we may need to use a custom toolchain for building, such as using our own gcc, or using our own musl libc, etc. This modification can be achieved through overlays.
Sometimes we may need to use a custom toolchain for building, such as using our own gcc,
or using our own musl libc, etc. This modification can be achieved through overlays.
For example, let's try to use a different version of gcc, and test it through `nix repl`:
@ -218,9 +267,13 @@ So how to use this method in Flakes? The example `flake.nix` is as follows:
}
```
`nixpkgs.overlays` is used to modify the `pkgs` instance globally, and the modified `pkgs` instance will take effect to the whole flake. It will likely cause a large number of cache missing, and thus require building a large number of Nix packages locally.
`nixpkgs.overlays` is used to modify the `pkgs` instance globally, and the modified `pkgs`
instance will take effect to the whole flake. It will likely cause a large number of cache
missing, and thus require building a large number of Nix packages locally.
To avoid this problem, a better way is to create a new `pkgs` instance, and only use this instance when building the packages we want to modify. The example `flake.nix` is as follows:
To avoid this problem, a better way is to create a new `pkgs` instance, and only use this
instance when building the packages we want to modify. The example `flake.nix` is as
follows:
```nix{10-19,34-37}
{
@ -268,7 +321,8 @@ To avoid this problem, a better way is to create a new `pkgs` instance, and only
}
```
Through the above method, we can easily customize the build toolchain of some packages without affecting the build of other packages.
Through the above method, we can easily customize the build toolchain of some packages
without affecting the build of other packages.
## References

View file

@ -1,30 +1,36 @@
# Dev Environments
We have learned how to build development environments, but it's a bit tedious to write `flake.nix` for each project.
We have learned how to build development environments, but it's a bit tedious to write
`flake.nix` for each project.
Luckily, some people in the community have done this for us. The following repository contains development environment templates for most programming languages. Just copy and paste them:
Luckily, some people in the community have done this for us. The following repository
contains development environment templates for most programming languages. Just copy and
paste them:
- [dev-templates](https://github.com/the-nix-way/dev-templates)
- [MordragT/nix-templates](https://github.com/MordragT/nix-templates)
If you think the structure of `flake.nix` is still too complicated and want a simpler way,
you can consider using the following project,
which encapsulates Nix more thoroughly and provides users with a simpler definition:
you can consider using the following project, which encapsulates Nix more thoroughly and
provides users with a simpler definition:
- [cachix/devenv](https://github.com/cachix/devenv)
If you don't want to write a single line of nix code and just want to get a reproducible development environment with minimal cost,
here's a tool that might meet your needs:
If you don't want to write a single line of nix code and just want to get a reproducible
development environment with minimal cost, here's a tool that might meet your needs:
- [jetpack-io/devbox](https://github.com/jetpack-io/devbox)
## Dev Environment for Python
The development environment for Python is much more cumbersome compared to languages like Java or Go because it defaults to installing software in the global environment.
To install software for the current project, you must create a virtual environment first (unlike in languages such as JavaScript or Go,
where virtual environments are not necessary). This behavior is very unfriendly for Nix.
The development environment for Python is much more cumbersome compared to languages like
Java or Go because it defaults to installing software in the global environment. To
install software for the current project, you must create a virtual environment first
(unlike in languages such as JavaScript or Go, where virtual environments are not
necessary). This behavior is very unfriendly for Nix.
By default, when using pip in Python, it installs software globally. On NixOS, running `pip install` directly will result in an error:
By default, when using pip in Python, it installs software globally. On NixOS, running
`pip install` directly will result in an error:
```bash
pip install -r requirements.txt
@ -41,38 +47,47 @@ note: If you believe this is a mistake, please contact your Python installation
hint: See PEP 668 for the detailed specification.
```
Based on the error message, `pip install` is directly disabled by NixOS. Even when attempting `pip install --user`, it is similarly disabled.
To improve the reproducibility of the environment, Nix eliminates these commands altogether.
Even if we create a new environment using methods like `mkShell`,
these commands still result in errors (presumably because the pip command in Nixpkgs itself has
been modified to prevent any modification instructions like `install` from running).
Based on the error message, `pip install` is directly disabled by NixOS. Even when
attempting `pip install --user`, it is similarly disabled. To improve the reproducibility
of the environment, Nix eliminates these commands altogether. Even if we create a new
environment using methods like `mkShell`, these commands still result in errors
(presumably because the pip command in Nixpkgs itself has been modified to prevent any
modification instructions like `install` from running).
However, many project installation scripts are based on pip, which means these scripts cannot be used directly.
Additionally, the content in nixpkgs is limited, and many packages from PyPI are missing.
This requires users to package them themselves, adding a lot of complexity and mental burden.
However, many project installation scripts are based on pip, which means these scripts
cannot be used directly. Additionally, the content in nixpkgs is limited, and many
packages from PyPI are missing. This requires users to package them themselves, adding a
lot of complexity and mental burden.
One solution is to use the `venv` virtual environment. Within a virtual environment, you can use commands like pip normally:
One solution is to use the `venv` virtual environment. Within a virtual environment, you
can use commands like pip normally:
```shell
python -m venv ./env
source ./env/bin/activate
```
Alternatively, you can use a third-party tool called `virtualenv`, but this requires additional installation.
Alternatively, you can use a third-party tool called `virtualenv`, but this requires
additional installation.
For those who still lack confidence in the venv created directly with Python, they may prefer to include the virtual environment in `/nix/store` to make it immutable.
This can be achieved by directly installing the dependencies from `requirements.txt` or `poetry.toml` using Nix.
There are existing Nix packaging tools available to assist with this:
For those who still lack confidence in the venv created directly with Python, they may
prefer to include the virtual environment in `/nix/store` to make it immutable. This can
be achieved by directly installing the dependencies from `requirements.txt` or
`poetry.toml` using Nix. There are existing Nix packaging tools available to assist with
this:
> Note that even in these environments, running commands like `pip install` directly will still fail.
> Python dependencies must be installed through `flake.nix` because the data is located in the `/nix/store` directory,
> and these modification commands can only be executed during the Nix build phase.
> Note that even in these environments, running commands like `pip install` directly will
> still fail. Python dependencies must be installed through `flake.nix` because the data
> is located in the `/nix/store` directory, and these modification commands can only be
> executed during the Nix build phase.
- [DavHau/mach-nix](https://github.com/DavHau/mach-nix) (currently unmaintained)
- [poetry2nix](https://github.com/nix-community/poetry2nix)
The advantage of these tools is that they utilize the lock mechanism of Nix Flakes to improve reproducibility.
However, the downside is that they add an extra layer of abstraction, making the underlying system more complex.
The advantage of these tools is that they utilize the lock mechanism of Nix Flakes to
improve reproducibility. However, the downside is that they add an extra layer of
abstraction, making the underlying system more complex.
Finally, in some more complex projects, neither of the above solutions may be feasible.
In such cases, the best solution is to use containers such as Docker or Podman. Containers have fewer restrictions compared to Nix and can provide the best compatibility.
Finally, in some more complex projects, neither of the above solutions may be feasible. In
such cases, the best solution is to use containers such as Docker or Podman. Containers
have fewer restrictions compared to Nix and can provide the best compatibility.

View file

@ -1,15 +1,26 @@
# Distributed Building
Distributed building can significantly speed up the build process by utilizing multiple machines. However, for ordinary NixOS users, distributed building may not be very useful since `cache.nixos.org` provides a vast majority of caches for the `x86_64` architecture.
Distributed building can significantly speed up the build process by utilizing multiple
machines. However, for ordinary NixOS users, distributed building may not be very useful
since `cache.nixos.org` provides a vast majority of caches for the `x86_64` architecture.
Distributed building is particularly valuable in scenarios where no cache is available, such as:
Distributed building is particularly valuable in scenarios where no cache is available,
such as:
1. Users of `RISC-V` or `ARM64` architectures, especially `RISC-V`, as there are very few caches for these architectures in the official cache repository. Local compilation is often required.
2. Users who heavily customize their systems. The packages in the official cache repository are built with default configurations. If you modify the build parameters, the official cache is not applicable, and local compilation is necessary. For example, in embedded scenarios, customization of the underlying kernel, drivers, etc., is often required, leading to the need for local compilation.
1. Users of `RISC-V` or `ARM64` architectures, especially `RISC-V`, as there are very few
caches for these architectures in the official cache repository. Local compilation is
often required.
2. Users who heavily customize their systems. The packages in the official cache
repository are built with default configurations. If you modify the build parameters,
the official cache is not applicable, and local compilation is necessary. For example,
in embedded scenarios, customization of the underlying kernel, drivers, etc., is often
required, leading to the need for local compilation.
## Configuring Distributed Building
Currently, there is no official documentation for distributed building. However, I have provided a sample distributed build configuration (a NixOS module) below, along with some recommended reference documents at the end of this section.
Currently, there is no official documentation for distributed building. However, I have
provided a sample distributed build configuration (a NixOS module) below, along with some
recommended reference documents at the end of this section.
```nix
{ ... }: {
@ -129,9 +140,14 @@ Currently, there is no official documentation for distributed building. However,
Here are some observed issues and limitations:
1. You cannot specify which hosts to use at build time. You can only specify a list of hosts in the configuration file, and Nix automatically selects available hosts.
2. When choosing a host, Nix always prefers the remote host over the local host, even if the local host has better performance. This can result in underutilization of the local host's CPU.
3. The smallest unit of distributed building is a derivation. When building large packages, other machines may remain idle for a long time, waiting for the large package to be built. This can lead to resource wastage.
1. You cannot specify which hosts to use at build time. You can only specify a list of
hosts in the configuration file, and Nix automatically selects available hosts.
2. When choosing a host, Nix always prefers the remote host over the local host, even if
the local host has better performance. This can result in underutilization of the local
host's CPU.
3. The smallest unit of distributed building is a derivation. When building large
packages, other machines may remain idle for a long time, waiting for the large package
to be built. This can lead to resource wastage.
## References

View file

@ -1,16 +1,23 @@
# Development Environments on NixOS
NixOS's reproducibility makes it ideal for building development environments. However, if you're used to other distros, you may encounter problems because NixOS has its own logic. We'll briefly explain this below.
NixOS's reproducibility makes it ideal for building development environments. However, if
you're used to other distros, you may encounter problems because NixOS has its own logic.
We'll briefly explain this below.
On NixOS, it's recommended to only install common tools in the global environment, such as `git`, `vim`, `emacs`, `tmux`, `zsh`, etc. The development environment of each language should be an independent environment for each project.
On NixOS, it's recommended to only install common tools in the global environment, such as
`git`, `vim`, `emacs`, `tmux`, `zsh`, etc. The development environment of each language
should be an independent environment for each project.
You should NOT install the development environment of each language in the global environment. The project environment should be completely isolated from each other and will not affect each other.
You should NOT install the development environment of each language in the global
environment. The project environment should be completely isolated from each other and
will not affect each other.
In the following sections, we'll introduce how the development environment works in NixOS.
## Creating 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.
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:
@ -38,15 +45,19 @@ Hello, world!
|| ||
```
`nix shell` is very useful when you just want to try out some packages or quickly create a clean environment.
`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`.
`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`.
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).
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).
```nix
{ lib, stdenv, buildEnv }:
@ -101,7 +112,9 @@ stdenv.mkDerivation ({
} // rest)
```
`pkgs.mkShell { ... }` is a special derivation (Nix package). Its `name`, `buildInputs`, and other parameters are customizable, and `shellHook` is a special parameter that will be executed when `nix develop` enters the environment.
`pkgs.mkShell { ... }` is a special derivation (Nix package). Its `name`, `buildInputs`,
and other parameters are customizable, and `shellHook` is a special parameter that will be
executed when `nix develop` enters the environment.
Here is a `flake.nix` that defines a development environment with Node.js 18 installed:
@ -138,11 +151,14 @@ 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`), the current version of nodejs will be outputted, and now you can use `node` `pnpm` `yarn` seamlessly.
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 outputted, and now you can use `node` `pnpm` `yarn` seamlessly.
## Using zsh/fish/... instead of bash
`pkgs.mkShell` uses `bash` by default, but you can also use `zsh` or `fish` by add `exec <your-shell>` into `shellHook`.
`pkgs.mkShell` uses `bash` by default, but you can also use `zsh` or `fish` by add
`exec <your-shell>` into `shellHook`.
Here is an example:
@ -185,11 +201,15 @@ With the above configuration, `nix develop` will enter the REPL environment of n
## Creating a Development Environment with `pkgs.runCommand`
The derivation created by `pkgs.mkShell` cannot be used directly, but must be accessed via `nix develop`.
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.
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`.
Using `mkDerivation` directly is a bit cumbersome, and Nixpkgs provides some simpler
functions to help us create such wrappers, such as `pkgs.runCommand`.
Example:
@ -229,11 +249,15 @@ Example:
}
```
Then execute `nix run .#dev` or `nix shell .#dev --command 'dev-shell'`, you will enter a nushell session, where you can use the `node` `pnpm` command normally, and the node version is 20.
Then execute `nix run .#dev` or `nix shell .#dev --command 'dev-shell'`, you will enter a
nushell session, where you can use the `node` `pnpm` command normally, and the node
version is 20.
The wrapper generated in this way is an executable file, which does not actually depend on the `nix run` or `nix shell` command.
The wrapper generated in this way is an executable file, which does not actually depend on
the `nix run` or `nix shell` command.
For example, we can directly install this wrapper through NixOS's `environment.systemPackages`, and then execute it directly:
For example, we can directly install this wrapper through NixOS's
`environment.systemPackages`, and then execute it directly:
```nix
{pkgs, lib, ...}{
@ -260,7 +284,10 @@ For example, we can directly install this wrapper through NixOS's `environment.s
}
```
Add the above configuration to any NixOS Module, then deploy it with `sudo nixos-rebuild switch`, and you can enter the development environment directly with the `dev-shell` command, which is the special feature of `pkgs.runCommand` compared to `pkgs.mkShell`.
Add the above configuration to any NixOS Module, then deploy it with
`sudo nixos-rebuild switch`, and you can enter the development environment directly with
the `dev-shell` command, which is the special feature of `pkgs.runCommand` compared to
`pkgs.mkShell`.
Related source code:
@ -269,7 +296,8 @@ Related source code:
## 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`:
Now let's take a look at `nix develop`, first read the help document output by
`nix develop --help`:
```
Name
@ -280,20 +308,25 @@ Synopsis
# ......
```
It tells us that `nix develop` accepts a parameter `installable`, which means that we can enter the development environment of any installable Nix package through it, not just the environment created by `pkgs.mkShell`.
It tells us that `nix develop` accepts a parameter `installable`, which means that we can
enter the development environment of any installable Nix package through it, not just the
environment created by `pkgs.mkShell`.
By default, `nix develop` will try to use the following attributes in the flake outputs:
- `devShells.<system>.default`
- `packages.<system>.default`
If we use `nix develop /path/to/flake#<name>` to specify the flake package address and flake output name, then `nix develop` will try the following attributes in the flake outputs:
If we use `nix develop /path/to/flake#<name>` to specify the flake package address and
flake output name, then `nix develop` will try the following attributes in the flake
outputs:
- `devShells.<system>.<name>`
- `packages.<system>.<name>`
- `legacyPackages.<system>.<name>`
Now let's try it out. First, test it to confirm that We don't have `c++` `g++` and other compilation-related commands in the current environment:
Now let's try it out. First, test it to confirm that We don't have `c++` `g++` and other
compilation-related commands in the current environment:
```shell
ryan in 🌐 aquamarine in ~
@ -331,11 +364,13 @@ This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```
We can see that the `CXX` environment variable have been set, and the `c++` `g++` and other commands can be used normally now.
We can see that the `CXX` environment variable have been set, and the `c++` `g++` and
other commands can be used normally now.
In addition, we can also call every build phase of the `hello` package normally:
> The default execution order of all build phases of a Nix package is: `$prePhases unpackPhase patchPhase $preConfigurePhases configurePhase $preBuildPhases buildPhase checkPhase $preInstallPhases installPhase fixupPhase installCheckPhase $preDistPhases distPhase $postPhases`
> The default execution order of all build phases of a Nix package is:
> `$prePhases unpackPhase patchPhase $preConfigurePhases configurePhase $preBuildPhases buildPhase checkPhase $preInstallPhases installPhase fixupPhase installCheckPhase $preDistPhases distPhase $postPhases`
```shell
# unpack source code
@ -393,11 +428,13 @@ ryan in 🌐 aquamarine in /tmp/xxx/hello-2.12.1 via C v12.3.0-gcc via ❄️ i
Hello, world!
```
This usage is mainly used to debug the build process of a Nix package, or to execute some commands in the build environment of a Nix package.
This usage is mainly used to debug the build process of a Nix package, or to execute some
commands in the build environment of a Nix package.
## `nix build`
The `nix build` command is used to build a software package and creates a symbolic link named `result` in the current directory, which points to the build result.
The `nix build` command is used to build a software package and creates a symbolic link
named `result` in the current directory, which points to the build result.
Here's an example:
@ -434,16 +471,21 @@ nix build "nixpkgs#ponysay"
## Using `nix profile` to manage development environments and entertainment environments
`nix develop` is a tool for creating and managing multiple user environments, and switch to different environments when needed.
`nix develop` is a tool for creating and managing multiple user environments, and switch
to different environments when needed.
Unlike `nix develop`, `nix profile` manages the user's system environment, instead of creating a temporary shell environment.
So it's more compatible with Jetbrains IDE / VSCode and other IDEs, and won't have the problem of not being able to use the configured development environment in the IDE.
Unlike `nix develop`, `nix profile` manages the user's system environment, instead of
creating a temporary shell environment. So it's more compatible with Jetbrains IDE /
VSCode and other IDEs, and won't have the problem of not being able to use the configured
development environment in the IDE.
TODO
## Other Commands
There are other commands like `nix flake init`, which you can explore in [New Nix Commands][New Nix Commands]. For more detailed information, please refer to the documentation.
There are other commands like `nix flake init`, which you can explore in [New Nix
Commands][New Nix Commands]. For more detailed information, please refer to the
documentation.
## References

View file

@ -105,10 +105,14 @@ An example of kernel development with `flake.nix`.
}
```
With the above `flake.nix`, I can enter the kernel build environment with `nix develop .#kernel`, and then use `unpackPhase` to unpack the kernel source code and cd into it.
But I can't use `make menuconfig` to configure the kernel, because the `ncurses` package is missing in this environment.
With the above `flake.nix`, I can enter the kernel build environment with
`nix develop .#kernel`, and then use `unpackPhase` to unpack the kernel source code and cd
into it. But I can't use `make menuconfig` to configure the kernel, because the `ncurses`
package is missing in this environment.
To solve this problem, I add a `fhs` environment to install the `ncurses` package and other necessary packages, and then I can use `nix develop .#fhs` to enter this environment and use `make menuconfig` to configure the kernel.
To solve this problem, I add a `fhs` environment to install the `ncurses` package and
other necessary packages, and then I can use `nix develop .#fhs` to enter this environment
and use `make menuconfig` to configure the kernel.
## References

View file

@ -1,6 +1,7 @@
# Packging 101
WIP work in progress, please refer to the following reference documents to learn Nix packaging.
WIP work in progress, please refer to the following reference documents to learn Nix
packaging.
## 参考文档
@ -10,11 +11,15 @@ WIP work in progress, please refer to the following reference documents to learn
- [languages-frameworks - Nixpkgs Manual](https://github.com/NixOS/nixpkgs/tree/nixos-unstable/doc/languages-frameworks)
- [Wrapping packages - NixOS Cookbook](https://nixos.wiki/wiki/Nix_Cookbook#Wrapping_packages)
- Useful tools:
- [nurl](https://github.com/nix-community/nurl): Generate Nix fetcher calls from repository URLs
- [nix-init](https://github.com/nix-community/nix-init): Generate Nix packages from URLs with hash prefetching, dependency inference, license detection, and more
- [nurl](https://github.com/nix-community/nurl): Generate Nix fetcher calls from
repository URLs
- [nix-init](https://github.com/nix-community/nix-init): Generate Nix packages from URLs
with hash prefetching, dependency inference, license detection, and more
- 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/setup-hooks/make-wrapper.sh](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/setup-hooks/make-wrapper.sh)
- FHS related
- [pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix): `pkgs.buildFHSEnvBubblewrap`
- [pkgs/build-support/build-fhsenv-chroot/default.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix): `pkgs.buildFHSEnvChroot`
- [pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix):
`pkgs.buildFHSEnvBubblewrap`
- [pkgs/build-support/build-fhsenv-chroot/default.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix):
`pkgs.buildFHSEnvChroot`

View file

@ -2,45 +2,104 @@
## What is the difference between NixOS rollback capability and btrfs/zfs system snapshot rollback?
The difference lies in the nature of the snapshots. System snapshots created with btrfs/zfs does not contain the 'knowledge' of how to build this snapshot from scratch, it is **uninterpretable**, and its content is strongly correlated with the current hardware environment, making it difficult to reproduce on other machines.
The difference lies in the nature of the snapshots. System snapshots created with
btrfs/zfs does not contain the 'knowledge' of how to build this snapshot from scratch, it
is **uninterpretable**, and its content is strongly correlated with the current hardware
environment, making it difficult to reproduce on other machines.
On the other hand, NixOS configuration is a piece of "knowledge" that can build an identical OS from scratch. It is **explainable** and can be automatically built with just a few simple commands. The NixOS configuration serves as documentation of all the changes made to your OS and is also used to automatically build the OS itself.
On the other hand, NixOS configuration is a piece of "knowledge" that can build an
identical OS from scratch. It is **explainable** and can be automatically built with just
a few simple commands. The NixOS configuration serves as documentation of all the changes
made to your OS and is also used to automatically build the OS itself.
The NixOS configuration file is like the **source code** of a program. As long as the source code is intact, it is easy to modify, review, or rebuild an identical program. In contrast, system snapshots are like compiled binary programs derived from source code, making it much more difficult to modify or review them. Moreover, snapshots are large in size, making sharing or migrating them more costly compared to source code.
The NixOS configuration file is like the **source code** of a program. As long as the
source code is intact, it is easy to modify, review, or rebuild an identical program. In
contrast, system snapshots are like compiled binary programs derived from source code,
making it much more difficult to modify or review them. Moreover, snapshots are large in
size, making sharing or migrating them more costly compared to source code.
However, this doesn't mean that NixOS eliminates the need for system snapshots. As mentioned in Chapter 1 of this book, NixOS can only guarantee reproducibility for everything declared in the declarative configuration. Other aspects of the system that are not covered by the declarative configuration, such as dynamic data in MySQL/PostgreSQL, user-uploaded files, system logs, videos, music, and images in user home directories, still require system snapshots or other means of backup.
However, this doesn't mean that NixOS eliminates the need for system snapshots. As
mentioned in Chapter 1 of this book, NixOS can only guarantee reproducibility for
everything declared in the declarative configuration. Other aspects of the system that are
not covered by the declarative configuration, such as dynamic data in MySQL/PostgreSQL,
user-uploaded files, system logs, videos, music, and images in user home directories,
still require system snapshots or other means of backup.
## How does Nix compare to traditional system management tools like Ansible?
Nix is not only used for managing desktop environments but is also widely employed for batch management of cloud servers. The official [NixOps](https://github.com/NixOS/nixops) from the NixOS community and [colmena](https://github.com/zhaofengli/colmena) developed by the community are tools specifically designed for this use case.
Nix is not only used for managing desktop environments but is also widely employed for
batch management of cloud servers. The official [NixOps](https://github.com/NixOS/nixops)
from the NixOS community and [colmena](https://github.com/zhaofengli/colmena) developed by
the community are tools specifically designed for this use case.
When compared to widely used traditional tools like Ansible, Nix has the following main advantages:
When compared to widely used traditional tools like Ansible, Nix has the following main
advantages:
1. One of the biggest problems with this Ansible is that each deployment is based on incremental changes to the current state of the system. The current state of the system, like the snapshots mentioned above, is not interpretable and is difficult to reproduce. NixOS declares the target state of the system through its configuration files, so that the deployment result is independent of the current state of the system, and repeated deployments will not cause any problems.
2. Nix Flakes uses a version lock file `flake.lock` to lock the hash value, version number, data source and other information of all dependencies, which greatly improves the reproducibility of the system. Traditional tools like Ansible don't have this feature, so they're not very reproducible.
1. This is why Docker is so popular - it provides, at a fraction of the cost, a **reproducible system environment on a wide range of machines** that traditional Ops tools like Ansible don't.
3. Nix provides a high degree of ease of system customization by shielding the underlying implementation details with a layer of declarative abstraction so that users only need to care about their core requirements. Tools like Ansible have much weaker abstractions.
1. If you've ever used a declarative configuration tool like terraform/kubernetes, this should be easy to understand. The more complex the requirements, the greater the benefit of declarative configuration.
1. One of the biggest problems with this Ansible is that each deployment is based on
incremental changes to the current state of the system. The current state of the
system, like the snapshots mentioned above, is not interpretable and is difficult to
reproduce. NixOS declares the target state of the system through its configuration
files, so that the deployment result is independent of the current state of the system,
and repeated deployments will not cause any problems.
2. Nix Flakes uses a version lock file `flake.lock` to lock the hash value, version
number, data source and other information of all dependencies, which greatly improves
the reproducibility of the system. Traditional tools like Ansible don't have this
feature, so they're not very reproducible.
1. This is why Docker is so popular - it provides, at a fraction of the cost, a
**reproducible system environment on a wide range of machines** that traditional Ops
tools like Ansible don't.
3. Nix provides a high degree of ease of system customization by shielding the underlying
implementation details with a layer of declarative abstraction so that users only need
to care about their core requirements. Tools like Ansible have much weaker
abstractions.
1. If you've ever used a declarative configuration tool like terraform/kubernetes, this
should be easy to understand. The more complex the requirements, the greater the
benefit of declarative configuration.
## What are the advantages of Nix compared to Docker container technology?
Nix and container technologies like Docker do have overlapping use cases, such as:
1. Many people use Nix to manage development and build environments, as discussed in this book. On the other hand, technologies like [Dev Containers](https://github.com/devcontainers/spec), which build development environments based on containers, are also popular.
2. The DevOps/SRE field is currently dominated by container technologies based on Dockerfiles. Commonly used distributions like Ubuntu/Debian are frequently used within containers, and there are also mature options available for the host machine. In this context, what significant advantages do switching to NixOS offer?
1. Many people use Nix to manage development and build environments, as discussed in this
book. On the other hand, technologies like
[Dev Containers](https://github.com/devcontainers/spec), which build development
environments based on containers, are also popular.
2. The DevOps/SRE field is currently dominated by container technologies based on
Dockerfiles. Commonly used distributions like Ubuntu/Debian are frequently used within
containers, and there are also mature options available for the host machine. In this
context, what significant advantages do switching to NixOS offer?
Regarding the first point of "managing the development and build environments," Nix provides a development environment experience that closely resembles working directly on the host machine. This offers several advantages over Dev Containers, as outlined below:
Regarding the first point of "managing the development and build environments," Nix
provides a development environment experience that closely resembles working directly on
the host machine. This offers several advantages over Dev Containers, as outlined below:
1. Nix does not use namespaces for filesystem and network isolation, allowing easy interaction with the host machine's filesystem (including /dev for external devices) and network environment within the Nix-created development environment. In contrast, containers require various mappings to enable communication between the container and the host machine's filesystem, which can sometimes lead to file permission issues.
2. Due to the absence of strong isolation, Nix development environments have no issues supporting GUI applications. Running GUI programs within this environment is as seamless as running them in the system environment.
1. Nix does not use namespaces for filesystem and network isolation, allowing easy
interaction with the host machine's filesystem (including /dev for external devices)
and network environment within the Nix-created development environment. In contrast,
containers require various mappings to enable communication between the container and
the host machine's filesystem, which can sometimes lead to file permission issues.
2. Due to the absence of strong isolation, Nix development environments have no issues
supporting GUI applications. Running GUI programs within this environment is as
seamless as running them in the system environment.
In other words, Nix provides a development experience that is closest to the host machine, with no strong isolation. Developers can use familiar development and debugging tools in this environment, and their past development experience can be seamlessly migrated. On the other hand, if Dev Containers are used, developers may encounter various issues related to filesystem communication, network environment, user permissions, and the inability to use GUI debugging tools due to strong isolation.
In other words, Nix provides a development experience that is closest to the host machine,
with no strong isolation. Developers can use familiar development and debugging tools in
this environment, and their past development experience can be seamlessly migrated. On the
other hand, if Dev Containers are used, developers may encounter various issues related to
filesystem communication, network environment, user permissions, and the inability to use
GUI debugging tools due to strong isolation.
If we decide to use Nix to manage all development environments, then building Docker containers based on Nix would provide the highest level of consistency. Additionally, adopting a unified technological architecture for all environments significantly reduces infrastructure maintenance costs. This answers the second point mentioned earlier: when managing development environments with Nix as a prerequisite, using NixOS for container base images and cloud servers offers distinct advantages.
If we decide to use Nix to manage all development environments, then building Docker
containers based on Nix would provide the highest level of consistency. Additionally,
adopting a unified technological architecture for all environments significantly reduces
infrastructure maintenance costs. This answers the second point mentioned earlier: when
managing development environments with Nix as a prerequisite, using NixOS for container
base images and cloud servers offers distinct advantages.
## error: collision between `...` and `...`
This error occurs when you installed two packages that depend on the same library but with different versions in the same profile(home module or nixos module).
This error occurs when you installed two packages that depend on the same library but with
different versions in the same profile(home module or nixos module).
For example, if you have the following configuration:
@ -78,9 +137,12 @@ and `/nix/store/370s8inz4fc9k9lqk4qzj5vyr60q166w-python3-3.11.6-env/lib/python3.
Here are some solutions:
1. Split the two packages into two different **profiles**. For example, you can install `lldb` via `environment.systemPackages` and `python311` via `home.packages`.
2. Different versions of Python3 are treated as different packages, so you can change your custom Python3 version to `python310` to avoid the conflict.
3. Use `override` to override the version of the library used by the package to be consistent with the version used by the other package.
1. Split the two packages into two different **profiles**. For example, you can install
`lldb` via `environment.systemPackages` and `python311` via `home.packages`.
2. Different versions of Python3 are treated as different packages, so you can change your
custom Python3 version to `python310` to avoid the conflict.
3. Use `override` to override the version of the library used by the package to be
consistent with the version used by the other package.
```nix
{

View file

@ -7,7 +7,9 @@ titleTemplate: "Home Page"
hero:
name: "NixOS & Flakes Book"
text: "An unofficial book for beginners"
tagline: Want to know NixOS & Flakes in detail? Looking for a beginner-friendly tutorial? Then you've come to the right place!
tagline:
Want to know NixOS & Flakes in detail? Looking for a beginner-friendly tutorial? Then
you've come to the right place!
image:
src: /logo.png
alt: NixOS Flakes

View file

@ -3,17 +3,33 @@
## Advantages of NixOS
- **Declarative Configuration, OS as Code**
- NixOS uses declarative configuration to manage the entire system environment. These configurations can be managed directly with Git, allowing the system to be restored to any historical state as long as the configuration files are preserved (provided the desired states are declared in the Nix configuration).
- Nix Flakes further enhance reproducibility by utilizing a `flake.lock` version lock file, which records the data source addresses, hash values, and other relevant information for all dependencies. This design greatly improves Nix's reproducibility and ensures consistent build results. It draws inspiration from package management designs in programming languages like Cargo and npm.
- NixOS uses declarative configuration to manage the entire system environment. These
configurations can be managed directly with Git, allowing the system to be restored to
any historical state as long as the configuration files are preserved (provided the
desired states are declared in the Nix configuration).
- Nix Flakes further enhance reproducibility by utilizing a `flake.lock` version lock
file, which records the data source addresses, hash values, and other relevant
information for all dependencies. This design greatly improves Nix's reproducibility
and ensures consistent build results. It draws inspiration from package management
designs in programming languages like Cargo and npm.
- **Highly Convenient System Customization Capability**
- With just a few configuration changes, various components of the system can be easily replaced. Nix encapsulates all the underlying complex operations within Nix packages, providing users with a concise set of declarative parameters.
- Modifications are safe and switching between different desktop environments (such as GNOME, KDE, i3, and sway) is straightforward, with minimal pitfalls.
- With just a few configuration changes, various components of the system can be easily
replaced. Nix encapsulates all the underlying complex operations within Nix packages,
providing users with a concise set of declarative parameters.
- Modifications are safe and switching between different desktop environments (such as
GNOME, KDE, i3, and sway) is straightforward, with minimal pitfalls.
- **Rollback Capability**
- It is possible to roll back to any previous system state, and NixOS even includes all old versions in the boot options by default, ensuring the ability to easily revert changes. Consequently, Nix is regarded as one of the most stable package management approaches.
- It is possible to roll back to any previous system state, and NixOS even includes all
old versions in the boot options by default, ensuring the ability to easily revert
changes. Consequently, Nix is regarded as one of the most stable package management
approaches.
- **No Dependency Conflict Issues**
- Each software package in Nix has a unique hash, which is incorporated into its installation path, allowing multiple versions to coexist.
- Each software package in Nix has a unique hash, which is incorporated into its
installation path, allowing multiple versions to coexist.
- **The community is active, with a diverse range of third-party projects**
- The official package repository, nixpkgs, has numerous contributors, and many people share their Nix configurations. Exploring the NixOS ecosystem is an exciting experience, akin to discovering a new continent.
- The official package repository, nixpkgs, has numerous contributors, and many people
share their Nix configurations. Exploring the NixOS ecosystem is an exciting
experience, akin to discovering a new continent.
<figure>
<img src="/nixos-bootloader.avif">
@ -31,23 +47,51 @@
## Disadvantages of NixOS
- **High Learning Curve**:
- Achieving complete reproducibility and avoiding pitfalls associated with improper usage requires learning about Nix's entire design and managing the system declaratively, rather than blindly using commands like `nix-env -i` (similar to `apt-get install`).
- Achieving complete reproducibility and avoiding pitfalls associated with improper
usage requires learning about Nix's entire design and managing the system
declaratively, rather than blindly using commands like `nix-env -i` (similar to
`apt-get install`).
- **Disorganized Documentation**:
- Currently, Nix Flakes remains an experimental feature, and there is limited documentation specifically focused on it. Most Nix community documentation primarily covers the classic `/etc/nixos/configuration.nix`. If you want to start learning directly from Nix Flakes(`flake.nix`), you need to refer to a significant amount of outdated documentation and extract the relevant information. Additionally, some core features of Nix, such as `imports` and the Nixpkgs Module System, lack detailed official documentation, requiring resorting to source code analysis.
- Currently, Nix Flakes remains an experimental feature, and there is limited
documentation specifically focused on it. Most Nix community documentation primarily
covers the classic `/etc/nixos/configuration.nix`. If you want to start learning
directly from Nix Flakes(`flake.nix`), you need to refer to a significant amount of
outdated documentation and extract the relevant information. Additionally, some core
features of Nix, such as `imports` and the Nixpkgs Module System, lack detailed
official documentation, requiring resorting to source code analysis.
- **Increased Disk Space Usage**:
- To ensure the ability to roll back the system at any time, Nix retains all historical environments by default, resulting in increased disk space usage.
- While this additional space usage may not be a concern on desktop computers, it can become problematic on resource-constrained cloud servers.
- To ensure the ability to roll back the system at any time, Nix retains all historical
environments by default, resulting in increased disk space usage.
- While this additional space usage may not be a concern on desktop computers, it can
become problematic on resource-constrained cloud servers.
- **Obscure Error Messages**:
- Due to the [complex merging algorithm](https://discourse.nixos.org/t/best-resources-for-learning-about-the-nixos-module-system/1177/4) of the [Nixpkgs module system](../other-usage-of-flakes/module-system.md), NixOS error messages are quite poor. In many cases, regardless of whether you add `--show-trace`, it will only tell you that there is an error in the code (the most common and confusing error message is [Infinite recursion encountered](https://discourse.nixos.org/t/infinite-recursion-encountered-by-making-module-configurable/23508/2)), but where exactly is the error? The type system says it doesn't know, so you have to find it yourself. In my experience, **the simplest and most effective way to deal with these meaningless error messages is to use a "binary search" to gradually restore the code**.
- Due to the
[complex merging algorithm](https://discourse.nixos.org/t/best-resources-for-learning-about-the-nixos-module-system/1177/4)
of the [Nixpkgs module system](../other-usage-of-flakes/module-system.md), NixOS error
messages are quite poor. In many cases, regardless of whether you add `--show-trace`,
it will only tell you that there is an error in the code (the most common and
confusing error message is
[Infinite recursion encountered](https://discourse.nixos.org/t/infinite-recursion-encountered-by-making-module-configurable/23508/2)),
but where exactly is the error? The type system says it doesn't know, so you have to
find it yourself. In my experience, **the simplest and most effective way to deal with
these meaningless error messages is to use a "binary search" to gradually restore the
code**.
- This problem is probably the biggest pain point of NixOS at the moment.
- **More Complex Underlying Implementation**:
- Nix's declarative abstraction introduces additional complexity in the underlying code compared to similar code in traditional imperative tools.
- This complexity increases implementation difficulty and makes it more challenging to make custom modifications at the lower level. However, this burden primarily falls on Nix package maintainers, as regular users have limited exposure to the underlying complexities, reducing their burden.
- Nix's declarative abstraction introduces additional complexity in the underlying code
compared to similar code in traditional imperative tools.
- This complexity increases implementation difficulty and makes it more challenging to
make custom modifications at the lower level. However, this burden primarily falls on
Nix package maintainers, as regular users have limited exposure to the underlying
complexities, reducing their burden.
## Summary
Overall, I believe that NixOS is suitable for developers with a certain level of Linux usage experience and programming knowledge who desire greater control over their systems.
Overall, I believe that NixOS is suitable for developers with a certain level of Linux
usage experience and programming knowledge who desire greater control over their systems.
I do not recommend newcomers without any Linux usage experience to dive directly into NixOS, as it may lead to a frustrating journey.
I do not recommend newcomers without any Linux usage experience to dive directly into
NixOS, as it may lead to a frustrating journey.
> If you have more questions about NixOS, you can refer to the last chapter of this book, [FAQ](../faq/).
> If you have more questions about NixOS, you can refer to the last chapter of this book,
> [FAQ](../faq/).

View file

@ -2,34 +2,77 @@
# Introduction to Nix & NixOS
Nix is a declarative package manager that enables users to declare the desired system state in configuration files (declarative configuration), and it takes responsibility for achieving that state.
Nix is a declarative package manager that enables users to declare the desired system
state in configuration files (declarative configuration), and it takes responsibility for
achieving that state.
> In simple terms, "declarative configuration" means that users only need to declare the desired outcome. For instance, if you declare that you want to replace the i3 window manager with sway, Nix will assist you in achieving that goal. You don't have to worry about the underlying details, such as which packages sway requires for installation, which i3-related packages need to be uninstalled, or the necessary adjustments to system configuration and environment variables for sway. Nix automatically handles these details for the user (provided that the Nix packages related to sway and i3 are properly designed).
> In simple terms, "declarative configuration" means that users only need to declare the
> desired outcome. For instance, if you declare that you want to replace the i3 window
> manager with sway, Nix will assist you in achieving that goal. You don't have to worry
> about the underlying details, such as which packages sway requires for installation,
> which i3-related packages need to be uninstalled, or the necessary adjustments to system
> configuration and environment variables for sway. Nix automatically handles these
> details for the user (provided that the Nix packages related to sway and i3 are properly
> designed).
NixOS, a Linux distribution built on top of the Nix package manager, can be described as "OS as Code." It employs declarative Nix configuration files to describe the entire state of the operating system.
NixOS, a Linux distribution built on top of the Nix package manager, can be described as
"OS as Code." It employs declarative Nix configuration files to describe the entire state
of the operating system.
An operating system consists of various software packages, configuration files, and text/binary data, all of which represent the current state of the system. Declarative configuration can manage only the static portion of this state. Dynamic data, such as PostgreSQL, MySQL, or MongoDB data, cannot be effectively managed through declarative configuration (it is not feasible to delete all new PostgreSQL data that is not declared in the configuration during each deployment).
Therefore, **NixOS primarily focuses on managing the static portion of the system state in a declarative manner**.
Dynamic data, along with the contents in the user's home directory, remain unaffected by NixOS when rolling back to a previous generation.
An operating system consists of various software packages, configuration files, and
text/binary data, all of which represent the current state of the system. Declarative
configuration can manage only the static portion of this state. Dynamic data, such as
PostgreSQL, MySQL, or MongoDB data, cannot be effectively managed through declarative
configuration (it is not feasible to delete all new PostgreSQL data that is not declared
in the configuration during each deployment). Therefore, **NixOS primarily focuses on
managing the static portion of the system state in a declarative manner**. Dynamic data,
along with the contents in the user's home directory, remain unaffected by NixOS when
rolling back to a previous generation.
Although we cannot achieve complete system reproducibility, the `/home` directory, being an important user directory, contains many necessary configuration files - [Dotfiles](https://wiki.archlinux.org/title/Dotfiles). A significant community project called [home-manager](https://github.com/nix-community/home-manager) is designed to manage user-level packages and configuration files within the user's home directory.
Although we cannot achieve complete system reproducibility, the `/home` directory, being
an important user directory, contains many necessary configuration files -
[Dotfiles](https://wiki.archlinux.org/title/Dotfiles). A significant community project
called [home-manager](https://github.com/nix-community/home-manager) is designed to manage
user-level packages and configuration files within the user's home directory.
Due to Nix's features, such as being declarative and reproducible, Nix is not limited to managing desktop environments but is also extensively used for managing development environments, compilation environments, cloud virtual machines, and container image construction. [NixOps](https://github.com/NixOS/nixops) (an official Nix project) and [colmena](https://github.com/zhaofengli/colmena) (a community project) are both operational tools based on Nix.
Due to Nix's features, such as being declarative and reproducible, Nix is not limited to
managing desktop environments but is also extensively used for managing development
environments, compilation environments, cloud virtual machines, and container image
construction. [NixOps](https://github.com/NixOS/nixops) (an official Nix project) and
[colmena](https://github.com/zhaofengli/colmena) (a community project) are both
operational tools based on Nix.
## Why NixOS?
I first learned about the Nix package manager several years ago. It utilizes the Nix language to describe system configuration. NixOS, the Linux distribution built on top of it, allows for rolling back the system to any previous state (although only the state declared in Nix configuration files can be rolled back). While it sounded impressive, I found it troublesome to learn a new language and write code to install packages, so I didn't pursue it at the time.
I first learned about the Nix package manager several years ago. It utilizes the Nix
language to describe system configuration. NixOS, the Linux distribution built on top of
it, allows for rolling back the system to any previous state (although only the state
declared in Nix configuration files can be rolled back). While it sounded impressive, I
found it troublesome to learn a new language and write code to install packages, so I
didn't pursue it at the time.
However, I recently encountered numerous environmental issues while using EndeavourOS, and resolving them consumed a significant amount of my energy, leaving me exhausted. Upon careful consideration, I realized that the lack of version control and rollback mechanisms in EndeavourOS prevented me from restoring the system when problems arose.
However, I recently encountered numerous environmental issues while using EndeavourOS, and
resolving them consumed a significant amount of my energy, leaving me exhausted. Upon
careful consideration, I realized that the lack of version control and rollback mechanisms
in EndeavourOS prevented me from restoring the system when problems arose.
That's when I decided to switch to NixOS.
To my delight, NixOS has exceeded my expectations. The most astonishing aspect is that I can now restore my entire i3 environment and all my commonly used packages on a fresh NixOS host with just one command `sudo nixos-rebuild switch --flake .`. It's truly fantastic!
To my delight, NixOS has exceeded my expectations. The most astonishing aspect is that I
can now restore my entire i3 environment and all my commonly used packages on a fresh
NixOS host with just one command `sudo nixos-rebuild switch --flake .`. It's truly
fantastic!
The rollback capability and reproducibility of NixOS has instilled a great deal of confidence in me—I no longer fear breaking the system. I've even ventured into experimenting with new things on NixOS, such as the hyprland compositor. Previously, on EndeavourOS, I wouldn't have dared to tinker with such novel compositors, as any system mishaps would have entailed significant manual troubleshooting using various workarounds.
The rollback capability and reproducibility of NixOS has instilled a great deal of
confidence in me—I no longer fear breaking the system. I've even ventured into
experimenting with new things on NixOS, such as the hyprland compositor. Previously, on
EndeavourOS, I wouldn't have dared to tinker with such novel compositors, as any system
mishaps would have entailed significant manual troubleshooting using various workarounds.
As I get more and more involved with NixOS and Nix, I find it also very suitable for synchronously managing the configuration of multiple hosts.
Currently my personal [nix-config](https://github.com/ryan4yin/nix-config) synchronously manages the configuration of many hosts:
As I get more and more involved with NixOS and Nix, I find it also very suitable for
synchronously managing the configuration of multiple hosts. Currently my personal
[nix-config](https://github.com/ryan4yin/nix-config) synchronously manages the
configuration of many hosts:
- Desktop computers
- 1 Macbook Pro 2020 (Intel amd64).
@ -39,7 +82,9 @@ Currently my personal [nix-config](https://github.com/ryan4yin/nix-config) synch
- 3 NixOS virtual machines (amd64).
- Several development boards for aarch64 and riscv64.
The development environment of three desktop computers is managed by Home Manager,
the main configuration is completely shared, and the configuration modified on any host can be seamlessly synchronized to other hosts through Git.
The development environment of three desktop computers is managed by Home Manager, the
main configuration is completely shared, and the configuration modified on any host can be
seamlessly synchronized to other hosts through Git.
Nix almost completely shielded me from the differences between OS and architecture at the bottom of the three machines, and the experience was very slippery!
Nix almost completely shielded me from the differences between OS and architecture at the
bottom of the three machines, and the experience was very slippery!

View file

@ -3,11 +3,17 @@
Nix can be installed in various ways:
1. As a package manager on macOS, Linux, or WSL.
2. As the system environment manager on NixOS, a Linux distribution that utilizes Nix for system management.
2. As the system environment manager on NixOS, a Linux distribution that utilizes Nix for
system management.
This book primarily focuses on the usage of NixOS and Flakes. Therefore, we will skip content that pertains solely to Nix(such as installation on macOS, Linux, or WSL).
This book primarily focuses on the usage of NixOS and Flakes. Therefore, we will skip
content that pertains solely to Nix(such as installation on macOS, Linux, or WSL).
The installation process of NixOS is straightforward, but we won't delve into the specifics here. For more information, please visit the official download site at <https://nixos.org/download.html>.
The installation process of NixOS is straightforward, but we won't delve into the
specifics here. For more information, please visit the official download site at
<https://nixos.org/download.html>.
> If you're using macOS, [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter) may be a good starting point for you,
> you can learn how to use Nix with this book and take nix-darwin-kickstarter as a start point to build your own Nix configuration.
> If you're using macOS,
> [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter)
> may be a good starting point for you, you can learn how to use Nix with this book and
> take nix-darwin-kickstarter as a start point to build your own Nix configuration.

View file

@ -2,44 +2,90 @@
## What is Nix Cache Server {#what-is-nix-cache-server}
Nix provides an official cache server, [https://cache.nixos.org](https://cache.nixos.org), which caches build results for all packages in nixpkgs under commonly used CPU architectures. When you execute Nix build commands locally, if Nix finds a corresponding cache on the server, it directly downloads the cached file, skipping the time-consuming local build process and significantly improving build speed.
Nix provides an official cache server, [https://cache.nixos.org](https://cache.nixos.org),
which caches build results for all packages in nixpkgs under commonly used CPU
architectures. When you execute Nix build commands locally, if Nix finds a corresponding
cache on the server, it directly downloads the cached file, skipping the time-consuming
local build process and significantly improving build speed.
## Why Add Custom Cache Servers {#why-add-custom-cache-servers}
> Note: The methods introduced here can only accelerate the download of packages; many `inputs` data sources will still be fetched from GitHub. Also, if the cache is not found, local builds will be executed, which typically requires downloading source code and building dependencies from GitHub or somewhere else, which may make it slow. To completely address the speed issue, it is still recommended to use solutions such as a transparent proxy running on your router or local machine.
> Note: The methods introduced here can only accelerate the download of packages; many
> `inputs` data sources will still be fetched from GitHub. Also, if the cache is not
> found, local builds will be executed, which typically requires downloading source code
> and building dependencies from GitHub or somewhere else, which may make it slow. To
> completely address the speed issue, it is still recommended to use solutions such as a
> transparent proxy running on your router or local machine.
Two reasons:
1. Add cache servers for some third-party projects, such as the nix-community cache server [https://nix-community.cachix.org](https://nix-community.cachix.org), which can significantly improve the build speed of these third-party projects.
1. Add cache servers for some third-party projects, such as the nix-community cache server
[https://nix-community.cachix.org](https://nix-community.cachix.org), which can
significantly improve the build speed of these third-party projects.
2. Adding a mirrored cache server to accelerate downloads.
1. The access speed of the official cache server in China is slow. Without a local global proxy, it is almost unusable. Adding Chinese Nix cache mirrors like ustc/sjtu/tuna can alleviate this issue.
1. The access speed of the official cache server in China is slow. Without a local
global proxy, it is almost unusable. Adding Chinese Nix cache mirrors like
ustc/sjtu/tuna can alleviate this issue.
## How to Add Custom Cache Servers {#how-to-add-custom-cache-servers}
In Nix, you can configure cache servers using the following options:
1. [substituters](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-substituters): It is a string list, and each string is the address of a cache server. Nix will attempt to find caches from these servers in the order specified in the list.
2. [trusted-public-keys](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-public-keys): To prevent malicious attacks, The [require-sigs](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-require-sigs) option is enabled by default. Only caches with signatures that can be verified by any public key in `trusted-public-keys` will be used by Nix. Therefore, you need to add the public key corresponding to the `substituters` in `trusted-public-keys`.
1. cache mirror's data are directly synchronized from the official cache server. Therefore, their public keys are the same as those of the official cache server, and you can use the public key of the official cache server without additional configuration.
2. This entirely trust-based public key verification mechanism transfers the security responsibility to users. If users want to use a third-party cache server to speed up the build process of a certain library, they must take on the corresponding security risks and decide whether to add the public key of that cache server to `trusted-public-keys`. To completely solve this trust issue, Nix has introduced the experimental feature [ca-derivations](https://nixos.wiki/wiki/Ca-derivations), which does not depend on `trusted-public-keys` for signature verification. Interested users can explore it further.
1. [substituters](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-substituters):
It is a string list, and each string is the address of a cache server. Nix will attempt
to find caches from these servers in the order specified in the list.
2. [trusted-public-keys](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-public-keys):
To prevent malicious attacks, The
[require-sigs](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-require-sigs)
option is enabled by default. Only caches with signatures that can be verified by any
public key in `trusted-public-keys` will be used by Nix. Therefore, you need to add the
public key corresponding to the `substituters` in `trusted-public-keys`.
1. cache mirror's data are directly synchronized from the official cache server.
Therefore, their public keys are the same as those of the official cache server, and
you can use the public key of the official cache server without additional
configuration.
2. This entirely trust-based public key verification mechanism transfers the security
responsibility to users. If users want to use a third-party cache server to speed up
the build process of a certain library, they must take on the corresponding security
risks and decide whether to add the public key of that cache server to
`trusted-public-keys`. To completely solve this trust issue, Nix has introduced the
experimental feature [ca-derivations](https://nixos.wiki/wiki/Ca-derivations), which
does not depend on `trusted-public-keys` for signature verification. Interested
users can explore it further.
You can configure the `substituters` and `trusted-public-keys` parameters in the following ways:
You can configure the `substituters` and `trusted-public-keys` parameters in the following
ways:
1. Configure in `/etc/nix/nix.conf`, a global configuration that affects all users.
1. You can use `nix.settings.substituters` and `nix.settings.trusted-public-keys` in any NixOS Module to declaratively generate `/etc/nix/nix.conf`.
2. Configure in the `flake.nix` of a flake project using `nixConfig.substituters`. This configuration only affects the current flake.
3. Temporarily set through the `--option` parameter of the `nix` command, and this configuration only applies to the current command.
1. You can use `nix.settings.substituters` and `nix.settings.trusted-public-keys` in
any NixOS Module to declaratively generate `/etc/nix/nix.conf`.
2. Configure in the `flake.nix` of a flake project using `nixConfig.substituters`. This
configuration only affects the current flake.
3. Temporarily set through the `--option` parameter of the `nix` command, and this
configuration only applies to the current command.
Among these three methods, except for the first global configuration, the other two are temporary configurations. If multiple methods are used simultaneously, later configurations will directly override earlier ones.
Among these three methods, except for the first global configuration, the other two are
temporary configurations. If multiple methods are used simultaneously, later
configurations will directly override earlier ones.
However, there are security risks in temporarily setting `substituters`, as explained earlier regarding the deficiencies of the security verification mechanism based on `trusted-public-keys`. To set `substituters` through the second and third methods, you need to meet one of the following conditions:
However, there are security risks in temporarily setting `substituters`, as explained
earlier regarding the deficiencies of the security verification mechanism based on
`trusted-public-keys`. To set `substituters` through the second and third methods, you
need to meet one of the following conditions:
1. The current user is included in the [`trusted-users`](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-users) parameter list in `/etc/nix/nix.conf`.
2. The `substituters` specified temporarily via `--option substituters "http://xxx"` are included in the [`trusted-substituters`](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-substituters) parameter list in `/etc/nix/nix.conf`.
1. The current user is included in the
[`trusted-users`](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-users)
parameter list in `/etc/nix/nix.conf`.
2. The `substituters` specified temporarily via `--option substituters "http://xxx"` are
included in the
[`trusted-substituters`](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-substituters)
parameter list in `/etc/nix/nix.conf`.
Based on the above information, the following are examples of the three configuration methods mentioned earlier.
Based on the above information, the following are examples of the three configuration
methods mentioned earlier.
Firstly, declaratively configure system-level `substituters` and `trusted-public-keys` using `nix.settings` in `/etc/nixos/configuration.nix` or any NixOS Module:
Firstly, declaratively configure system-level `substituters` and `trusted-public-keys`
using `nix.settings` in `/etc/nixos/configuration.nix` or any NixOS Module:
```nix{7-27}
{
@ -73,9 +119,11 @@ Firstly, declaratively configure system-level `substituters` and `trusted-public
}
```
The second method is to configure `substituters` and `trusted-public-keys` using `nixConfig` in `flake.nix`:
The second method is to configure `substituters` and `trusted-public-keys` using
`nixConfig` in `flake.nix`:
> As mentioned earlier, it is essential to configure `nix.settings.trusted-users` in this configuration. Otherwise, the `substituters` we set here will not take effect.
> As mentioned earlier, it is essential to configure `nix.settings.trusted-users` in this
> configuration. Otherwise, the `substituters` we set here will not take effect.
```nix{5-23,43-47}
{
@ -133,27 +181,41 @@ The second method is to configure `substituters` and `trusted-public-keys` using
}
```
Finally, the third method involves using the following command to temporarily specify `substituters` and `trusted-public-keys` during deployment:
Finally, the third method involves using the following command to temporarily specify
`substituters` and `trusted-public-keys` during deployment:
```bash
sudo nixos-rebuild switch --option substituters "https://nix-community.cachix.org" --option trusted-public-keys "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
```
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 `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.
> 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
As mentioned earlier, the `substituters` configured by the three methods will override each other, but the ideal situation should be:
As mentioned earlier, the `substituters` configured by the three methods will override
each other, but the ideal situation should be:
1. At the system level in `/etc/nix/nix.conf`, configure only the most generic `substituters` and `trusted-public-keys`, such as official cache servers and domestic mirror sources.
2. In each flake project's `flake.nix`, configure the `substituters` and `trusted-public-keys` specific to that project, such as non-official cache servers like nix-community.
3. When building a flake project, nix should **merge** the `substituters` and `trusted-public-keys` configured in `flake.nix` and `/etc/nix/nix.conf`.
1. At the system level in `/etc/nix/nix.conf`, configure only the most generic
`substituters` and `trusted-public-keys`, such as official cache servers and domestic
mirror sources.
2. In each flake project's `flake.nix`, configure the `substituters` and
`trusted-public-keys` specific to that project, such as non-official cache servers like
nix-community.
3. When building a flake project, nix should **merge** the `substituters` and
`trusted-public-keys` configured in `flake.nix` and `/etc/nix/nix.conf`.
Nix provides the [`extra-` prefix](https://nixos.org/manual/nix/stable/command-ref/conf-file.html?highlight=extra#file-format) to achieve this **merging** functionality.
Nix provides the
[`extra-` prefix](https://nixos.org/manual/nix/stable/command-ref/conf-file.html?highlight=extra#file-format)
to achieve this **merging** functionality.
According to the official documentation, if the value of the `xxx` parameter is a list, the value of `extra-xxx` will be appended to the end of the `xxx` parameter:
According to the official documentation, if the value of the `xxx` parameter is a list,
the value of `extra-xxx` will be appended to the end of the `xxx` parameter:
In other words, you can use it like this:
@ -228,13 +290,23 @@ In other words, you can use it like this:
## Accelerate Package Downloads via a Proxy Server {#accelerate-package-downloads-via-a-proxy-server}
> Referenced from Issue: [roaming laptop: network proxy configuration - NixOS/nixpkgs](https://github.com/NixOS/nixpkgs/issues/27535#issuecomment-1178444327)
> Although it's mentioned earlier that a transparent proxy running on your router or local machine can completely solve the issue of slow package downloads in NixOS, the configuration is rather cumbersome and often requires additional hardware.
> Referenced from Issue:
> [roaming laptop: network proxy configuration - NixOS/nixpkgs](https://github.com/NixOS/nixpkgs/issues/27535#issuecomment-1178444327)
> Although it's mentioned earlier that a transparent proxy running on your router or local
> machine can completely solve the issue of slow package downloads in NixOS, the
> configuration is rather cumbersome and often requires additional hardware.
More users may prefer to directly speed up package downloads by using a HTTP/Socks5 proxy running on their machine. Here's how to set it up.
Using methods like `export HTTPS_PROXY=http://127.0.0.1:7890` in the Terminal will not work because the actual work is done by a background process called `nix-daemon`, not by commands directly executed in the Terminal.
More users may prefer to directly speed up package downloads by using a HTTP/Socks5 proxy
running on their machine. Here's how to set it up. Using methods like
`export HTTPS_PROXY=http://127.0.0.1:7890` in the Terminal will not work because the
actual work is done by a background process called `nix-daemon`, not by commands directly
executed in the Terminal.
The implementation code of `nix-daemon` is located at [nixpkgs/nixos/modules/services/system/nix-daemon.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/modules/services/system/nix-daemon.nix#L184-L191), which sets environment variables through the `systemd.services.nix-daemon.environment` option. We can also add proxy-related environment variables to the running environment of `nix-daemon` in the same way, as shown in the following example Module:
The implementation code of `nix-daemon` is located at
[nixpkgs/nixos/modules/services/system/nix-daemon.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/modules/services/system/nix-daemon.nix#L184-L191),
which sets environment variables through the `systemd.services.nix-daemon.environment`
option. We can also add proxy-related environment variables to the running environment of
`nix-daemon` in the same way, as shown in the following example Module:
```nix
{
@ -246,12 +318,15 @@ The implementation code of `nix-daemon` is located at [nixpkgs/nixos/modules/ser
}
```
After deploying this configuration, you can check if the environment variables have been set by running `sudo cat /proc/$(pidof nix-daemon)/environ | tr '\0' '\n'`.
After deploying this configuration, you can check if the environment variables have been
set by running `sudo cat /proc/$(pidof nix-daemon)/environ | tr '\0' '\n'`.
**However, be aware that when the proxy server is not available, nix-daemon will be unable to access any cache servers!**
Therefore, I still recommend using a transparent proxy to address acceleration issues.
**However, be aware that when the proxy server is not available, nix-daemon will be unable
to access any cache servers!** Therefore, I still recommend using a transparent proxy to
address acceleration issues.
If you only need to use a proxy temporarily, you can set the proxy environment variables with the following commands:
If you only need to use a proxy temporarily, you can set the proxy environment variables
with the following commands:
```bash
sudo mkdir /run/systemd/system/nix-daemon.service.d/
@ -263,6 +338,12 @@ sudo systemctl daemon-reload
sudo systemctl restart nix-daemon
```
The settings in `/run/systemd/system/nix-daemon.service.d/override.conf` will be automatically deleted when the system restarts, or you can manually delete it and restart the nix-daemon service to restore the original settings.
The settings in `/run/systemd/system/nix-daemon.service.d/override.conf` will be
automatically deleted when the system restarts, or you can manually delete it and restart
the nix-daemon service to restore the original settings.
> When using some commercial or public proxies, you might encounter HTTP 403 errors when downloading from GitHub (as described in [nixos-and-flakes-book/issues/74](https://github.com/ryan4yin/nixos-and-flakes-book/issues/74)). In such cases, you can try changing the proxy server or setting up [access-tokens](https://github.com/NixOS/nix/issues/6536) to resolve the issue.
> When using some commercial or public proxies, you might encounter HTTP 403 errors when
> downloading from GitHub (as described in
> [nixos-and-flakes-book/issues/74](https://github.com/ryan4yin/nixos-and-flakes-book/issues/74)).
> In such cases, you can try changing the proxy server or setting up
> [access-tokens](https://github.com/NixOS/nix/issues/6536) to resolve the issue.

View file

@ -1,8 +1,12 @@
# Downgrading or Upgrading Packages
When working with Flakes, you may encounter situations where you need to downgrade or upgrade certain packages to address bugs or compatibility issues. In Flakes, package versions and hash values are directly tied to the git commit of their flake input. To modify the package version, you need to lock the git commit of the flake input.
When working with Flakes, you may encounter situations where you need to downgrade or
upgrade certain packages to address bugs or compatibility issues. In Flakes, package
versions and hash values are directly tied to the git commit of their flake input. To
modify the package version, you need to lock the git commit of the flake input.
Here's an example of how you can add multiple nixpkgs inputs, each using a different git commit or branch:
Here's an example of how you can add multiple nixpkgs inputs, each using a different git
commit or branch:
```nix{8-13,19-20,27-44}
{
@ -61,9 +65,12 @@ Here's an example of how you can add multiple nixpkgs inputs, each using a diffe
}
```
In the above example, we have defined multiple nixpkgs inputs: `nixpkgs`, `nixpkgs-stable`, and `nixpkgs-fd40cef8d`. Each input corresponds to a different git commit or branch.
In the above example, we have defined multiple nixpkgs inputs: `nixpkgs`,
`nixpkgs-stable`, and `nixpkgs-fd40cef8d`. Each input corresponds to a different git
commit or branch.
Next, you can refer to the packages from `pkgs-stable` or `pkgs-fd40cef8d` within your submodule. Here's an example of a Home Manager submodule:
Next, you can refer to the packages from `pkgs-stable` or `pkgs-fd40cef8d` within your
submodule. Here's an example of a Home Manager submodule:
```nix{4-7,13,25}
{
@ -95,6 +102,13 @@ Next, you can refer to the packages from `pkgs-stable` or `pkgs-fd40cef8d` withi
}
```
By adjusting the configuration as shown above, you can deploy it using `sudo nixos-rebuild switch`. This will downgrade your Firefox/Chrome/VSCode versions to the ones corresponding to `nixpkgs-stable` or `nixpkgs-fd40cef8d`.
By adjusting the configuration as shown above, you can deploy it using
`sudo nixos-rebuild switch`. This will downgrade your Firefox/Chrome/VSCode versions to
the ones corresponding to `nixpkgs-stable` or `nixpkgs-fd40cef8d`.
> According to [1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347), it's not a good practice to use `import` in submodules or subflakes to customize `nixpkgs`. Each `import` creates a new instance of nixpkgs, which increases build time and memory usage as the configuration grows. To avoid this problem, we create all nixpkgs instances in `flake.nix`.
> According to
> [1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347),
> it's not a good practice to use `import` in submodules or subflakes to customize
> `nixpkgs`. Each `import` creates a new instance of nixpkgs, which increases build time
> and memory usage as the configuration grows. To avoid this problem, we create all
> nixpkgs instances in `flake.nix`.

View file

@ -1,18 +1,36 @@
# Get Started with NixOS
Now that we have learned the basics of the Nix language, we can start using it to configure our NixOS system. The default configuration file for NixOS is located at `/etc/nixos/configuration.nix`. This file contains all the declarative configuration for the system, including settings for the time zone, language, keyboard layout, network, users, file system, and boot options.
Now that we have learned the basics of the Nix language, we can start using it to
configure our NixOS system. The default configuration file for NixOS is located at
`/etc/nixos/configuration.nix`. This file contains all the declarative configuration for
the system, including settings for the time zone, language, keyboard layout, network,
users, file system, and boot options.
To modify the system state in a reproducible manner (which is highly recommended), we need to manually edit the `/etc/nixos/configuration.nix` file and then execute `sudo nixos-rebuild switch` to apply the modified configuration. This command generates a new system environment based on the modified configuration file, sets the new environment as the default one, and preserves the previous environment in the boot options of grub/systemd-boot. This ensures that we can always roll back to the old environment even if the new one fails to start.
To modify the system state in a reproducible manner (which is highly recommended), we need
to manually edit the `/etc/nixos/configuration.nix` file and then execute
`sudo nixos-rebuild switch` to apply the modified configuration. This command generates a
new system environment based on the modified configuration file, sets the new environment
as the default one, and preserves the previous environment in the boot options of
grub/systemd-boot. This ensures that we can always roll back to the old environment even
if the new one fails to start.
While `/etc/nixos/configuration.nix` is the classic method for configuring NixOS, it relies on data sources configured by `nix-channel` and lacks a version-locking mechanism, making it challenging to ensure the reproducibility of the system. A better approach is to use Flakes, which provides reproducibility and facilitates configuration management.
While `/etc/nixos/configuration.nix` is the classic method for configuring NixOS, it
relies on data sources configured by `nix-channel` and lacks a version-locking mechanism,
making it challenging to ensure the reproducibility of the system. A better approach is to
use Flakes, which provides reproducibility and facilitates configuration management.
In this section, we will first learn how to manage NixOS using the classic method (`/etc/nixos/configuration.nix`), and then we will explore the more advanced Flakes.
In this section, we will first learn how to manage NixOS using the classic method
(`/etc/nixos/configuration.nix`), and then we will explore the more advanced Flakes.
## Configuring the System using `/etc/nixos/configuration.nix`
The `/etc/nixos/configuration.nix` file is the default and classic method for configuring NixOS. While it lacks some of the advanced features of Flakes, it is still widely used and provides flexibility in system configuration.
The `/etc/nixos/configuration.nix` file is the default and classic method for configuring
NixOS. While it lacks some of the advanced features of Flakes, it is still widely used and
provides flexibility in system configuration.
To illustrate how to use `/etc/nixos/configuration.nix`, let's consider an example where we enable SSH and add a user named `ryan` to the system. We can achieve this by adding the following content to `/etc/nixos/configuration.nix`:
To illustrate how to use `/etc/nixos/configuration.nix`, let's consider an example where
we enable SSH and add a user named `ryan` to the system. We can achieve this by adding the
following content to `/etc/nixos/configuration.nix`:
```nix{14-38}
# Edit this configuration file to define what should be installed on
@ -58,20 +76,33 @@ To illustrate how to use `/etc/nixos/configuration.nix`, let's consider an examp
}
```
In this configuration, we declare our intention to enable the openssh service, add an SSH public key for the user 'ryan', and disable password login.
In this configuration, we declare our intention to enable the openssh service, add an SSH
public key for the user 'ryan', and disable password login.
To deploy the modified configuration, run `sudo nixos-rebuild switch`. This command will apply the changes, generate a new system environment, and set it as the default. You can now log in to the system using SSH with the configured SSH keys.
To deploy the modified configuration, run `sudo nixos-rebuild switch`. This command will
apply the changes, generate a new system environment, and set it as the default. You can
now log in to the system using SSH with the configured SSH keys.
> You can always try to add `--show-trace --print-build-logs --verbose` to the `nixos-rebuild` command to get the detailed error message if you encounter any errors during the deployment.
> You can always try to add `--show-trace --print-build-logs --verbose` to the
> `nixos-rebuild` command to get the detailed error message if you encounter any errors
> during the deployment.
Remember that any reproducible changes to the system can be made by modifying the `/etc/nixos/configuration.nix` file and deploying the changes with `sudo nixos-rebuild switch`.
Remember that any reproducible changes to the system can be made by modifying the
`/etc/nixos/configuration.nix` file and deploying the changes with
`sudo nixos-rebuild switch`.
To find configuration options and documentation:
- Use search engines like Google, e.g., search for `Chrome NixOS` to find NixOS-related information about Chrome. The NixOS Wiki and the source code of Nixpkgs are usually among the top results.
- Utilize the [NixOS Options Search](https://search.nixos.org/options) to search for keywords.
- Refer to the [Configuration section](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration) in the NixOS Manual for system-level configuration documentation.
- Search for keywords directly in the source code of [nixpkgs](https://github.com/NixOS/nixpkgs) on GitHub.
- Use search engines like Google, e.g., search for `Chrome NixOS` to find NixOS-related
information about Chrome. The NixOS Wiki and the source code of Nixpkgs are usually
among the top results.
- Utilize the [NixOS Options Search](https://search.nixos.org/options) to search for
keywords.
- Refer to the
[Configuration section](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration)
in the NixOS Manual for system-level configuration documentation.
- Search for keywords directly in the source code of
[nixpkgs](https://github.com/NixOS/nixpkgs) on GitHub.
## References

View file

@ -1,29 +1,48 @@
# Introduction to Flakes
The flakes experimental feature is a major development for Nix, it introduces a policy for managing dependencies between Nix expressions, it improves reproducibility, composability and usability in the Nix ecosystem. Although it's still an experimental feature, flakes have been widely used by the Nix community.[^1]
The flakes experimental feature is a major development for Nix, it introduces a policy for
managing dependencies between Nix expressions, it improves reproducibility, composability
and usability in the Nix ecosystem. Although it's still an experimental feature, flakes
have been widely used by the Nix community.[^1]
Flakes is one of the most significant changes the nix project has ever seen.[^2]
In simple terms, if you've worked with some JavaScript/Go/Rust/Python, you should be familiar with files like `package.json`/`go.mod`/`Cargo.toml`/`pyproject.toml`. In these programming languages, these files are used to describe the dependencies between software packages and how to build projects.
In simple terms, if you've worked with some JavaScript/Go/Rust/Python, you should be
familiar with files like `package.json`/`go.mod`/`Cargo.toml`/`pyproject.toml`. In these
programming languages, these files are used to describe the dependencies between software
packages and how to build projects.
Similarly, the package managers in these programming languages also use files like `package-lock.json`/`go.sum`/`Cargo.lock`/`poetry.lock` to lock the versions of dependencies, ensuring the reproducibility of projects.
Similarly, the package managers in these programming languages also use files like
`package-lock.json`/`go.sum`/`Cargo.lock`/`poetry.lock` to lock the versions of
dependencies, ensuring the reproducibility of projects.
Flakes borrow ideas from these package managers to enhance the reproducibility, composability, and usability of the Nix ecosystem.
Flakes borrow ideas from these package managers to enhance the reproducibility,
composability, and usability of the Nix ecosystem.
Flakes introduce `flake.nix`, similar to `package.json`, to describe the dependencies between Nix packages and how to build projects.
Additionally, it provides `flake.lock`, akin to `package-lock.json`, to lock the versions of dependencies, ensuring project reproducibility.
Flakes introduce `flake.nix`, similar to `package.json`, to describe the dependencies
between Nix packages and how to build projects. Additionally, it provides `flake.lock`,
akin to `package-lock.json`, to lock the versions of dependencies, ensuring project
reproducibility.
On the other hand, Flakes experimental features did not break Nix's original design at the user level.
The two new files `flake.nix`/`flake.lock` introduced by Flakes are just a wrapper for other Nix configurations.
In the following chapters, we will see that Flakes features provide a new and more convenient way to manage the dependencies between Nix expressions based on Nix's original design.
On the other hand, Flakes experimental features did not break Nix's original design at the
user level. The two new files `flake.nix`/`flake.lock` introduced by Flakes are just a
wrapper for other Nix configurations. In the following chapters, we will see that Flakes
features provide a new and more convenient way to manage the dependencies between Nix
expressions based on Nix's original design.
## A Word of Caution about Flakes <Badge type="danger" text="caution" />
The benefits of Flakes are evident, and the entire NixOS community has embraced it wholeheartedly. Currently, more than half of the users utilize Flakes[^3], providing assurance that Flakes will not be deprecated.
The benefits of Flakes are evident, and the entire NixOS community has embraced it
wholeheartedly. Currently, more than half of the users utilize Flakes[^3], providing
assurance that Flakes will not be deprecated.
:warning: However, it's important to note that **Flakes is still an experimental feature**. Some issues persist, and there is a possibility of introducing breaking changes during the stabilization process. The extent of these breaking changes remains uncertain.
:warning: However, it's important to note that **Flakes is still an experimental
feature**. Some issues persist, and there is a possibility of introducing breaking changes
during the stabilization process. The extent of these breaking changes remains uncertain.
Overall, I strongly recommend everyone to use Flakes, especially since this book revolves around NixOS and Flakes. However, it's crucial to be prepared for potential problems that may arise due to forthcoming breaking changes.
Overall, I strongly recommend everyone to use Flakes, especially since this book revolves
around NixOS and Flakes. However, it's crucial to be prepared for potential problems that
may arise due to forthcoming breaking changes.
## Flakes Tutorials
@ -39,42 +58,79 @@ I won't go into too much detail here, please refer to the following documents:
I delved into some details regarding Flakes:
- [[RFC 0136] A Plan to Stabilize Flakes and the New CLI Incrementally](https://github.com/NixOS/rfcs/pull/136): A plan to incrementally stabilize Flakes and the new CLI, merged.
- [CLI stabilization effort](https://github.com/NixOS/nix/issues/7701): An issue tracking the progress of the New CLI stabilization effort.
- [Why Are Flakes Still Experimental? - NixOS Discourse](https://discourse.nixos.org/t/why-are-flakes-still-experimental/29317): A post discussing why Flakes are still considered experimental.
- [Flakes Are Such an Obviously Good Thing - Graham Christensen](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/): An article emphasizing the advantages of Flakes while suggesting areas for improvement in its design and development process.
- [ teaching Nix 3 CLI and Flakes #281 - nix.dev](https://github.com/NixOS/nix.dev/issues/281): An issue about "Teaching Nix 3 CLI and Flakes" in nix.dev, and the conclusion is that we should not promote unstable features in nix.dev.
- [Draft: 1-year Roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9): A roadmap provided by the NixOS Foundation, which includes plans regarding the stabilization of Flakes.
- [[RFC 0136] A Plan to Stabilize Flakes and the New CLI Incrementally](https://github.com/NixOS/rfcs/pull/136):
A plan to incrementally stabilize Flakes and the new CLI, merged.
- [CLI stabilization effort](https://github.com/NixOS/nix/issues/7701): An issue tracking
the progress of the New CLI stabilization effort.
- [Why Are Flakes Still Experimental? - NixOS Discourse](https://discourse.nixos.org/t/why-are-flakes-still-experimental/29317):
A post discussing why Flakes are still considered experimental.
- [Flakes Are Such an Obviously Good Thing - Graham Christensen](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/):
An article emphasizing the advantages of Flakes while suggesting areas for improvement
in its design and development process.
- [ teaching Nix 3 CLI and Flakes #281 - nix.dev](https://github.com/NixOS/nix.dev/issues/281):
An issue about "Teaching Nix 3 CLI and Flakes" in nix.dev, and the conclusion is that we
should not promote unstable features in nix.dev.
- [Draft: 1-year Roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9):
A roadmap provided by the NixOS Foundation, which includes plans regarding the
stabilization of Flakes.
After reviewing these resources, it seems that Flakes may be(or may not...) stabilized within two years, possibly accompanied by some breaking changes.
After reviewing these resources, it seems that Flakes may be(or may not...) stabilized
within two years, possibly accompanied by some breaking changes.
## The New CLI and the Classic CLI
Nix introduced two experimental features, `nix-command` and `flakes`, in the year 2020.
These features bring forth a new command-line interface (referred to as the New CLI), a standardized Nix package structure definition (known as the Flakes feature), and features like `flake.lock`, similar to version lock files in cargo/npm.
Despite being experimental as of February 1, 2024, these features have gained widespread adoption within the Nix community due to their significant enhancement of Nix capabilities.
These features bring forth a new command-line interface (referred to as the New CLI), a
standardized Nix package structure definition (known as the Flakes feature), and features
like `flake.lock`, similar to version lock files in cargo/npm. Despite being experimental
as of February 1, 2024, these features have gained widespread adoption within the Nix
community due to their significant enhancement of Nix capabilities.
The current Nix New CLI (the `nix-command` experimental feature) is tightly coupled with the Flakes experimental feature.
While there are ongoing efforts to explicitly separate them, using Flakes essentially requires the use of the New CLI.
In this book, serving as a beginner's guide to NixOS and Flakes, it is necessary to introduce the differences between the New CLI, which Flakes relies on, and the old CLI.
The current Nix New CLI (the `nix-command` experimental feature) is tightly coupled with
the Flakes experimental feature. While there are ongoing efforts to explicitly separate
them, using Flakes essentially requires the use of the New CLI. In this book, serving as a
beginner's guide to NixOS and Flakes, it is necessary to introduce the differences between
the New CLI, which Flakes relies on, and the old CLI.
Here, we list the old Nix CLI and related concepts that are no longer needed when using the New CLI and Flakes (`nix-command` and `flakes`).
When researching, you can replace them with the corresponding New CLI commands (except for `nix-collect-garbage`, as there is currently no alternative for this command):
Here, we list the old Nix CLI and related concepts that are no longer needed when using
the New CLI and Flakes (`nix-command` and `flakes`). When researching, you can replace
them with the corresponding New CLI commands (except for `nix-collect-garbage`, as there
is currently no alternative for this command):
1. `nix-channel`: `nix-channel` manages software package versions through stable/unstable/test channels, similar to other package management tools such as apt/yum/pacman.
1. In Flakes, The functionality of `nix-channel` is entirely replaced by the `inputs` section in `flake.nix`.
2. `nix-env`: `nix-env` is a core command-line tool for classic Nix used to manage software packages in the user environment.
1. It installs packages from the data sources added by `nix-channel`, causing the installed package's version to be influenced by the channel. Packages installed with `nix-env` are not automatically recorded in Nix's declarative configuration and are completely independent of its control, making them challenging to reproduce on other machines. Therefore, it is not recommended to use this command directly.
2. The corresponding command in the New CLI is `nix profile`. Personally, I don't recommend it for beginners.
3. `nix-shell`: `nix-shell` creates a temporary shell environment, which is useful for development and testing.
1. New CLI: This tool is divided into three sub-commands: `nix develop`, `nix shell`, and `nix run`. We will discuss these three commands in detail in the "[Development](../development/intro.md)" chapter.
4. `nix-build`: `nix-build` builds Nix packages and places the build results in `/nix/store`, but it does not record them in Nix's declarative configuration.
1. `nix-channel`: `nix-channel` manages software package versions through
stable/unstable/test channels, similar to other package management tools such as
apt/yum/pacman.
1. In Flakes, The functionality of `nix-channel` is entirely replaced by the `inputs`
section in `flake.nix`.
2. `nix-env`: `nix-env` is a core command-line tool for classic Nix used to manage
software packages in the user environment.
1. It installs packages from the data sources added by `nix-channel`, causing the
installed package's version to be influenced by the channel. Packages installed with
`nix-env` are not automatically recorded in Nix's declarative configuration and are
completely independent of its control, making them challenging to reproduce on other
machines. Therefore, it is not recommended to use this command directly.
2. The corresponding command in the New CLI is `nix profile`. Personally, I don't
recommend it for beginners.
3. `nix-shell`: `nix-shell` creates a temporary shell environment, which is useful for
development and testing.
1. New CLI: This tool is divided into three sub-commands: `nix develop`, `nix shell`,
and `nix run`. We will discuss these three commands in detail in the
"[Development](../development/intro.md)" chapter.
4. `nix-build`: `nix-build` builds Nix packages and places the build results in
`/nix/store`, but it does not record them in Nix's declarative configuration.
1. New CLI: `nix-build` is replaced by `nix build`.
5. `nix-collect-garbage`: Garbage collection command used to clean up unused Store Objects in `/nix/store`.
1. There is a similar command in the New CLI, `nix store gc --debug`, but it does not clean the profile generations, so there is currently no alternative for this command.
5. `nix-collect-garbage`: Garbage collection command used to clean up unused Store Objects
in `/nix/store`.
1. There is a similar command in the New CLI, `nix store gc --debug`, but it does not
clean the profile generations, so there is currently no alternative for this
command.
6. And other less commonly used commands are not listed here.
1. You can refer to the detailed command comparison list in [Try to explain nix commands](https://qiita.com/Sumi-Sumi/items/6de9ee7aab10bc0dbead?_x_tr_sl=auto&_x_tr_tl=en&_x_tr_hl=en).
1. You can refer to the detailed command comparison list in
[Try to explain nix commands](https://qiita.com/Sumi-Sumi/items/6de9ee7aab10bc0dbead?_x_tr_sl=auto&_x_tr_tl=en&_x_tr_hl=en).
[^1]: [Flakes - NixOS Wiki](https://nixos.wiki/index.php?title=Flakes)
[^2]: [Flakes are such an obviously good thing](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/)
[^3]: [Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9)
[^2]:
[Flakes are such an obviously good thing](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/)
[^3]:
[Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9)

View file

@ -1,6 +1,7 @@
# Modularize Your NixOS Configuration
At this point, the skeleton of the entire system is configured. The current configuration structure in `/etc/nixos` should be as follows:
At this point, the skeleton of the entire system is configured. The current configuration
structure in `/etc/nixos` should be as follows:
```
$ tree
@ -13,20 +14,45 @@ $ tree
The functions of these four files are:
- `flake.lock`: An automatically generated version-lock file that records all input sources, hash values, and version numbers of the entire flake to ensure reproducibility.
- `flake.nix`: The entry file that will be recognized and deployed when executing `sudo nixos-rebuild switch`. See [Flakes - NixOS Wiki](https://nixos.wiki/wiki/Flakes) for all options of flake.nix.
- `configuration.nix`: Imported as a Nix module in flake.nix, all system-level configuration is currently written here. See [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration) for all options of configuration.nix.
- `home.nix`: Imported by Home-Manager as the configuration of the user `ryan` in flake.nix, containing all of `ryan`'s configuration and managing `ryan`'s home folder. See [Appendix A. Configuration Options - Home-Manager](https://nix-community.github.io/home-manager/options.xhtml) for all options of home.nix.
- `flake.lock`: An automatically generated version-lock file that records all input
sources, hash values, and version numbers of the entire flake to ensure reproducibility.
- `flake.nix`: The entry file that will be recognized and deployed when executing
`sudo nixos-rebuild switch`. See [Flakes - NixOS Wiki](https://nixos.wiki/wiki/Flakes)
for all options of flake.nix.
- `configuration.nix`: Imported as a Nix module in flake.nix, all system-level
configuration is currently written here. See
[Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration)
for all options of configuration.nix.
- `home.nix`: Imported by Home-Manager as the configuration of the user `ryan` in
flake.nix, containing all of `ryan`'s configuration and managing `ryan`'s home folder.
See
[Appendix A. Configuration Options - Home-Manager](https://nix-community.github.io/home-manager/options.xhtml)
for all options of home.nix.
By modifying these files, you can declaratively change the system and home directory status.
By modifying these files, you can declaratively change the system and home directory
status.
However, as the configuration grows, relying solely on `configuration.nix` and `home.nix` can lead to bloated and difficult-to-maintain files. A better solution is to use the Nix module system to split the configuration into multiple Nix modules and write them in a classified manner.
However, as the configuration grows, relying solely on `configuration.nix` and `home.nix`
can lead to bloated and difficult-to-maintain files. A better solution is to use the Nix
module system to split the configuration into multiple Nix modules and write them in a
classified manner.
The Nix module system provides a parameter, `imports`, which accepts a list of `.nix` files and merges all the configuration defined in these files into the current Nix module. Note that `imports` will not simply overwrite duplicate configuration but handle it more reasonably. For example, if `program.packages = [...]` is defined in multiple modules, then `imports` will merge all `program.packages` defined in all Nix modules into one list. Attribute sets can also be merged correctly. The specific behavior can be explored by yourself.
The Nix module system provides a parameter, `imports`, which accepts a list of `.nix`
files and merges all the configuration defined in these files into the current Nix module.
Note that `imports` will not simply overwrite duplicate configuration but handle it more
reasonably. For example, if `program.packages = [...]` is defined in multiple modules,
then `imports` will merge all `program.packages` defined in all Nix modules into one list.
Attribute sets can also be merged correctly. The specific behavior can be explored by
yourself.
> I only found a description of `imports` in [Nixpkgs-Unstable Official Manual - evalModules Parameters](https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules-parameters): `A list of modules. These are merged together to form the final configuration.` It's a bit ambiguous...
> I only found a description of `imports` in
> [Nixpkgs-Unstable Official Manual - evalModules Parameters](https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules-parameters):
> `A list of modules. These are merged together to form the final configuration.` It's a
> bit ambiguous...
With the help of `imports`, we can split `home.nix` and `configuration.nix` into multiple Nix modules defined in different `.nix` files. Lets look at an example module `packages.nix`:
With the help of `imports`, we can split `home.nix` and `configuration.nix` into multiple
Nix modules defined in different `.nix` files. Lets look at an example module
`packages.nix`:
```nix
{
@ -43,7 +69,8 @@ With the help of `imports`, we can split `home.nix` and `configuration.nix` into
}
```
This modules loads two other modules in the imports section, namely `special-fonts-1.nix` and `special-fonts-2.nix`. Both files are modules themselves and look similar to this.
This modules loads two other modules in the imports section, namely `special-fonts-1.nix`
and `special-fonts-2.nix`. Both files are modules themselves and look similar to this.
```nix
{ config, pkgs, ...}: {
@ -53,15 +80,23 @@ This modules loads two other modules in the imports section, namely `special-fon
Both import statements above are equivalent in the parameters they receive:
- Statement `(1)` imports the function in `special-fonts-1.nix` and calls it by passing `{config = config; pkgs = pkgs}`. Basically using the return value of the call (another partial configuration [attritbute set]) inside the `imports` list.
- Statement `(1)` imports the function in `special-fonts-1.nix` and calls it by passing
`{config = config; pkgs = pkgs}`. Basically using the return value of the call (another
partial configuration [attritbute set]) inside the `imports` list.
- Statement `(2)` defines a path to a module, whose function Nix will load _automatically_ when assembling the configuration `config`. It will pass all matching arguments from the function in `packages.nix` to the loaded function in `special-fonts-2.nix` which results in `import ./special-fonts-2.nix {config = config; pkgs = pkgs}`.
- Statement `(2)` defines a path to a module, whose function Nix will load _automatically_
when assembling the configuration `config`. It will pass all matching arguments from the
function in `packages.nix` to the loaded function in `special-fonts-2.nix` which results
in `import ./special-fonts-2.nix {config = config; pkgs = pkgs}`.
Here is a nice starter example of modularizing the configuration, Highly recommended:
- [Misterio77/nix-starter-configs](https://github.com/Misterio77/nix-starter-configs)
A more complicated example, [ryan4yin/nix-config/i3-kickstarter](https://github.com/ryan4yin/nix-config/tree/i3-kickstarter) is the configuration of my previous NixOS system with the i3 window manager. Its structure is as follows:
A more complicated example,
[ryan4yin/nix-config/i3-kickstarter](https://github.com/ryan4yin/nix-config/tree/i3-kickstarter)
is the configuration of my previous NixOS system with the i3 window manager. Its structure
is as follows:
```shell
├── flake.lock
@ -116,13 +151,18 @@ A more complicated example, [ryan4yin/nix-config/i3-kickstarter](https://github.
└── wallpaper.jpg # wallpaper
```
There is no need to follow the above structure, you can organize your configuration in any way you like. The key is to use `imports` to import all the submodules into the main module.
There is no need to follow the above structure, you can organize your configuration in any
way you like. The key is to use `imports` to import all the submodules into the main
module.
## `lib.mkOverride`, `lib.mkDefault`, and `lib.mkForce`
In Nix, some people use `lib.mkDefault` and `lib.mkForce` to define values. These functions are designed to set default values or force values of options.
In Nix, some people use `lib.mkDefault` and `lib.mkForce` to define values. These
functions are designed to set default values or force values of options.
You can explore the source code of `lib.mkDefault` and `lib.mkForce` by running `nix repl -f '<nixpkgs>'` and then entering `:e lib.mkDefault`. To learn more about `nix repl`, type `:?` for the help information.
You can explore the source code of `lib.mkDefault` and `lib.mkForce` by running
`nix repl -f '<nixpkgs>'` and then entering `:e lib.mkDefault`. To learn more about
`nix repl`, type `:?` for the help information.
Here's the source code:
@ -143,13 +183,22 @@ Here's the source code:
# ......
```
In summary, `lib.mkDefault` is used to set default values of options with a priority of 1000 internally, and `lib.mkForce` is used to force values of options with a priority of 50 internally. If you set a value of an option directly, it will be set with a default priority of 1000, the same as `lib.mkDefault`.
In summary, `lib.mkDefault` is used to set default values of options with a priority of
1000 internally, and `lib.mkForce` is used to force values of options with a priority of
50 internally. If you set a value of an option directly, it will be set with a default
priority of 1000, the same as `lib.mkDefault`.
The lower the `priority` value, the higher the actual priority. As a result, `lib.mkForce` has a higher priority than `lib.mkDefault`. If you define multiple values with the same priority, Nix will throw an error.
The lower the `priority` value, the higher the actual priority. As a result, `lib.mkForce`
has a higher priority than `lib.mkDefault`. If you define multiple values with the same
priority, Nix will throw an error.
Using these functions can be very helpful for modularizing the configuration. You can set default values in a low-level module (base module) and force values in a high-level module.
Using these functions can be very helpful for modularizing the configuration. You can set
default values in a low-level module (base module) and force values in a high-level
module.
For example, in my configuration at [ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-server.nix](https://github.com/ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-server.nix#L32), I define default values like this:
For example, in my configuration at
[ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-server.nix](https://github.com/ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-server.nix#L32),
I define default values like this:
```nix{6}
{ lib, pkgs, ... }:
@ -163,7 +212,9 @@ For example, in my configuration at [ryan4yin/nix-config/blob/c515ea9/modules/ni
}
```
Then, for my desktop machine, I override the value in [ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-desktop.nix](https://github.com/ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-desktop.nix#L18) like this:
Then, for my desktop machine, I override the value in
[ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-desktop.nix](https://github.com/ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-desktop.nix#L18)
like this:
```nix{10}
{ lib, pkgs, ... }:
@ -183,13 +234,23 @@ Then, for my desktop machine, I override the value in [ryan4yin/nix-config/blob/
## `lib.mkOrder`, `lib.mkBefore`, and `lib.mkAfter`
In addition to `lib.mkDefault` and `lib.mkForce`, there are also `lib.mkBefore` and `lib.mkAfter`, which are used to set the merge order of **list-type options**. These functions further contribute to the modularization of the configuration.
In addition to `lib.mkDefault` and `lib.mkForce`, there are also `lib.mkBefore` and
`lib.mkAfter`, which are used to set the merge order of **list-type options**. These
functions further contribute to the modularization of the configuration.
> I haven't found the official documentation for list-type options, but I simply understand that they are types whose merge results are related to the order of merging. According to this understanding, both `list` and `string` types are list-type options, and these functions can indeed be used on these two types in practice.
> I haven't found the official documentation for list-type options, but I simply
> understand that they are types whose merge results are related to the order of merging.
> According to this understanding, both `list` and `string` types are list-type options,
> and these functions can indeed be used on these two types in practice.
As mentioned earlier, when you define multiple values with the same **override priority**, Nix will throw an error. However, by using `lib.mkOrder`, `lib.mkBefore`, or `lib.mkAfter`, you can define multiple values with the same override priority, and they will be merged in the order you specify.
As mentioned earlier, when you define multiple values with the same **override priority**,
Nix will throw an error. However, by using `lib.mkOrder`, `lib.mkBefore`, or
`lib.mkAfter`, you can define multiple values with the same override priority, and they
will be merged in the order you specify.
To examine the source code of `lib.mkBefore`, you can run `nix repl -f '<nixpkgs>'` and then enter `:e lib.mkBefore`. To learn more about `nix repl`, type `:?` for the help information:
To examine the source code of `lib.mkBefore`, you can run `nix repl -f '<nixpkgs>'` and
then enter `:e lib.mkBefore`. To learn more about `nix repl`, type `:?` for the help
information:
```nix
# ......
@ -206,9 +267,11 @@ To examine the source code of `lib.mkBefore`, you can run `nix repl -f '<nixpkgs
# ......
```
Therefore, `lib.mkBefore` is a shorthand for `lib.mkOrder 500`, and `lib.mkAfter` is a shorthand for `lib.mkOrder 1500`.
Therefore, `lib.mkBefore` is a shorthand for `lib.mkOrder 500`, and `lib.mkAfter` is a
shorthand for `lib.mkOrder 1500`.
To test the usage of `lib.mkBefore` and `lib.mkAfter`, let's create a simple Flake project:
To test the usage of `lib.mkBefore` and `lib.mkAfter`, let's create a simple Flake
project:
```nix{10-38}
# flake.nix
@ -256,7 +319,8 @@ To test the usage of `lib.mkBefore` and `lib.mkAfter`, let's create a simple Fla
}
```
The flake above contains the usage of `lib.mkBefore` and `lib.mkAfter` on multiline strings, single-line strings, and lists. Let's test the results:
The flake above contains the usage of `lib.mkBefore` and `lib.mkAfter` on multiline
strings, single-line strings, and lists. Let's test the results:
```bash
# Example 1: multiline string merging
@ -288,9 +352,12 @@ echo 'insert after default';"
```
As you can see, `lib.mkBefore` and `lib.mkAfter` can define the order of merging of multiline strings, single-line strings, and lists. The order of merging is the same as the order of definition.
As you can see, `lib.mkBefore` and `lib.mkAfter` can define the order of merging of
multiline strings, single-line strings, and lists. The order of merging is the same as the
order of definition.
> For a deeper introduction to the module system, see [Module System & Custom Options](../other-usage-of-flakes/module-system.md).
> For a deeper introduction to the module system, see
> [Module System & Custom Options](../other-usage-of-flakes/module-system.md).
## References

View file

@ -2,7 +2,12 @@
## Enabling Flakes Support for NixOS {#enable-nix-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:
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:
```nix{12,16}
{ config, pkgs, ... }:
@ -32,31 +37,37 @@ Compared to the default configuration method currently used in NixOS, Flakes off
}
```
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.
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.
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.
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.
## 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`.
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:
You can start by using the official templates to learn how to write a flake. First, check
what templates are available:
```bash
nix flake show templates
```
Among them, the `templates#full` template demonstrates all possible usage. Take a look at its content:
Among them, the `templates#full` template demonstrates all possible usage. Take a look at
its content:
```bash
nix flake init -t templates#full
cat 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:
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:
```nix{16}
{
@ -81,32 +92,56 @@ Here's an example of the content:
}
```
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.
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.
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.
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.
After the switch, we can manage the system through the Flakes feature.
Currently, our flake includes these files:
- `/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.
- `/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.
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.
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.
> 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.
> 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.
> 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.
## `flake.nix` Configuration Explained {#flake-nix-configuration-explained}
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.
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.
### 1. Flake Inputs
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:
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}
{
@ -121,18 +156,23 @@ First, let's look at the `inputs` attribute. It is an attribute set that defines
}
```
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.
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.
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.
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:
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}
{
@ -157,13 +197,19 @@ It is a function that takes the dependencies from `inputs` as its parameters, an
}
```
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.
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.
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:
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
@ -171,10 +217,14 @@ 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.
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:
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
@ -184,14 +234,24 @@ sudo nixos-rebuild switch --flake github:owner/repo#your-hostname
**A Flake can depend on other Flakes to utilize the features they provide.**
By default, a flake searches for a `flake.nix` file in the root directory of each of its dependencies (i.e., each item in `inputs`) and lazily evaluates their `outputs` functions. It then passes the attribute set returned by these functions as arguments to its own `outputs` function, enabling us to use the features provided by the other flakes within our current flake.
By default, a flake searches for a `flake.nix` file in the root directory of each of its
dependencies (i.e., each item in `inputs`) and lazily evaluates their `outputs` functions.
It then passes the attribute set returned by these functions as arguments to its own
`outputs` function, enabling us to use the features provided by the other flakes within
our current flake.
More precisely, the evaluation of the `outputs` function for each dependency is lazy. This means that a flake's `outputs` function is only evaluated when it is actually used, thereby avoiding unnecessary calculations and improving efficiency.
More precisely, the evaluation of the `outputs` function for each dependency is lazy. This
means that a flake's `outputs` function is only evaluated when it is actually used,
thereby avoiding unnecessary calculations and improving efficiency.
The description above may be a bit confusing, so let's take a look at the process with the `flake.nix` example used in this section.
Our `flake.nix` declares the `inputs.nixpkgs` dependency, so that [nixpkgs/flake.nix] will be evaluated when we run the `sudo nixos-rebuild switch` command.
The description above may be a bit confusing, so let's take a look at the process with the
`flake.nix` example used in this section. Our `flake.nix` declares the `inputs.nixpkgs`
dependency, so that [nixpkgs/flake.nix] will be evaluated when we run the
`sudo nixos-rebuild switch` command.
From the source code of the Nixpkgs repository, we can see that its flake outputs definition includes the `lib` attribute, and in our example, we use the `lib` attribute's `nixosSystem` function to configure our NixOS system:
From the source code of the Nixpkgs repository, we can see that its flake outputs
definition includes the `lib` attribute, and in our example, we use the `lib` attribute's
`nixosSystem` function to configure our NixOS system:
```nix{8-13}
{
@ -211,27 +271,43 @@ From the source code of the Nixpkgs repository, we can see that its flake output
}
```
The attribute set following `nixpkgs.lib.nixosSystem` is the function's parameter. We have only set two parameters here:
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.
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.
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.
> 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`.
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 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.
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.
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:
@ -249,44 +325,67 @@ Here's a simplified structure of a Nixpkgs Module:
}
```
The definition is actually a Nix function, and it has five **automatically generated, automatically injected, and declaration-free parameters** provided by the module system:
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.
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 options' values in the current environment, which will be used extensively in the subsequent section on the module system.
2. `config`: A set of all options' values in the current environment, which will be used
extensively in the subsequent section on the module system.
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 `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.
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 `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.
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:
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. `specialArgs`: There are scattered mentions related to it in the NixOS Manual and the
Nixpkgs Manual.
- Nixpkgs Manual: [Module System - Nixpkgs]
- NixOS Manual: [nixpkgs/nixos-23.11/nixos/doc/manual/development/option-types.section.md#L237-L244]
- NixOS Manual:
[nixpkgs/nixos-23.11/nixos/doc/manual/development/option-types.section.md#L237-L244]
1. `_module.args`:
- NixOS Manual: [Appendix A. Configuration Options](https://nixos.org/manual/nixos/stable/options#opt-_module.args)
- NixOS Manual:
[Appendix A. Configuration Options](https://nixos.org/manual/nixos/stable/options#opt-_module.args)
- Source Code: [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:
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.
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.
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:
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}
{
@ -334,7 +433,10 @@ Or you can achieve the same effect using the `_module.args` option:
}
```
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:
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{3}
# Nix will match by name and automatically inject the inputs
@ -345,15 +447,22 @@ Choose one of the two methods above to modify your configuration, and then you c
}
```
The next section will demonstrate how to use `specialArgs`/`_module.args` to install system software from other flake sources.
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.
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.
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.
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`:
@ -400,29 +509,48 @@ Next, you can reference this flake input data source in `configuration.nix`:
}
```
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.
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 deployment, you can directly test and verify the installation using the `hx` command in the terminal.
After deployment, you can directly test and verify the installation using the `hx` command
in the terminal.
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):
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):
```bash
nix run github:helix-editor/helix/master
```
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).
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
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.
- [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.
- [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.
[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
[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

@ -2,7 +2,9 @@
## Show detailed error messages
You can always try to add `--show-trace --print-build-logs --verbose` to the `nixos-rebuild` command to get the detailed error message if you encounter any errors during the deployment. e.g.
You can always try to add `--show-trace --print-build-logs --verbose` to the
`nixos-rebuild` command to get the detailed error message if you encounter any errors
during the deployment. e.g.
```bash
cd /etc/nixos
@ -14,13 +16,19 @@ sudo nixos-rebuild switch --flake .#myhost --show-trace -L -v
## Managing the Configuration with Git
NixOS configuration, being a set of text files, is well-suited for version control with Git. This allows easy rollback to a previous version in case of issues.
NixOS configuration, being a set of text files, is well-suited for version control with
Git. This allows easy rollback to a previous version in case of issues.
> NOTE: When using Git, Nix ignores all files that are not tracked by Git. If you encounter an error in Nix stating that a particular file is not found, it may be because you haven't `git add`ed it.
> NOTE: When using Git, Nix ignores all files that are not tracked by Git. If you
> encounter an error in Nix stating that a particular file is not found, it may be because
> you haven't `git add`ed it.
By default, NixOS places the configuration in `/etc/nixos`, which requires root permissions for modification, making it inconvenient for daily use. Thankfully, Flakes can help solve this problem by allowing you to place your flake anywhere you prefer.
By default, NixOS places the configuration in `/etc/nixos`, which requires root
permissions for modification, making it inconvenient for daily use. Thankfully, Flakes can
help solve this problem by allowing you to place your flake anywhere you prefer.
For example, you can place your flake in `~/nixos-config` and create a symbolic link in `/etc/nixos` as follows:
For example, you can place your flake in `~/nixos-config` and create a symbolic link in
`/etc/nixos` as follows:
```shell
sudo mv /etc/nixos /etc/nixos.bak # Backup the original configuration
@ -30,9 +38,12 @@ sudo ln -s ~/nixos-config/ /etc/nixos
sudo nixos-rebuild switch
```
This way, you can use Git to manage the configuration in `~/nixos-config`. The configuration can be modified with regular user-level permissions and does not require root ownership.
This way, you can use Git to manage the configuration in `~/nixos-config`. The
configuration can be modified with regular user-level permissions and does not require
root ownership.
Another approach is to delete `/etc/nixos` directly and specify the configuration file path each time you deploy it:
Another approach is to delete `/etc/nixos` directly and specify the configuration file
path each time you deploy it:
```shell
sudo mv /etc/nixos /etc/nixos.bak
@ -43,7 +54,8 @@ cd ~/nixos-config
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:
```shell
cd ~/nixos-config
@ -54,11 +66,15 @@ git checkout HEAD^1
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.
## Viewing and Deleting Historical Data
As mentioned earlier, each NixOS deployment creates a new version, and all versions are added to the system's boot options. In addition to restarting the computer, you can query all available historical versions using the following command:
As mentioned earlier, each NixOS deployment creates a new version, and all versions are
added to the system's boot options. In addition to restarting the computer, you can query
all available historical versions using the following command:
```shell
nix profile history --profile /nix/var/nix/profiles/system
@ -78,14 +94,16 @@ sudo nix-collect-garbage --delete-old
To find out why a package is installed, you can use the following command:
1. Enter a shell with `nix-tree` & `rg` available: `nix shell nixpkgs#nix-tree nixpkgs#ripgrep`
1. Enter a shell with `nix-tree` & `rg` available:
`nix shell nixpkgs#nix-tree nixpkgs#ripgrep`
1. ` nix-store --gc --print-roots | rg -v '/proc/' | rg -Po '(?<= -> ).*' | xargs -o nix-tree`
1. `/<package-name>` to find the package you want to check.
1. `w` to show the package is depended by which packages, and the full dependency chain.
## Reducing Disk Usage
The following configuration can be added to your NixOS configuration to help reduce disk usage:
The following configuration can be added to your NixOS configuration to help reduce disk
usage:
```nix
{ lib, pkgs, ... }:
@ -113,4 +131,5 @@ The following configuration can be added to your NixOS configuration to help red
}
```
By incorporating this configuration, you can better manage and optimize the disk usage of your NixOS system.
By incorporating this configuration, you can better manage and optimize the disk usage of
your NixOS system.

View file

@ -1,8 +1,12 @@
# Getting Started with Home Manager
As I mentioned earlier, NixOS can only manage system-level configuration. To manage user-level configuration in the Home directory, we need to install Home Manager.
As I mentioned earlier, NixOS can only manage system-level configuration. To manage
user-level configuration in the Home directory, we need to install Home Manager.
According to the official [Home Manager Manual](https://nix-community.github.io/home-manager/index.xhtml), to install Home Manager as a module of NixOS, we first need to create `/etc/nixos/home.nix`. Here's an example of its contents:
According to the official
[Home Manager Manual](https://nix-community.github.io/home-manager/index.xhtml), to
install Home Manager as a module of NixOS, we first need to create `/etc/nixos/home.nix`.
Here's an example of its contents:
```nix
{ config, pkgs, ... }:
@ -167,7 +171,9 @@ According to the official [Home Manager Manual](https://nix-community.github.io/
}
```
After adding `/etc/nixos/home.nix`, you need to import this new configuration file in `/etc/nixos/flake.nix` to make use of it, use the following command to generate an example in the current folder for reference:
After adding `/etc/nixos/home.nix`, you need to import this new configuration file in
`/etc/nixos/flake.nix` to make use of it, use the following command to generate an example
in the current folder for reference:
```shell
nix flake new example -t github:nix-community/home-manager#nixos
@ -219,42 +225,70 @@ 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 `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.
> 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**!)
To find the options we can use in `home.nix`, referring to the following documents:
- [Home Manager - Appendix A. Configuration Options](https://nix-community.github.io/home-manager/options.xhtml): A list of all options, it is recommended to search for keywords in it.
- [Home Manager Option Search](https://mipmip.github.io/home-manager-option-search/) is another option search tool with better UI.
- [home-manager](https://github.com/nix-community/home-manager): Some options are not listed in the official documentation, or the documentation is not clear enough, you can directly search and read the corresponding source code in this home-manager repo.
- [Home Manager - Appendix A. Configuration Options](https://nix-community.github.io/home-manager/options.xhtml):
A list of all options, it is recommended to search for keywords in it.
- [Home Manager Option Search](https://mipmip.github.io/home-manager-option-search/) is
another option search tool with better UI.
- [home-manager](https://github.com/nix-community/home-manager): Some options are not
listed in the official documentation, or the documentation is not clear enough, you can
directly search and read the corresponding source code in this home-manager repo.
## Home Manager vs NixOS
There are many software packages or configurations that can be set up using either NixOS Modules (`configuration.nix`) or Home Manager (`home.nix`), which brings about a choice dilemma: **What is the difference between placing software packages or configuration files in NixOS Modules versus Home Manager, and how should one make a decision?**
There are many software packages or configurations that can be set up using either NixOS
Modules (`configuration.nix`) or Home Manager (`home.nix`), which brings about a choice
dilemma: **What is the difference between placing software packages or configuration files
in NixOS Modules versus Home Manager, and how should one make a decision?**
First, let's look at the differences: Software packages and configuration files installed via NixOS Modules are global to the entire system. Global configurations are usually stored in `/etc`, and system-wide installed software is accessible in any user environment.
First, let's look at the differences: Software packages and configuration files installed
via NixOS Modules are global to the entire system. Global configurations are usually
stored in `/etc`, and system-wide installed software is accessible in any user
environment.
On the other hand, configurations and software installed via Home Manager will be linked to the respective user's Home directory. The software installed is only available in the corresponding user environment, and it becomes unusable when switched to another user.
On the other hand, configurations and software installed via Home Manager will be linked
to the respective user's Home directory. The software installed is only available in the
corresponding user environment, and it becomes unusable when switched to another user.
Based on these characteristics, the general recommended usage is:
- NixOS Modules: Install system core components and other software packages or configurations needed by all users.
- For instance, if you want a software package to continue working when you switch to the root user, or if you want a configuration to apply system-wide, you should install it using NixOS Modules.
- NixOS Modules: Install system core components and other software packages or
configurations needed by all users.
- For instance, if you want a software package to continue working when you switch to
the root user, or if you want a configuration to apply system-wide, you should install
it using NixOS Modules.
- Home Manager: Use Home Manager for all other configurations and software.
The benefits of this approach are:
1. Software and background services installed at the system level often run with root privileges. Avoiding unnecessary software installations at the system level can reduce the security risks of the system.
1. Many configurations in Home Manager are universal for NixOS, macOS, and other Linux distributions. Choosing Home Manager to install software and configure systems can improve the portability of configurations.
1. If you need multi-user support, software and configurations installed via Home Manager can better isolate different user environments, preventing configuration and software version conflicts between users.
1. Software and background services installed at the system level often run with root
privileges. Avoiding unnecessary software installations at the system level can reduce
the security risks of the system.
1. Many configurations in Home Manager are universal for NixOS, macOS, and other Linux
distributions. Choosing Home Manager to install software and configure systems can
improve the portability of configurations.
1. If you need multi-user support, software and configurations installed via Home Manager
can better isolate different user environments, preventing configuration and software
version conflicts between users.
## How to use packages installed by Home Manager with privileged access?
The first thing that comes to mind is to switch to `root`, but then any packages installed by the current user through `home.nix` will be unavailable.
let's take `kubectl` as an example(it's pre-installed via `home.nix`):
The first thing that comes to mind is to switch to `root`, but then any packages installed
by the current user through `home.nix` will be unavailable. let's take `kubectl` as an
example(it's pre-installed via `home.nix`):
```sh
# 1. kubectl is available
@ -283,7 +317,9 @@ Error: nu::shell::external_command
/home/ryan/nix-config> exit
```
But it's possible to run those packages with privileged access without switching to `root`, by using `sudo`, we temporarily grant the current user privileged access to system resources:
But it's possible to run those packages with privileged access without switching to
`root`, by using `sudo`, we temporarily grant the current user privileged access to system
resources:
```sh
sudo kubectl

View file

@ -1,6 +1,7 @@
# Updating the System
With Flakes, updating the system is straightforward. Simply execute the following commands in `/etc/nixos` or any other location where you keep the configuration:
With Flakes, updating the system is straightforward. Simply execute the following commands
in `/etc/nixos` or any other location where you keep the configuration:
```shell
# Update flake.lock
@ -13,4 +14,6 @@ nix flake lock --update-input home-manager
sudo nixos-rebuild switch --flake .
```
Occasionally, you may encounter a "sha256 mismatch" error when running `nixos-rebuild switch`. This error can be resolved by updating `flake.lock` using `nix flake update`.
Occasionally, you may encounter a "sha256 mismatch" error when running
`nixos-rebuild switch`. This error can be resolved by updating `flake.lock` using
`nix flake update`.

View file

@ -1,6 +1,8 @@
# `pkgs.callPackage`
`pkgs.callPackage` is used to parameterize the construction of Nix Derivation. To understand its purpose, let's first consider how we would define a Nix package (also known as a Derivation) without using `pkgs.callPackage`.
`pkgs.callPackage` is used to parameterize the construction of Nix Derivation. To
understand its purpose, let's first consider how we would define a Nix package (also known
as a Derivation) without using `pkgs.callPackage`.
## 1. Without `pkgs.callPackage`
@ -10,7 +12,8 @@ We can define a Nix package using code like this:
pkgs.writeShellScriptBin "hello" ''echo "hello, ryan!"''
```
To verify this, you can use `nix repl`, and you'll see that the result is indeed a Derivation:
To verify this, you can use `nix repl`, and you'll see that the result is indeed a
Derivation:
```shell
nix repl -f '<nixpkgs>'
@ -23,13 +26,21 @@ nix-repl> pkgs.writeShellScriptBin "hello" '' echo "hello, xxx!" ''
«derivation /nix/store/zhgar12vfhbajbchj36vbbl3mg6762s8-hello.drv»
```
While the definition of this Derivation is quite concise, most Derivations in nixpkgs are much more complex. In previous sections, we introduced and extensively used the `import xxx.nix` method to import Nix expressions from other Nix files, which can enhance code maintainability.
While the definition of this Derivation is quite concise, most Derivations in nixpkgs are
much more complex. In previous sections, we introduced and extensively used the
`import xxx.nix` method to import Nix expressions from other Nix files, which can enhance
code maintainability.
1. To enhance maintainability, you can store the definition of the Derivation in a separate file, e.g., `hello.nix`.
1. However, the context within `hello.nix` itself doesn't include the `pkgs` variable, so you'll need to modify its content to pass `pkgs` as a parameter to `hello.nix`.
2. In places where you need to use this Derivation, you can use `import ./hello.nix pkgs` to import `hello.nix` and use `pkgs` as a parameter to execute the function defined within.
1. To enhance maintainability, you can store the definition of the Derivation in a
separate file, e.g., `hello.nix`.
1. However, the context within `hello.nix` itself doesn't include the `pkgs` variable,
so you'll need to modify its content to pass `pkgs` as a parameter to `hello.nix`.
2. In places where you need to use this Derivation, you can use `import ./hello.nix pkgs`
to import `hello.nix` and use `pkgs` as a parameter to execute the function defined
within.
Let's continue to verify this using `nix repl`, and you'll see that the result is still a Derivation:
Let's continue to verify this using `nix repl`, and you'll see that the result is still a
Derivation:
```shell
cat hello.nix
@ -49,13 +60,19 @@ nix-repl> import ./hello.nix pkgs
## 2. Using `pkgs.callPackage`
In the previous example without `pkgs.callPackage`, we directly passed `pkgs` as a parameter to `hello.nix`. However, this approach has some drawbacks:
In the previous example without `pkgs.callPackage`, we directly passed `pkgs` as a
parameter to `hello.nix`. However, this approach has some drawbacks:
1. All other dependencies of the `hello` Derivation are tightly coupled with `pkgs`.
1. If we need custom dependencies, we have to modify either `pkgs` or the content of `hello.nix`, which can be cumbersome.
2. In cases where `hello.nix` becomes complex, it's challenging to determine which Derivations from `pkgs` it relies on, making it difficult to analyze the dependencies between Derivations.
1. If we need custom dependencies, we have to modify either `pkgs` or the content of
`hello.nix`, which can be cumbersome.
2. In cases where `hello.nix` becomes complex, it's challenging to determine which
Derivations from `pkgs` it relies on, making it difficult to analyze the dependencies
between Derivations.
`pkgs.callPackage`, as a tool for parameterizing the construction of Derivations, addresses these issues. Let's take a look at its source code and comments [nixpkgs/lib/customisation.nix#L101-L121](https://github.com/NixOS/nixpkgs/blob/fe138d3/lib/customisation.nix#L101-L121):
`pkgs.callPackage`, as a tool for parameterizing the construction of Derivations,
addresses these issues. Let's take a look at its source code and comments
[nixpkgs/lib/customisation.nix#L101-L121](https://github.com/NixOS/nixpkgs/blob/fe138d3/lib/customisation.nix#L101-L121):
```nix
/* Call the package function in the file `fn` with the required
@ -91,17 +108,28 @@ In the previous example without `pkgs.callPackage`, we directly passed `pkgs` as
# ......
```
In essence, `pkgs.callPackage` is used as `pkgs.callPackage fn args`, where the place holder `fn` is a Nix file or function, and `args` is an attribute set. Here's how it works:
In essence, `pkgs.callPackage` is used as `pkgs.callPackage fn args`, where the place
holder `fn` is a Nix file or function, and `args` is an attribute set. Here's how it
works:
1. `pkgs.callPackage fn args` first checks if `fn` is a function or a file. If it's a file, it imports the function defined within.
1. After this step, you have a function, typically with parameters like `lib`, `stdenv`, `fetchurl`, and possibly some custom parameters.
2. Next, `pkgs.callPackage fn args` merges `args` with the `pkgs` attribute set. If there are conflicts, the parameters in `args` will override those in `pkgs`.
3. Then, `pkgs.callPackage fn args` extracts the parameters of the `fn` function from the merged attribute set and uses them to execute the function.
1. `pkgs.callPackage fn args` first checks if `fn` is a function or a file. If it's a
file, it imports the function defined within.
1. After this step, you have a function, typically with parameters like `lib`,
`stdenv`, `fetchurl`, and possibly some custom parameters.
2. Next, `pkgs.callPackage fn args` merges `args` with the `pkgs` attribute set. If there
are conflicts, the parameters in `args` will override those in `pkgs`.
3. Then, `pkgs.callPackage fn args` extracts the parameters of the `fn` function from the
merged attribute set and uses them to execute the function.
4. The result of the function execution is a Derivation, which is a Nix package.
What can a Nix file or function, used as an argument to `pkgs.callPackage`, look like? You can examine examples we've used before in [Nixpkgs's Advanced Usage - Introduction](./intro.md): `hello.nix`, `fcitx5-rime.nix`, `vscode/with-extensions.nix`, and `firefox/common.nix`. All of them can be imported using `pkgs.callPackage`.
What can a Nix file or function, used as an argument to `pkgs.callPackage`, look like? You
can examine examples we've used before in
[Nixpkgs's Advanced Usage - Introduction](./intro.md): `hello.nix`, `fcitx5-rime.nix`,
`vscode/with-extensions.nix`, and `firefox/common.nix`. All of them can be imported using
`pkgs.callPackage`.
For instance, if you've defined a custom NixOS kernel configuration in `kernel.nix` and made the development branch name and kernel source code configurable:
For instance, if you've defined a custom NixOS kernel configuration in `kernel.nix` and
made the development branch name and kernel source code configurable:
```nix
{
@ -128,7 +156,8 @@ For instance, if you've defined a custom NixOS kernel configuration in `kernel.n
})
```
You can use `pkgs.callPackage ./hello.nix {}` in any Nix module to import and use it, replacing any of its parameters as needed:
You can use `pkgs.callPackage ./hello.nix {}` in any Nix module to import and use it,
replacing any of its parameters as needed:
```nix
{ lib, pkgs, pkgsKernel, kernel-src, ... }:
@ -147,13 +176,21 @@ You can use `pkgs.callPackage ./hello.nix {}` in any Nix module to import and us
}
```
As shown above, by using `pkgs.callPackage`, you can pass different `src` and `boardName` to the function defined in `kernel.nix`, to generate different kernel packages. This allows you to adapt the same `kernel.nix` to different kernel source code and development boards.
As shown above, by using `pkgs.callPackage`, you can pass different `src` and `boardName`
to the function defined in `kernel.nix`, to generate different kernel packages. This
allows you to adapt the same `kernel.nix` to different kernel source code and development
boards.
The advantages of `pkgs.callPackage` are:
1. Derivation definitions are parameterized, and all dependencies of the Derivation are the function parameters in its definition. This makes it easy to analyze dependencies between Derivations.
2. All dependencies and other custom parameters of the Derivation can be easily replaced by using the second parameter of `pkgs.callPackage`, greatly enhancing Derivation reusability.
3. While achieving the above two functionalities, it does not increase code complexity, as all dependencies in `pkgs` can be automatically injected.
1. Derivation definitions are parameterized, and all dependencies of the Derivation are
the function parameters in its definition. This makes it easy to analyze dependencies
between Derivations.
2. All dependencies and other custom parameters of the Derivation can be easily replaced
by using the second parameter of `pkgs.callPackage`, greatly enhancing Derivation
reusability.
3. While achieving the above two functionalities, it does not increase code complexity, as
all dependencies in `pkgs` can be automatically injected.
So it's always recommended to use `pkgs.callPackage` to define Derivations.

View file

@ -1,13 +1,24 @@
# Nixpkgs's Advanced Usage
`callPackage`, `Overriding`, and `Overlays` are the techniques occasionally used when using Nix to customize the build method of Nix packages.
`callPackage`, `Overriding`, and `Overlays` are the techniques occasionally used when
using Nix to customize the build method of Nix packages.
We know that many programs have a large number of build parameters that need to be configured, and different users may want to use different build parameters. This is where `Overriding` and `Overlays` come in handy. Let me give you a few examples I have encountered:
We know that many programs have a large number of build parameters that need to be
configured, and different users may want to use different build parameters. This is where
`Overriding` and `Overlays` come in handy. Let me give you a few examples I have
encountered:
1. [`fcitx5-rime.nix`](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix): By default, `fcitx5-rime` use `rime-data` as the value of `rimeDataPkgs`, but this parameter can be customized by `override`.
2. [`vscode/with-extensions.nix`](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/applications/editors/vscode/with-extensions.nix): This package for VS Code can also be customized by overriding the value of `vscodeExtensions`, thus we can install some custom plugins into VS Code.
- [`nix-vscode-extensions`](https://github.com/nix-community/nix-vscode-extensions): This is a vscode plugin manager implemented by overriding `vscodeExtensions`.
3. [`firefox/common.nix`](https://github.com/NixOS/nixpkgs/blob/416ffcd08f1f16211130cd9571f74322e98ecef6/pkgs/applications/networking/browsers/firefox/common.nix): Firefox has many customizable parameters too.
1. [`fcitx5-rime.nix`](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix):
By default, `fcitx5-rime` use `rime-data` as the value of `rimeDataPkgs`, but this
parameter can be customized by `override`.
2. [`vscode/with-extensions.nix`](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/applications/editors/vscode/with-extensions.nix):
This package for VS Code can also be customized by overriding the value of
`vscodeExtensions`, thus we can install some custom plugins into VS Code.
- [`nix-vscode-extensions`](https://github.com/nix-community/nix-vscode-extensions):
This is a vscode plugin manager implemented by overriding `vscodeExtensions`.
3. [`firefox/common.nix`](https://github.com/NixOS/nixpkgs/blob/416ffcd08f1f16211130cd9571f74322e98ecef6/pkgs/applications/networking/browsers/firefox/common.nix):
Firefox has many customizable parameters too.
4. ...
In short, `callPackage`, `Overriding` and `Overlays` can be used to customize the build parameters of Nix packages.
In short, `callPackage`, `Overriding` and `Overlays` can be used to customize the build
parameters of Nix packages.

View file

@ -1,21 +1,34 @@
# The Ingenious Uses of Multiple nixpkgs Instances
In the section [Downgrade or Upgrade Packages](../nixos-with-flakes/downgrade-or-upgrade-packages.md), we have seen how to instantiate multiple distinct nixpkgs instances using the method `import nixpkgs {...}`, and use them at any submodules via `specialArgs`.
There are numerous applications for this technique, some common ones include:
In the section
[Downgrade or Upgrade Packages](../nixos-with-flakes/downgrade-or-upgrade-packages.md), we
have seen how to instantiate multiple distinct nixpkgs instances using the method
`import nixpkgs {...}`, and use them at any submodules via `specialArgs`. There are
numerous applications for this technique, some common ones include:
1. Instantiate nixpkgs instances with different commit IDs to install various versions of software packages. This approach was used in the previous section [Downgrade or Upgrade Packages](/nixos-with-flakes/downgrade-or-upgrade-packages.md).
1. Instantiate nixpkgs instances with different commit IDs to install various versions of
software packages. This approach was used in the previous section
[Downgrade or Upgrade Packages](/nixos-with-flakes/downgrade-or-upgrade-packages.md).
2. If you wish to utilize overlays without affecting the default nixpkgs instance, you can instantiate a new nixpkgs instance and apply overlays to it.
2. If you wish to utilize overlays without affecting the default nixpkgs instance, you can
instantiate a new nixpkgs instance and apply overlays to it.
- The `nixpkgs.overlays = [...];` mentioned in the previous section on Overlays directly modifies the global nixpkgs instance. If your overlays make changes to some low-level packages, it might impact other modules. One downside is an increase in local compilation (due to cache invalidation), and there might also be functionality issues with the affected packages.
- The `nixpkgs.overlays = [...];` mentioned in the previous section on Overlays
directly modifies the global nixpkgs instance. If your overlays make changes to some
low-level packages, it might impact other modules. One downside is an increase in
local compilation (due to cache invalidation), and there might also be functionality
issues with the affected packages.
3. In cross-system architecture compilation, you can instantiate multiple nixpkgs instances to selectively use QEMU simulation for compilation and cross-compilation in different locations, or to add various GCC compilation parameters.
3. In cross-system architecture compilation, you can instantiate multiple nixpkgs
instances to selectively use QEMU simulation for compilation and cross-compilation in
different locations, or to add various GCC compilation parameters.
In conclusion, instantiating multiple nixpkgs instances is highly advantageous.
## Instantiating `nixpkgs`
Let's first understand how to instantiate a non-global nixpkgs instance. The most common syntax is as follows:
Let's first understand how to instantiate a non-global nixpkgs instance. The most common
syntax is as follows:
```nix
{
@ -68,11 +81,16 @@ Let's first understand how to instantiate a non-global nixpkgs instance. The mos
We have learned in our study of Nix syntax:
> The `import` expression takes a path to another Nix file as an argument and returns the execution result of that Nix file.
> If the argument to `import` is a folder path, it returns the execution result of the `default.nix` file within that folder.
> The `import` expression takes a path to another Nix file as an argument and returns the
> execution result of that Nix file. If the argument to `import` is a folder path, it
> returns the execution result of the `default.nix` file within that folder.
`nixpkgs` is a flake with a `default.nix` file in its root directory. So, `import nixpkgs` essentially returns the execution result of [nixpkgs/default.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/default.nix).
Starting from this file, you can find that the implementation of `import nixpkgs` is in [pkgs/top-level/impure.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/top-level/impure.nix), as excerpted below:
`nixpkgs` is a flake with a `default.nix` file in its root directory. So, `import nixpkgs`
essentially returns the execution result of
[nixpkgs/default.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/default.nix).
Starting from this file, you can find that the implementation of `import nixpkgs` is in
[pkgs/top-level/impure.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/top-level/impure.nix),
as excerpted below:
```nix
# ... skipping some lines
@ -113,12 +131,21 @@ import ./. (builtins.removeAttrs args [ "system" ] // {
})
```
Therefore, `import nixpkgs {...}` effectively calls this function, and the subsequent attribute set becomes the arguments for this function.
Therefore, `import nixpkgs {...}` effectively calls this function, and the subsequent
attribute set becomes the arguments for this function.
## Considerations
When creating multiple nixpkgs instances, there are some details to keep in mind. Here are some common issues to consider:
When creating multiple nixpkgs instances, there are some details to keep in mind. Here are
some common issues to consider:
1. According to the article [1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347) shared by @fbewivpjsbsby, it's not a good practice to use `import` to customize `nixpkgs` in submodules or sub-flakes. This is because each `import` evaluates separately, creating a new nixpkgs instance each time. As the number of configurations increases, this can lead to longer build times and higher memory usage. Therefore, it's recommended to create all nixpkgs instances in the `flake.nix` file.
1. According to the article
[1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347)
shared by @fbewivpjsbsby, it's not a good practice to use `import` to customize
`nixpkgs` in submodules or sub-flakes. This is because each `import` evaluates
separately, creating a new nixpkgs instance each time. As the number of configurations
increases, this can lead to longer build times and higher memory usage. Therefore, it's
recommended to create all nixpkgs instances in the `flake.nix` file.
2. When mixing QEMU simulation and cross-compilation, care should be taken to avoid unnecessary duplication of package compilations.
2. When mixing QEMU simulation and cross-compilation, care should be taken to avoid
unnecessary duplication of package compilations.

View file

@ -1,20 +1,29 @@
# Overlays
In the previous section, we learned about overriding derivations by `pkgs.xxx.override { ... }` or `pkgs.xxx.overrideAttrs (finalAttrs: previousAttrs: { ... });`.
However, this approach will generate a new derivation and doesn't modify the original derivation in `pkgs` instance.
If the derivation you want to override is also used by other Nix packages, they will still use the unmodified derivation.
In the previous section, we learned about overriding derivations by
`pkgs.xxx.override { ... }` or
`pkgs.xxx.overrideAttrs (finalAttrs: previousAttrs: { ... });`. However, this approach
will generate a new derivation and doesn't modify the original derivation in `pkgs`
instance. If the derivation you want to override is also used by other Nix packages, they
will still use the unmodified derivation.
To globally modify derivations in the default nixpkgs instance, Nix provides a feature called "overlays".
To globally modify derivations in the default nixpkgs instance, Nix provides a feature
called "overlays".
In traditional Nix environments, overlays can be configured globally using the `~/.config/nixpkgs/overlays.nix` or `~/.config/nixpkgs/overlays/*.nix` files.
However, with Flakes feature, to ensure system reproducibility, overlays cannot rely on configurations outside of the Git repository.
In traditional Nix environments, overlays can be configured globally using the
`~/.config/nixpkgs/overlays.nix` or `~/.config/nixpkgs/overlays/*.nix` files. However,
with Flakes feature, to ensure system reproducibility, overlays cannot rely on
configurations outside of the Git repository.
When using `flake.nix` to configure NixOS, both Home Manager and NixOS provide the `nixpkgs.overlays` option to define overlays. You can refer to the following documentation for more details:
When using `flake.nix` to configure NixOS, both Home Manager and NixOS provide the
`nixpkgs.overlays` option to define overlays. You can refer to the following documentation
for more details:
- [Home Manager docs - `nixpkgs.overlays`](https://nix-community.github.io/home-manager/options.xhtml#opt-nixpkgs.overlays)
- [Nixpkgs source code - `nixpkgs.overlays`](https://github.com/NixOS/nixpkgs/blob/30d7dd7e7f2cba9c105a6906ae2c9ed419e02f17/nixos/modules/misc/nixpkgs.nix#L169)
Let's take a look at an example module that loads overlays. This module can be used as a Home Manager module or a NixOS module, as the definitions are the same:
Let's take a look at an example module that loads overlays. This module can be used as a
Home Manager module or a NixOS module, as the definitions are the same:
```nix
# ./overlays/default.nix
@ -61,8 +70,10 @@ Let's take a look at an example module that loads overlays. This module can be u
In the above example, we define three overlays.
1. Overlay 1 modifies the `google-chrome` derivation by adding a command-line argument for a proxy server.
2. Overlay 2 modifies the `steam` derivation by adding extra packages and environment variables.
1. Overlay 1 modifies the `google-chrome` derivation by adding a command-line argument for
a proxy server.
2. Overlay 2 modifies the `steam` derivation by adding extra packages and environment
variables.
3. Overlay 3 is defined in a separate file `./overlays/overlay3/default.nix`.
One example of importing the above configuration as a NixOS module is as follows:
@ -94,12 +105,15 @@ This is just an example. Please write your own overlays according to your needs.
## Multiple nixpkgs Instances with different Overlays
The `nixpkgs.overlays = [...];` mentioned above directly modifies the global nixpkgs instance `pkgs`. If your overlays make changes to some low-level packages, it might impact other modules.
One downside is an increase in local compilation (due to cache invalidation),
and there might also be functionality issues with the affected packages.
The `nixpkgs.overlays = [...];` mentioned above directly modifies the global nixpkgs
instance `pkgs`. If your overlays make changes to some low-level packages, it might impact
other modules. One downside is an increase in local compilation (due to cache
invalidation), and there might also be functionality issues with the affected packages.
If you wish to utilize overlays only in a specific location without affecting the default nixpkgs instance, you can instantiate a new nixpkgs instance and apply your overlays to it.
We will discuss how to do this in the next section [The Ingenious Uses of Multiple nixpkgs Instances](./multiple-nixpkgs.md).
If you wish to utilize overlays only in a specific location without affecting the default
nixpkgs instance, you can instantiate a new nixpkgs instance and apply your overlays to
it. We will discuss how to do this in the next section
[The Ingenious Uses of Multiple nixpkgs Instances](./multiple-nixpkgs.md).
## References

View file

@ -1,21 +1,34 @@
# Overriding
In Nix, you can customize Nix packages in `pkgs` by using the `override` function, which allows you to define custom build parameters and returns a new derivation with the overridden values. Let's take a look at an example:
In Nix, you can customize Nix packages in `pkgs` by using the `override` function, which
allows you to define custom build parameters and returns a new derivation with the
overridden values. Let's take a look at an example:
```nix
pkgs.fcitx5-rime.override { rimeDataPkgs = [ ./rime-data-flypy ]; }
```
In the above example, we override the `rimeDataPkgs` parameter of the `fcitx5-rime` derivation to use a custom package called `rime-data-flypy`. This creates a new derivation where `rimeDataPkgs` is overridden, while other parameters remain unchanged.
In the above example, we override the `rimeDataPkgs` parameter of the `fcitx5-rime`
derivation to use a custom package called `rime-data-flypy`. This creates a new derivation
where `rimeDataPkgs` is overridden, while other parameters remain unchanged.
To find out which parameters of a specific package can be overridden, there are a couple of approaches you can follow:
To find out which parameters of a specific package can be overridden, there are a couple
of approaches you can follow:
1. Check the source code of the package in the Nixpkgs repository on GitHub, such as [`fcitx5-rime.nix`](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix). Make sure to select the appropriate branch, such as `nixos-unstable`, if you are using that branch.
2. Use the `nix repl -f '<nixpkgs>'` command to open a Nix REPL and then enter `:e pkgs.fcitx5-rime`. This opens the source code of the package in your default editor, where you can see all the parameters of the package. To learn the basic usage of `nix repl`, you can type `:?` to see the help information.
1. Check the source code of the package in the Nixpkgs repository on GitHub, such as
[`fcitx5-rime.nix`](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix).
Make sure to select the appropriate branch, such as `nixos-unstable`, if you are using
that branch.
2. Use the `nix repl -f '<nixpkgs>'` command to open a Nix REPL and then enter
`:e pkgs.fcitx5-rime`. This opens the source code of the package in your default
editor, where you can see all the parameters of the package. To learn the basic usage
of `nix repl`, you can type `:?` to see the help information.
By using these methods, you can discover the input parameters of a package and determine which ones can be modified using `override`.
By using these methods, you can discover the input parameters of a package and determine
which ones can be modified using `override`.
For example, let's take a look at the source code of [pkgs.hello](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/applications/misc/hello/default.nix):
For example, let's take a look at the source code of
[pkgs.hello](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/applications/misc/hello/default.nix):
```nix
{ callPackage
@ -42,7 +55,8 @@ stdenv.mkDerivation (finalAttrs: {
})
```
In this example, the attributes `pname`, `version`, `src`, and `doCheck` can all be overridden using `overrideAttrs`. For instance:
In this example, the attributes `pname`, `version`, `src`, and `doCheck` can all be
overridden using `overrideAttrs`. For instance:
```nix
helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
@ -50,9 +64,11 @@ helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
});
```
In the above code, we use `overrideAttrs` to override the `doCheck` attribute, while leaving other attributes unchanged.
In the above code, we use `overrideAttrs` to override the `doCheck` attribute, while
leaving other attributes unchanged.
You can also override some default attributes defined in `stdenv.mkDerivation` using `overrideAttrs`. For example:
You can also override some default attributes defined in `stdenv.mkDerivation` using
`overrideAttrs`. For example:
```nix
helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
@ -60,8 +76,11 @@ helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
});
```
In this case, we override the `separateDebugInfo` attribute, which is defined in `stdenv.mkDerivation`, rather than in the source code of `hello`.
In this case, we override the `separateDebugInfo` attribute, which is defined in
`stdenv.mkDerivation`, rather than in the source code of `hello`.
To see all the attributes defined in `stdenv.mkDerivation`, you can check its source code by using `nix repl -f '<nixpkgs>'` and entering `:e stdenv.mkDerivation`.
To see all the attributes defined in `stdenv.mkDerivation`, you can check its source code
by using `nix repl -f '<nixpkgs>'` and entering `:e stdenv.mkDerivation`.
This will open the source code in your default editor. If you're new to using `nix repl`, you can type `:?` to see the help information.
This will open the source code in your default editor. If you're new to using `nix repl`,
you can type `:?` to see the help information.

View file

@ -1,6 +1,7 @@
# Flake Inputs
The `inputs` section in `flake.nix` is an attribute set used to specify the dependencies of the current flake. There are various types of inputs, as shown in the examples below:
The `inputs` section in `flake.nix` is an attribute set used to specify the dependencies
of the current flake. There are various types of inputs, as shown in the examples below:
```nix
{

View file

@ -1,3 +1,5 @@
# Other Usage of Flakes
So far, we have extensively used Flakes to manage NixOS configurations. In this section, I will provide a brief introduction to additional features and command-line options commonly used with Flakes.
So far, we have extensively used Flakes to manage NixOS configurations. In this section, I
will provide a brief introduction to additional features and command-line options commonly
used with Flakes.

View file

@ -1,37 +1,65 @@
# Module System and Custom Options
In our previous NixOS configurations, we set various values for `options` to configure NixOS or Home Manager. These `options` are actually defined in two locations:
In our previous NixOS configurations, we set various values for `options` to configure
NixOS or Home Manager. These `options` are actually defined in two locations:
- NixOS: [nixpkgs/nixos/modules](https://github.com/NixOS/nixpkgs/tree/23.11/nixos/modules), where all NixOS options visible on <https://search.nixos.org/options> are defined.
- Home Manager: [home-manager/modules](https://github.com/nix-community/home-manager/blob/release-23.11/modules), where you can find all its options at <https://nix-community.github.io/home-manager/options.xhtml>.
- NixOS:
[nixpkgs/nixos/modules](https://github.com/NixOS/nixpkgs/tree/23.11/nixos/modules),
where all NixOS options visible on <https://search.nixos.org/options> are defined.
- Home Manager:
[home-manager/modules](https://github.com/nix-community/home-manager/blob/release-23.11/modules),
where you can find all its options at
<https://nix-community.github.io/home-manager/options.xhtml>.
> If you are using nix-darwin too, its configuration is similar, and its module system is implemented in [nix-darwin/modules](https://github.com/LnL7/nix-darwin/tree/master/modules).
> If you are using nix-darwin too, its configuration is similar, and its module system is
> implemented in
> [nix-darwin/modules](https://github.com/LnL7/nix-darwin/tree/master/modules).
The foundation of the aforementioned NixOS Modules and Home Manager Modules is a universal module system implemented in Nixpkgs, found in [lib/modules.nix][lib/modules.nix]. The official documentation for this module system is provided below (even for experienced NixOS users, understanding this can be a challenging task):
The foundation of the aforementioned NixOS Modules and Home Manager Modules is a universal
module system implemented in Nixpkgs, found in [lib/modules.nix][lib/modules.nix]. The
official documentation for this module system is provided below (even for experienced
NixOS users, understanding this can be a challenging task):
- [Module System - Nixpkgs]
Because the documentation for Nixpkgs' module system is lacking, it directly recommends reading another writing guide specifically for NixOS module system, which is clearer but might still be challenging for newcomers:
Because the documentation for Nixpkgs' module system is lacking, it directly recommends
reading another writing guide specifically for NixOS module system, which is clearer but
might still be challenging for newcomers:
- [Writing NixOS Modules - Nixpkgs]
In summary, the module system is implemented by Nixpkgs and is not part of the Nix package manager. Therefore, its documentation is not included in the Nix package manager's documentation. Additionally, both NixOS and Home Manager are based on Nixpkgs' module system implementation.
In summary, the module system is implemented by Nixpkgs and is not part of the Nix package
manager. Therefore, its documentation is not included in the Nix package manager's
documentation. Additionally, both NixOS and Home Manager are based on Nixpkgs' module
system implementation.
## What is the Purpose of the Module System?
As ordinary users, using various options implemented by NixOS and Home Manager based on the module system is sufficient to meet most of our needs. So, what are the benefits of delving into the module system for us?
As ordinary users, using various options implemented by NixOS and Home Manager based on
the module system is sufficient to meet most of our needs. So, what are the benefits of
delving into the module system for us?
In the earlier discussion on modular configuration, the core idea was to split the configuration into multiple modules and then import these modules using `imports = [ ... ];`. This is the most basic usage of the module system. However, using only `imports = [ ... ];` allows us to import configurations defined in the module as they are without any customization, which limits flexibility. In simple configurations, this method is sufficient, but if the configuration is more complex, it becomes inadequate.
In the earlier discussion on modular configuration, the core idea was to split the
configuration into multiple modules and then import these modules using
`imports = [ ... ];`. This is the most basic usage of the module system. However, using
only `imports = [ ... ];` allows us to import configurations defined in the module as they
are without any customization, which limits flexibility. In simple configurations, this
method is sufficient, but if the configuration is more complex, it becomes inadequate.
To illustrate the drawback, let's consider an example. Suppose I manage four NixOS hosts, A, B, C, and D. I want to achieve the following goals while minimizing configuration repetition:
To illustrate the drawback, let's consider an example. Suppose I manage four NixOS hosts,
A, B, C, and D. I want to achieve the following goals while minimizing configuration
repetition:
- All hosts (A, B, C, and D) need to enable the Docker service and set it to start at boot.
- Host A should change the Docker storage driver to `btrfs` while keeping other settings the same.
- All hosts (A, B, C, and D) need to enable the Docker service and set it to start at
boot.
- Host A should change the Docker storage driver to `btrfs` while keeping other settings
the same.
- Hosts B and C, located in China, need to set a domestic mirror in Docker configuration.
- Host C, located in the United States, has no special requirements.
- Host D, a desktop machine, needs to set an HTTP proxy to accelerate Docker downloads.
If we purely use `imports`, we might have to split the configuration into several modules like this and then import different modules for each host:
If we purely use `imports`, we might have to split the configuration into several modules
like this and then import different modules for each host:
```bash
tree
@ -42,11 +70,18 @@ If we purely use `imports`, we might have to split the configuration into severa
└── docker-proxy.nix # Imports docker-default.nix and sets an HTTP proxy
```
Doesn't this configuration seem redundant? This is still a simple example; if we have more machines with greater configuration differences, the redundancy becomes even more apparent.
Doesn't this configuration seem redundant? This is still a simple example; if we have more
machines with greater configuration differences, the redundancy becomes even more
apparent.
Clearly, we need other means to address this redundant configuration issue, and customizing some of our own `options` is an excellent choice.
Clearly, we need other means to address this redundant configuration issue, and
customizing some of our own `options` is an excellent choice.
Before delving into the study of the module system, I emphasize once again that the following content is not necessary to learn and use. Many NixOS users have not customized any `options` and are satisfied with simply using `imports` to meet their needs. If you are a newcomer, consider learning this part when you encounter problems that `imports` cannot solve. That's completely okay.
Before delving into the study of the module system, I emphasize once again that the
following content is not necessary to learn and use. Many NixOS users have not customized
any `options` and are satisfied with simply using `imports` to meet their needs. If you
are a newcomer, consider learning this part when you encounter problems that `imports`
cannot solve. That's completely okay.
## Basic Structure and Usage
@ -70,12 +105,17 @@ The basic structure of modules defined in Nixpkgs is as follows:
}
```
Among these, we are already familiar with `imports = [ ... ];`, but the other two parts are yet to be explored. Let's have a brief introduction here:
Among these, we are already familiar with `imports = [ ... ];`, but the other two parts
are yet to be explored. Let's have a brief introduction here:
- `options = { ... };`: Similar to variable declarations in programming languages, it is used to declare configurable options.
- `config = { ... };`: Similar to variable assignments in programming languages, it is used to assign values to the options declared in `options`.
- `options = { ... };`: Similar to variable declarations in programming languages, it is
used to declare configurable options.
- `config = { ... };`: Similar to variable assignments in programming languages, it is
used to assign values to the options declared in `options`.
The most typical usage is to, within the same Nixpkgs module, set values for other `options` in `config = { .. };` based on the current values declared in `options = { ... };`. This achieves the functionality of parameterized configuration.
The most typical usage is to, within the same Nixpkgs module, set values for other
`options` in `config = { .. };` based on the current values declared in
`options = { ... };`. This achieves the functionality of parameterized configuration.
It's easier to understand with a direct example:
@ -126,10 +166,12 @@ in {
The module defined above introduces three `options`:
- `programs.foo.enable`: Used to control whether to enable this module.
- `programs.foo.package`: Allows customization of the `foo` package, such as using different versions, setting different compilation parameters, and so on.
- `programs.foo.package`: Allows customization of the `foo` package, such as using
different versions, setting different compilation parameters, and so on.
- `programs.foo.extraConfig`: Used for customizing the configuration file of `foo`.
Then, in the `config` section, based on the values declared in these three variables in `options`, different settings are applied:
Then, in the `config` section, based on the values declared in these three variables in
`options`, different settings are applied:
- If `programs.foo.enable` is `false` or undefined, no settings are applied.
- This is achieved using `lib.mkIf`.
@ -137,7 +179,8 @@ Then, in the `config` section, based on the values declared in these three varia
- Add `programs.foo.package` to `home.packages` to install it in the user environment.
- Write the value of `programs.foo.extraConfig` to `~/.config/foo/foorc`.
This way, we can import this module in another Nix file and achieve custom configuration for `foo` by setting the `options` defined here. For example:
This way, we can import this module in another Nix file and achieve custom configuration
for `foo` by setting the `options` defined here. For example:
```nix
# ./bar.nix
@ -158,11 +201,15 @@ This way, we can import this module in another Nix file and achieve custom confi
}
```
In the example above, the way we assign values to `options` is actually a kind of **abbreviation**. When a module declares only `options` without `config` (and other special parameters of the module system), we can omit the `config` prefix and directly use the name of `options` for assignment.
In the example above, the way we assign values to `options` is actually a kind of
**abbreviation**. When a module declares only `options` without `config` (and other
special parameters of the module system), we can omit the `config` prefix and directly use
the name of `options` for assignment.
## Assignment and Lazy Evaluation in the Module System
The module system takes full advantage of Nix's lazy evaluation feature, which is crucial for achieving parameterized configuration.
The module system takes full advantage of Nix's lazy evaluation feature, which is crucial
for achieving parameterized configuration.
Let's start with a simple example:
@ -201,50 +248,80 @@ Let's start with a simple example:
}
```
In the examples 1, 2, and 3 of the above configuration, the value of `config.warnings` depends on the value of `config.foo`, but their implementation methods are different. Save the above configuration as `flake.nix`, and then use the command `nix eval .#nixosConfigurations.test.config.warnings` to test examples 1, 2, and 3 separately. You will find that examples 1 and 3 work correctly, while example 2 results in an error: `error: infinite recursion encountered`.
In the examples 1, 2, and 3 of the above configuration, the value of `config.warnings`
depends on the value of `config.foo`, but their implementation methods are different. Save
the above configuration as `flake.nix`, and then use the command
`nix eval .#nixosConfigurations.test.config.warnings` to test examples 1, 2, and 3
separately. You will find that examples 1 and 3 work correctly, while example 2 results in
an error: `error: infinite recursion encountered`.
Let's explain each case:
1. Example 1 evaluation flow: `config.warnings` => `config.foo` => `config`
1. First, Nix attempts to compute the value of `config.warnings` but finds that it depends on `config.foo`.
2. Next, Nix tries to compute the value of `config.foo`, which depends on its outer `config`.
3. Nix attempts to compute the value of `config`, and since the contents not genuinely used by `config.foo` are lazily evaluated by Nix, there is no recursive dependency on `config.warnings` at this point.
4. The evaluation of `config.foo` is completed, followed by the assignment of `config.warnings`, and the computation ends.
1. First, Nix attempts to compute the value of `config.warnings` but finds that it
depends on `config.foo`.
2. Next, Nix tries to compute the value of `config.foo`, which depends on its outer
`config`.
3. Nix attempts to compute the value of `config`, and since the contents not genuinely
used by `config.foo` are lazily evaluated by Nix, there is no recursive dependency
on `config.warnings` at this point.
4. The evaluation of `config.foo` is completed, followed by the assignment of
`config.warnings`, and the computation ends.
2. Example 2: `config` => `config.foo` => `config`
1. Initially, Nix tries to compute the value of `config` but finds that it depends on `config.foo`.
2. Next, Nix attempts to compute the value of `config.foo`, which depends on its outer `config`.
3. Nix tries to compute the value of `config`, and this loops back to step 1, leading to an infinite recursion and eventually an error.
1. Initially, Nix tries to compute the value of `config` but finds that it depends on
`config.foo`.
2. Next, Nix attempts to compute the value of `config.foo`, which depends on its outer
`config`.
3. Nix tries to compute the value of `config`, and this loops back to step 1, leading
to an infinite recursion and eventually an error.
3. Example 3: The only difference from example 2 is the use of `lib.mkIf` to address the infinite recursion issue.
3. Example 3: The only difference from example 2 is the use of `lib.mkIf` to address the
infinite recursion issue.
The key lies in the function `lib.mkIf`. When using `lib.mkIf` to define `config`, it will be lazily evaluated by Nix. This means that the calculation of `config = lib.mkIf ...` will only occur after the evaluation of `config.foo` is completed.
The key lies in the function `lib.mkIf`. When using `lib.mkIf` to define `config`, it will
be lazily evaluated by Nix. This means that the calculation of `config = lib.mkIf ...`
will only occur after the evaluation of `config.foo` is completed.
The Nixpkgs module system provides a series of functions similar to `lib.mkIf` for parameterized configuration and intelligent module merging:
The Nixpkgs module system provides a series of functions similar to `lib.mkIf` for
parameterized configuration and intelligent module merging:
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.
4. Check [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
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]
- [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.
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.
## How to Selectively Import Modules {#selectively-import-modules}
In the examples above, we have introduced how to enable or disable certain features through custom options. However, our code implementations are all within the same Nix file. If our modules are scattered across different files, how can we achieve selective import?
In the examples above, we have introduced how to enable or disable certain features
through custom options. However, our code implementations are all within the same Nix
file. If our modules are scattered across different files, how can we achieve selective
import?
Let's first look at some common incorrect usage patterns, and then introduce the correct way to do it.
Let's first look at some common incorrect usage patterns, and then introduce the correct
way to do it.
### Incorrect Usage #1 - Using `imports` in `config = { ... };` {#wrong-usage-1}
@ -283,22 +360,33 @@ The first thought might be to directly use `imports` in `config = { ... };`, lik
}
```
But this won't work.
You can try save the above `flake.nix` in a new directory, and then run `nix eval .#nixosConfigurations.test.config.warnings` in it, some error like `error: The option 'imports' does not exist.` will be encountered.
But this won't work. You can try save the above `flake.nix` in a new directory, and then
run `nix eval .#nixosConfigurations.test.config.warnings` in it, some error like
`error: The option 'imports' does not exist.` will be encountered.
This is because `config` is a regular attribute set, while `imports` is a special parameter of the module system. There is no such definition as `config.imports`.
This is because `config` is a regular attribute set, while `imports` is a special
parameter of the module system. There is no such definition as `config.imports`.
### Correct Usage #1 - Define Individual `options` for All Modules That Require Conditional Import {#correct-usage-1}
This is the most recommended method. Modules in NixOS systems are implemented in this way, and searching for `enable` in <https://search.nixos.org/options> will show a large number of system modules that can be enabled or disabled through the `enable` option.
This is the most recommended method. Modules in NixOS systems are implemented in this way,
and searching for `enable` in <https://search.nixos.org/options> will show a large number
of system modules that can be enabled or disabled through the `enable` option.
The specific writing method has been introduced in the previous [Basic Structure and Usage](#basic-structure-and-usage) section and will not be repeated here.
The specific writing method has been introduced in the previous
[Basic Structure and Usage](#basic-structure-and-usage) section and will not be repeated
here.
The disadvantage of this method is that all Nix modules that require conditional import need to be modified, moving all configuration declarations in the module to the `config = { ... };` code block, increasing code complexity and being less friendly to beginners.
The disadvantage of this method is that all Nix modules that require conditional import
need to be modified, moving all configuration declarations in the module to the
`config = { ... };` code block, increasing code complexity and being less friendly to
beginners.
### Correct Usage #2 - Use `lib.optionals` in `imports = [];` {#correct-usage-2}
The main advantage of this method is that it is much simpler than the methods previously introduced, requiring no modification to the module content, just using `lib.optionals` in `imports` to decide whether to import a module or not.
The main advantage of this method is that it is much simpler than the methods previously
introduced, requiring no modification to the module content, just using `lib.optionals` in
`imports` to decide whether to import a module or not.
> Details about how `lib.optionals` works: <https://noogle.dev/f/lib/optionals>
@ -336,14 +424,19 @@ Let's look at an example directly:
{ warnings = ["foo"];}
```
Save the two Nix files above in a folder, and then run `nix eval .#nixosConfigurations.test.config.warnings` in the folder, and the operation is normal:
Save the two Nix files above in a folder, and then run
`nix eval .#nixosConfigurations.test.config.warnings` in the folder, and the operation is
normal:
```bash
nix eval .#nixosConfigurations.test.config.warnings
[ "foo" ]
```
One thing to note here is that **you cannot use parameters passed by `_module.args` in `imports =[ ... ];`**. We have already provided a detailed explanation in the previous section [Passing Non-default Parameters to Submodules](../nixos-with-flakes/nixos-with-flakes-enabled#pass-non-default-parameters-to-submodules).
One thing to note here is that **you cannot use parameters passed by `_module.args` in
`imports =[ ... ];`**. We have already provided a detailed explanation in the previous
section
[Passing Non-default Parameters to Submodules](../nixos-with-flakes/nixos-with-flakes-enabled#pass-non-default-parameters-to-submodules).
## References
@ -354,8 +447,13 @@ One thing to note here is that **you cannot use parameters passed by `_module.ar
- [Writing NixOS Modules - Nixpkgs]
[lib/modules.nix]: https://github.com/NixOS/nixpkgs/blob/23.11/lib/modules.nix#L995
[Module System - Nixpkgs]: https://github.com/NixOS/nixpkgs/blob/23.11/doc/module-system/module-system.chapter.md
[Writing NixOS Modules - Nixpkgs]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/writing-modules.chapter.md
[Option Definitions - NixOS]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-def.section.md
[Option Declarations - NixOS]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-declarations.section.md
[Options Types - NixOS]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-types.section.md
[Module System - Nixpkgs]:
https://github.com/NixOS/nixpkgs/blob/23.11/doc/module-system/module-system.chapter.md
[Writing NixOS Modules - Nixpkgs]:
https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/writing-modules.chapter.md
[Option Definitions - NixOS]:
https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-def.section.md
[Option Declarations - NixOS]:
https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-declarations.section.md
[Options Types - NixOS]:
https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-types.section.md

View file

@ -1,15 +1,27 @@
# Flake Outputs
In `flake.nix`, the `outputs` section defines the different outputs that a flake can produce during its build process. A flake can have multiple outputs simultaneously, which can include but are not limited to the following:
In `flake.nix`, the `outputs` section defines the different outputs that a flake can
produce during its build process. A flake can have multiple outputs simultaneously, which
can include but are not limited to the following:
- Nix packages: These are named `apps.<system>.<name>`, `packages.<system>.<name>`, or `legacyPackages.<system>.<name>`. You can build a specific package using the command `nix build .#<name>`.
- Nix helper functions: These are named `lib.<name>` and serve as libraries for other flakes to use.
- Nix development environments: These are named `devShells` and provide isolated development environments. They can be accessed using the command `nix develop`.
- NixOS configurations: These are named `nixosConfiguration` and represent specific NixOS system configurations. You can activate a configuration using the command `nixos-rebuild switch --flake .#<name>`.
- Nix templates: These are named `templates` and can be used as a starting point for creating new projects. You can generate a project using the command `nix flake init --template <reference>`.
- Other user-defined outputs: These outputs can be defined by the user and may be used by other Nix-related tools.
- Nix packages: These are named `apps.<system>.<name>`, `packages.<system>.<name>`, or
`legacyPackages.<system>.<name>`. You can build a specific package using the command
`nix build .#<name>`.
- Nix helper functions: These are named `lib.<name>` and serve as libraries for other
flakes to use.
- Nix development environments: These are named `devShells` and provide isolated
development environments. They can be accessed using the command `nix develop`.
- NixOS configurations: These are named `nixosConfiguration` and represent specific NixOS
system configurations. You can activate a configuration using the command
`nixos-rebuild switch --flake .#<name>`.
- Nix templates: These are named `templates` and can be used as a starting point for
creating new projects. You can generate a project using the command
`nix flake init --template <reference>`.
- Other user-defined outputs: These outputs can be defined by the user and may be used by
other Nix-related tools.
Here's an example excerpt from the NixOS Wiki that demonstrates the structure of the `outputs` section:
Here's an example excerpt from the NixOS Wiki that demonstrates the structure of the
`outputs` section:
```nix
{

View file

@ -1,12 +1,15 @@
# Usage of the New CLI
Once you have enabled the `nix-command` and `flakes` features, you can start using the new generation Nix command-line tools provided by [New Nix Commands][New Nix Commands].
In this section, we will focus on two commands: `nix shell` and `nix run`.
Other important commands like `nix build` will be discussed in detail in [`nix develop` & `pkgs.mkShell`](/development/intro.md)
Once you have enabled the `nix-command` and `flakes` features, you can start using the new
generation Nix command-line tools provided by [New Nix Commands][New Nix Commands]. In
this section, we will focus on two commands: `nix shell` and `nix run`. Other important
commands like `nix build` will be discussed in detail in
[`nix develop` & `pkgs.mkShell`](/development/intro.md)
## `nix shell`
The `nix shell` command allows you to enter an environment with the specified Nix package and opens an interactive shell within that environment:
The `nix shell` command allows you to enter an environment with the specified Nix package
and opens an interactive shell within that environment:
```shell
# hello is not available
@ -34,7 +37,9 @@ Hello, world!
## `nix run`
On the other hand, `nix run` creates an environment with the specified Nix package and directly runs that package within the environment (without installing it into the system environment):
On the other hand, `nix run` creates an environment with the specified Nix package and
directly runs that package within the environment (without installing it into the system
environment):
```shell
# hello is not available
@ -46,15 +51,19 @@ hello: command not found
Hello, world!
```
Since `nix run` directly executes the Nix package, the package specified as the argument must generate an executable program.
Since `nix run` directly executes the Nix package, the package specified as the argument
must generate an executable program.
According to the `nix run --help` documentation, `nix run` executes the command `<out>/bin/<name>`, where `<out>` is the root directory of the derivation and `<name>` is selected in the following order:
According to the `nix run --help` documentation, `nix run` executes the command
`<out>/bin/<name>`, where `<out>` is the root directory of the derivation and `<name>` is
selected in the following order:
- The `meta.mainProgram` attribute of the derivation
- The `pname` attribute of the derivation
- The content of the `name` attribute of the derivation with the version number removed
For example, in the case of the 'hello' package we tested earlier, `nix run` actually executes the program `$out/bin/hello`.
For example, in the case of the 'hello' package we tested earlier, `nix run` actually
executes the program `$out/bin/hello`.
Here are two more examples with detailed explanations of the relevant parameters:
@ -73,13 +82,16 @@ echo "Hello Nix" | nix run "github:NixOS/nixpkgs/nixos-unstable#ponysay"
## Common Use Cases for `nix run` and `nix shell`
These commands are commonly used for running programs temporarily. For example, if I want to clone my configuration repository using Git on a new NixOS host without Git installed, I can use the following command:
These commands are commonly used for running programs temporarily. For example, if I want
to clone my configuration repository using Git on a new NixOS host without Git installed,
I can use the following command:
```bash
nix run nixpkgs#git clone git@github.com:ryan4yin/nix-config.git
```
Alternatively, I can use `nix shell` to enter an environment with Git and then run the `git clone` command:
Alternatively, I can use `nix shell` to enter an environment with Git and then run the
`git clone` command:
```bash
nix shell nixpkgs#git

View file

@ -2,43 +2,94 @@
## The Pain of NixOS Beginners - Documentation and Flakes
NixOS is a highly distinctive Linux distribution built upon the Nix package manager, with a design philosophy that sets it apart from traditional distributions like Ubuntu, CentOS, Arch Linux and others.
NixOS is a highly distinctive Linux distribution built upon the Nix package manager, with
a design philosophy that sets it apart from traditional distributions like Ubuntu, CentOS,
Arch Linux and others.
One of NixOS's major advantages over other distributions lies in its reproducibility and declarative configuration, allowing users to replicate consistent system environments across multiple machines.
One of NixOS's major advantages over other distributions lies in its reproducibility and
declarative configuration, allowing users to replicate consistent system environments
across multiple machines.
While NixOS is powerful, its strength also comes with increased system complexity. This makes it more challenging for newcomers. One major challenge is that the knowledge accumulated on other Linux distributions is not easily transferable to NixOS. Another is that official and community documentation is often scattered and outdated. These issues have troubled many NixOS beginners.
While NixOS is powerful, its strength also comes with increased system complexity. This
makes it more challenging for newcomers. One major challenge is that the knowledge
accumulated on other Linux distributions is not easily transferable to NixOS. Another is
that official and community documentation is often scattered and outdated. These issues
have troubled many NixOS beginners.
One can observe these issues with the experimental feature of the Nix package manager called Flakes. Inspired by package managers like npm and Cargo, Flakes uses `flake.nix` to record all external dependencies and `flake.lock` to lock their versions. This significantly enhances the reproducibility and composability of the Nix package manager and NixOS configurations.
One can observe these issues with the experimental feature of the Nix package manager
called Flakes. Inspired by package managers like npm and Cargo, Flakes uses `flake.nix` to
record all external dependencies and `flake.lock` to lock their versions. This
significantly enhances the reproducibility and composability of the Nix package manager
and NixOS configurations.
Flakes' advantages have made it widely popular within the community: according to official surveys, over half of the new Nix repositories created on GitHub now utilize Flakes.
Flakes' advantages have made it widely popular within the community: according to official
surveys, over half of the new Nix repositories created on GitHub now utilize Flakes.
However, to maintain stability, the official documentation covers barely any Flakes-related content. This has left many Nix/NixOS users feeling confused. They see everyone using Flakes and want to learn it too, but find nowhere to start, often having to piece together scattered information, search through Nixpkgs source code, or seek help from more experienced users.
However, to maintain stability, the official documentation covers barely any
Flakes-related content. This has left many Nix/NixOS users feeling confused. They see
everyone using Flakes and want to learn it too, but find nowhere to start, often having to
piece together scattered information, search through Nixpkgs source code, or seek help
from more experienced users.
## The Origin of This Book
This book originated from my scattered notes when I first started with NixOS.
In April of this year (2023), when I got into NixOS, I fell in love with its design philosophy. At the recommendation of a friend, I learned about Nix's Flakes experimental feature. After comparing Flakes with the traditional NixOS configuration method, I realized that only a Flakes-enabled NixOS met my expectations. Consequently, I completely ignored the traditional Nix configuration approach and directly learned to configure my NixOS system using Flakes during my initial steps.
In April of this year (2023), when I got into NixOS, I fell in love with its design
philosophy. At the recommendation of a friend, I learned about Nix's Flakes experimental
feature. After comparing Flakes with the traditional NixOS configuration method, I
realized that only a Flakes-enabled NixOS met my expectations. Consequently, I completely
ignored the traditional Nix configuration approach and directly learned to configure my
NixOS system using Flakes during my initial steps.
Throughout my learning process, I found that there were very few beginner-friendly Flakes resources. The vast majority of documentation focused on the traditional Nix configuration approach, forcing me to extract the information I needed from various sources such as the NixOS Wiki, Zero to Nix, Nixpkgs Manual, and Nixpkgs source code while disregarding any non-Flakes-related content. This learning journey was quite convoluted and painful. To prevent future stumbling, I diligently documented numerous scattered notes as I progressed.
Throughout my learning process, I found that there were very few beginner-friendly Flakes
resources. The vast majority of documentation focused on the traditional Nix configuration
approach, forcing me to extract the information I needed from various sources such as the
NixOS Wiki, Zero to Nix, Nixpkgs Manual, and Nixpkgs source code while disregarding any
non-Flakes-related content. This learning journey was quite convoluted and painful. To
prevent future stumbling, I diligently documented numerous scattered notes as I
progressed.
With some experience under my belt, in early May of this year, I switched my main PC to NixOS. After organizing and refining my NixOS newcomer notes, I published them on my blog[^1] and shared them in the NixOS Chinese community. The Chinese community responded positively, and based on their advice, I translated the article into English and shared it on Reddit, receiving strong feedback[^2].
With some experience under my belt, in early May of this year, I switched my main PC to
NixOS. After organizing and refining my NixOS newcomer notes, I published them on my
blog[^1] and shared them in the NixOS Chinese community. The Chinese community responded
positively, and based on their advice, I translated the article into English and shared it
on Reddit, receiving strong feedback[^2].
The positive reception of this shared document encouraged me and drove me to continue improving it. Through continuous updates, the content of this document expanded to over 20,000 words. Some readers suggested that the reading experience could be improved, leading me to their suggestions[^3]. As a result, I migrated the article's content to a GitHub repository, established a dedicated documentation site, and adjusted the presentation to make it more aligned with a beginner's guide rather than a personal notebook.
The positive reception of this shared document encouraged me and drove me to continue
improving it. Through continuous updates, the content of this document expanded to over
20,000 words. Some readers suggested that the reading experience could be improved,
leading me to their suggestions[^3]. As a result, I migrated the article's content to a
GitHub repository, established a dedicated documentation site, and adjusted the
presentation to make it more aligned with a beginner's guide rather than a personal
notebook.
And so, a bilingual open-source book was born, which I named "<NixOS & Flakes Book>" with the Chinese title "NixOS & Flakes 新手指南" ("NixOS & Flakes Beginner's Guide").
And so, a bilingual open-source book was born, which I named "<NixOS & Flakes Book>" with
the Chinese title "NixOS & Flakes 新手指南" ("NixOS & Flakes Beginner's Guide").
This open-source book's content evolved step by step as I used NixOS and engaged with readers. The sense of accomplishment from readers' positive feedback has been my greatest motivation for updates. Some readers' feedback has been immensely helpful in its "evolution." Initially, I only wanted to share my experiences with NixOS in a somewhat casual manner, but it unexpectedly turned into an open-source book. Its readership abroad even surpassed that within my own country, and it garnered many stars - a result I never anticipated.
This open-source book's content evolved step by step as I used NixOS and engaged with
readers. The sense of accomplishment from readers' positive feedback has been my greatest
motivation for updates. Some readers' feedback has been immensely helpful in its
"evolution." Initially, I only wanted to share my experiences with NixOS in a somewhat
casual manner, but it unexpectedly turned into an open-source book. Its readership abroad
even surpassed that within my own country, and it garnered many stars - a result I never
anticipated.
I am grateful to all friends who have contributed to this book and offered suggestions, and I appreciate all the support and encouragement from the readers. Without all of you, this book's content might have remained confined to my personal blog, and it wouldn't have reached its current form.
I am grateful to all friends who have contributed to this book and offered suggestions,
and I appreciate all the support and encouragement from the readers. Without all of you,
this book's content might have remained confined to my personal blog, and it wouldn't have
reached its current form.
## The Features of This Book
1. Focused on NixOS and Flakes, disregarding the traditional Nix configuration approach.
2. Beginner-friendly, with explanations from the perspective of NixOS newcomers who have some experience with Linux usage and programming.
2. Beginner-friendly, with explanations from the perspective of NixOS newcomers who have
some experience with Linux usage and programming.
3. Step-by-step, progressive learning.
4. Most of the chapters in this book provide reference links at the end, making it easy for readers to delve deeper into the topics and evaluate the content's credibility.
5. Coherent content, well-organized, and structured. Readers can either read the book gradually or quickly find the information they need.
4. Most of the chapters in this book provide reference links at the end, making it easy
for readers to delve deeper into the topics and evaluate the content's credibility.
5. Coherent content, well-organized, and structured. Readers can either read the book
gradually or quickly find the information they need.
## Donation
@ -51,15 +102,19 @@ If you find this book helpful, please consider donating to support its developme
## Feedback and Discussion
Im not an expert on NixOS, and Ive only been using NixOS for less than 9 months until now(2024-02),
so there must be some misconceptions or complex cases in the book.
If anyone finds anything incorrect or have any questions / suggestions, just let me know about it by opening an issue or joining the discussion on [GitHub Discussions](https://github.com/ryan4yin/nixos-and-flakes-book/discussions). I'm happy to continue improving the content of this book.
Im not an expert on NixOS, and Ive only been using NixOS for less than 9 months until
now(2024-02), so there must be some misconceptions or complex cases in the book. If anyone
finds anything incorrect or have any questions / suggestions, just let me know about it by
opening an issue or joining the discussion on
[GitHub Discussions](https://github.com/ryan4yin/nixos-and-flakes-book/discussions). I'm
happy to continue improving the content of this book.
The reason why I wrote this little book was only because no one in the community did it for me, who was a beginner at the time, so I chose to do it myself.
Even though I knew I could make mistakes, it's much better than do nothing.
The reason why I wrote this little book was only because no one in the community did it
for me, who was a beginner at the time, so I chose to do it myself. Even though I knew I
could make mistakes, it's much better than do nothing.
My hope is that this book can help more people, enabling them to experience the joys of NixOS.
Hope you like it!
My hope is that this book can help more people, enabling them to experience the joys of
NixOS. Hope you like it!
## Historical Feedback and Discussions on This Book
@ -76,6 +131,11 @@ Chinese feedback and discussions:
- [[2023-06-24] NixOS 与 Flakes | 一份非官方的新手指南 - v2ex 社区](https://www.v2ex.com/t/951190#reply9)
- [[2023-06-24] NixOS 与 Flakes | 一份非官方的新手指南 - 0xffff 社区](https://0xffff.one/d/1547-nixos-yu-flakes-yi-fen-fei-guan)
[^1]: [NixOS & Nix Flakes - A Guide for Beginners - This Cute World](https://thiscute.world/en/posts/nixos-and-flake-basics/)
[^2]: [NixOS & Nix Flakes - A Guide for Beginners - Reddit](https://www.reddit.com/r/NixOS/comments/13dxw9d/nixos_nix_flakes_a_guide_for_beginners/)
[^3]: [Updates: NixOS & Nix Flakes - A Guide for Beginners - Reddit](https://www.reddit.com/r/NixOS/comments/14fvz1q/comment/jp4xhj3/?context=3)
[^1]:
[NixOS & Nix Flakes - A Guide for Beginners - This Cute World](https://thiscute.world/en/posts/nixos-and-flake-basics/)
[^2]:
[NixOS & Nix Flakes - A Guide for Beginners - Reddit](https://www.reddit.com/r/NixOS/comments/13dxw9d/nixos_nix_flakes_a_guide_for_beginners/)
[^3]:
[Updates: NixOS & Nix Flakes - A Guide for Beginners - Reddit](https://www.reddit.com/r/NixOS/comments/14fvz1q/comment/jp4xhj3/?context=3)

View file

@ -1,17 +1,29 @@
# Basics of the Nix Language
The Nix language is essential for declaring configurations to be built by Nix. To fully enjoy the benefits of NixOS and Flakes, it is necessary to grasp the fundamentals of this language.
The Nix language is essential for declaring configurations to be built by Nix. To fully
enjoy the benefits of NixOS and Flakes, it is necessary to grasp the fundamentals of this
language.
The Nix language is a straightforward functional language. If you have some programming experience, it should take you less than 2 hours to grasp its basics.
The Nix language is a straightforward functional language. If you have some programming
experience, it should take you less than 2 hours to grasp its basics.
The community already has a lot of good Nix language tutorials, so I won't remake the wheel.
To get started, I recommend reading the following resources for a quick introduction to the Nix language:
The community already has a lot of good Nix language tutorials, so I won't remake the
wheel. To get started, I recommend reading the following resources for a quick
introduction to the Nix language:
1. [**Nix Language Basics - nix.dev**](https://nix.dev/tutorials/first-steps/nix-language): This tutorial provides a comprehensive overview of the basics of the Nix language, recommended for beginners.
1. [**A tour of Nix**](https://nixcloud.io/tour/?id=introduction/nix): An online interactive tutorial focuses on programming language constructs and how Nix can be algorithmically used to solve problems.
1. [**Nix Language - Nix Reference Manual**](https://nixos.org/manual/nix/stable/language/): The official documentation of the Nix language.
1. nix.dev and other user-friendly tutorials are suitable for starter reading only, and **neither of them fully introduces the full syntax of Nix**. If you encounter a new syntax that you have not come across before, please refer to this official document.
1. <https://noogle.dev/> is a Nix function library search engine that can help you quickly find the functions you need and their usage, which is very practical.
1. [**Nix Language Basics - nix.dev**](https://nix.dev/tutorials/first-steps/nix-language):
This tutorial provides a comprehensive overview of the basics of the Nix language,
recommended for beginners.
1. [**A tour of Nix**](https://nixcloud.io/tour/?id=introduction/nix): An online
interactive tutorial focuses on programming language constructs and how Nix can be
algorithmically used to solve problems.
1. [**Nix Language - Nix Reference Manual**](https://nixos.org/manual/nix/stable/language/):
The official documentation of the Nix language.
1. nix.dev and other user-friendly tutorials are suitable for starter reading only, and
**neither of them fully introduces the full syntax of Nix**. If you encounter a new
syntax that you have not come across before, please refer to this official document.
1. <https://noogle.dev/> is a Nix function library search engine that can help you quickly
find the functions you need and their usage, which is very practical.
It's okay to have a rough impression of the syntax for now.
You can come back to review the syntax when you find something you don't understand later.
It's okay to have a rough impression of the syntax for now. You can come back to review
the syntax when you find something you don't understand later.

View file

@ -2,9 +2,14 @@
## 社区
- [Nix 社区官方页](https://nixos.org/community/): 包含官方社区、论坛、RFCs、官方团队的架构以及沟通贡献渠道等信息。
- [Nix 社区官方页](https://nixos.org/community/): 包含官方社区、论坛、RFCs、官方团队的架构
以及沟通贡献渠道等信息。
- [Nix Channel Status](https://status.nixos.org/): Nix 各 Channels 的当前的构建状态。
- [nix-community/NUR](https://github.com/nix-community/NUR): Nixpkgs 虽然包含了大量的软件包但是因为审核速度、许可协议等原因总有些包并未被及时收录。NUR 则是一个去中心化的 Nix 包 仓库,任何人都可以创建自己的私人仓库并将其加入到 NUR 中以便其他人使用。如果你想要使用 Nixpkgs 中没有的包,可以尝试在这里寻找。如果你希望将自己打的 Nix 包分享给别人,可以根据 NUR 的 README 创建并分享你自己的私人 Nix 仓库。
- [nix-community/NUR](https://github.com/nix-community/NUR): Nixpkgs 虽然包含了大量的软件
但是因为审核速度、许可协议等原因总有些包并未被及时收录。NUR 则是一个去中心化的 Nix
包 仓库,任何人都可以创建自己的私人仓库并将其加入到 NUR 中以便其他人使用。如果你想要使用
Nixpkgs 中没有的包,可以尝试在这里寻找。如果你希望将自己打的 Nix 包分享给别人,可以根据
NUR 的 README 创建并分享你自己的私人 Nix 仓库。
中文社区:
@ -17,20 +22,33 @@
## 文档与视频
逐渐熟悉 Nix 这一套工具链后,可以进一步读一读 Nix 的三本手册以及其他社区文档,挖掘更多的玩法:
逐渐熟悉 Nix 这一套工具链后,可以进一步读一读 Nix 的三本手册以及其他社区文档,挖掘更多的玩
法:
- [Eelco Dolstra - The Purely Functional Software Deployment Model - 2006](https://edolstra.github.io/pubs/phd-thesis.pdf): Eelco Dolstra 开创性的博士论文,介绍了 Nix 包管理器的设计思想。
- [Nix Reference Manual](https://nixos.org/manual/nix/stable/package-management/profiles.html): Nix 包管理器使用手册,主要包含 Nix 包管理器的设计、命令行使用说明。
- [nixpkgs Manual](https://nixos.org/manual/nixpkgs/unstable/): 主要介绍 Nixpkgs 的参数、Nix 包的使用、修改、打包方法。
- [NixOS Manual](https://nixos.org/manual/nixos/unstable/): NixOS 系统使用手册,主要包含 Wayland/X11, GPU 等系统级别的配置说明。
- [nix-pills](https://nixos.org/guides/nix-pills): Nix Pills 对如何使用 Nix 构建软件包进行了深入的阐述,写得比官方文档清晰易懂,而且也足够深入,值得一读。
- [nixos-in-production](https://github.com/Gabriella439/nixos-in-production): 这是一本介绍如何在生产环境中使用 NixOS 的书籍,目前还在编写中,不过已经有了一些很棒的内容。
- [Eelco Dolstra - The Purely Functional Software Deployment Model - 2006](https://edolstra.github.io/pubs/phd-thesis.pdf):
Eelco Dolstra 开创性的博士论文,介绍了 Nix 包管理器的设计思想。
- [Nix Reference Manual](https://nixos.org/manual/nix/stable/package-management/profiles.html):
Nix 包管理器使用手册,主要包含 Nix 包管理器的设计、命令行使用说明。
- [nixpkgs Manual](https://nixos.org/manual/nixpkgs/unstable/): 主要介绍 Nixpkgs 的参
数、Nix 包的使用、修改、打包方法。
- [NixOS Manual](https://nixos.org/manual/nixos/unstable/): NixOS 系统使用手册,主要包含
Wayland/X11, GPU 等系统级别的配置说明。
- [nix-pills](https://nixos.org/guides/nix-pills): Nix Pills 对如何使用 Nix 构建软件包进行
了深入的阐述,写得比官方文档清晰易懂,而且也足够深入,值得一读。
- [nixos-in-production](https://github.com/Gabriella439/nixos-in-production): 这是一本介绍
如何在生产环境中使用 NixOS 的书籍,目前还在编写中,不过已经有了一些很棒的内容。
另外 Youtube 上的 [NixOS Foundation](https://www.youtube.com/@NixOS-Foundation) 跟 [NixCon](https://www.youtube.com/@NixCon) 两个频道上也有很多官方视频,干货满满。
如下几个视频强烈推荐一阅:
另外 Youtube 上的 [NixOS Foundation](https://www.youtube.com/@NixOS-Foundation) 跟
[NixCon](https://www.youtube.com/@NixCon) 两个频道上也有很多官方视频,干货满满。如下几个视
频强烈推荐一阅:
- [Summer of Nix 2022 — Public Lecture Series](https://www.youtube.com/playlist?list=PLt4-_lkyRrOMWyp5G-m_d1wtTcbBaOxZk): NixOS Foundation 举办的一系列公开讲座,由 Eelco Dolstra、Armijn Hemel 等 Nix 社区核心成员主讲,内容涵盖了 Nix 的发展历程、NixOS 的历史、Nix 的未来等多个方面,干货满满。
- [Summer of Nix 2023 — Nix Developer Dialogues](https://www.youtube.com/playlist?list=PLt4-_lkyRrOPcBuz_tjm6ZQb-6rJjU3cf): 2023 年的 Summer of Nix一系列 Nix 社区核心成员的对话,内容包含 Nixpkgs 的演进与架构方面的挑战,探索 Nix 的模块系统,讨论 Nix 生态Nixpkgs 中的 AI 应用Nix 在商业领域的应用与开源经济学。
- [Summer of Nix 2022 — Public Lecture Series](https://www.youtube.com/playlist?list=PLt4-_lkyRrOMWyp5G-m_d1wtTcbBaOxZk):
NixOS Foundation 举办的一系列公开讲座,由 Eelco Dolstra、Armijn Hemel 等 Nix 社区核心成
员主讲,内容涵盖了 Nix 的发展历程、NixOS 的历史、Nix 的未来等多个方面,干货满满。
- [Summer of Nix 2023 — Nix Developer Dialogues](https://www.youtube.com/playlist?list=PLt4-_lkyRrOPcBuz_tjm6ZQb-6rJjU3cf):
2023 年的 Summer of Nix一系列 Nix 社区核心成员的对话,内容包含 Nixpkgs 的演进与架构方
面的挑战,探索 Nix 的模块系统,讨论 Nix 生态Nixpkgs 中的 AI 应用Nix 在商业领域的应用
与开源经济学。
另外 @NickCao 在 2021 年做的一个深入介绍 Nix 包管理器的演讲也很值得一阅:
@ -38,23 +56,34 @@
## 进阶技术与社区项目
在对 Nix Flakes 熟悉到一定程度后,你可以尝试一些 Flakes 的进阶玩法,如下是一些比较流行的社区项目,可以试用:
在对 Nix Flakes 熟悉到一定程度后,你可以尝试一些 Flakes 的进阶玩法,如下是一些比较流行的社
区项目,可以试用:
- [flake-parts](https://github.com/hercules-ci/flake-parts): 通过 Module 模块系统简化配置的编写与维护。
- [flake-utils-plus](https://github.com/gytis-ivaskevicius/flake-utils-plus):同样是用于简化 Flake 配置的第三方包,不过貌似更强大些
- [flake-parts](https://github.com/hercules-ci/flake-parts): 通过 Module 模块系统简化配置
的编写与维护。
- [flake-utils-plus](https://github.com/gytis-ivaskevicius/flake-utils-plus):同样是用于简
化 Flake 配置的第三方包,不过貌似更强大些
- ......
以及其他许多实用的社区项目可探索:
- [nix-output-monitor](https://github.com/maralorn/nix-output-monitor): 美化 `nix build` 命令的输出日志,同时打印出更详细的日志信息,以及构建计时器等额外信息,强烈推荐使用!
- [nix-output-monitor](https://github.com/maralorn/nix-output-monitor): 美化 `nix build`
命令的输出日志,同时打印出更详细的日志信息,以及构建计时器等额外信息,强烈推荐使用!
- [agenix](https://github.com/ryantm/agenix): secrets 管理工具
- [nixos-generator](https://github.com/nix-community/nixos-generators): 镜像生成工具,从 nixos 配置生成 iso/qcow2 等格式的镜像
- [nixos-generator](https://github.com/nix-community/nixos-generators): 镜像生成工具,从
nixos 配置生成 iso/qcow2 等格式的镜像
- [lanzaboote](https://github.com/nix-community/lanzaboote): 启用 secure boot
- [impermanence](https://github.com/nix-community/impermanence): 用于配置无状态系统。可用它持久化你指定的文件或文件夹,同时再将 /home 目录挂载为 tmpfs 或者每次启动时用工具擦除一遍。这样所有不受 impermanence 管理的数据都将成为临时数据,如果它们导致了任何问题,重启下系统这些数据就全部还原到初始状态了!
- [impermanence](https://github.com/nix-community/impermanence): 用于配置无状态系统。可用
它持久化你指定的文件或文件夹,同时再将 /home 目录挂载为 tmpfs 或者每次启动时用工具擦除一
遍。这样所有不受 impermanence 管理的数据都将成为临时数据,如果它们导致了任何问题,重启下
系统这些数据就全部还原到初始状态了!
- [colmena](https://github.com/zhaofengli/colmena): NixOS 主机部署工具
- [devbox](https://github.com/jetpack-io/devbox): 一个基于 Nix 的轻量级开发环境管理工具,类似 earthly目标是统一开发环境与部署环境使得开发环境与部署环境一致
- [nixpak](https://github.com/nixpak/nixpak): 一个使用沙箱运行任何 Nix 应用程序的工具(包括 GUI 应用程序),提升系统安全性
- [nixpacks](https://github.com/railwayapp/nixpacks): 一个将任何代码自动打包为 OCI 容器镜像的工具,类似 buildpacks
- [devbox](https://github.com/jetpack-io/devbox): 一个基于 Nix 的轻量级开发环境管理工具,
类似 earthly目标是统一开发环境与部署环境使得开发环境与部署环境一致
- [nixpak](https://github.com/nixpak/nixpak): 一个使用沙箱运行任何 Nix 应用程序的工具(包
括 GUI 应用程序),提升系统安全性
- [nixpacks](https://github.com/railwayapp/nixpacks): 一个将任何代码自动打包为 OCI 容器镜
像的工具,类似 buildpacks
- ...
想了解更多内容,可以看看 [awesome-nix](https://github.com/nix-community/awesome-nix).

View file

@ -1,14 +1,21 @@
# 加速 Dotfiles 的调试
在使用了 Home Manager 管理我们的 Dotfiles 后,会遇到的一个问题是,每次修改完我们的 Dotfiles都需要通过跑一遍 `sudo nixos-rebuild switch`(或者如果你是单独使用 home manager 的话,应该是这个指令 `home-manager switch`) 才能生效,但每次运行这个指令都会重新计算整个系统的状态,即使 Nix 内部现在已经有了很多缓存机制可以加速这个计算,这仍然是很痛苦的。
在使用了 Home Manager 管理我们的 Dotfiles 后,会遇到的一个问题是,每次修改完我们的
Dotfiles都需要通过跑一遍 `sudo nixos-rebuild switch`(或者如果你是单独使用 home manager的
话,应该是这个指令 `home-manager switch`) 才能生效,但每次运行这个指令都会重新计算整个系统
的状态,即使 Nix 内部现在已经有了很多缓存机制可以加速这个计算,这仍然是很痛苦的。
以我的 Neovim/Emacs 配置为例,我日常修改它们的频率非常高,有时候一天要改几十上百次,如果每次修改都要等 `nixos-rebuild` 跑个几十秒,这简直是在浪费时间。
以我的 Neovim/Emacs 配置为例,我日常修改它们的频率非常高,有时候一天要改几十上百次,如果每
次修改都要等 `nixos-rebuild` 跑个几十秒,这简直是在浪费时间。
幸运的是,在有了 [使用 Justfile 简化 NixOS 相关命令](./simplify-nixos-related-commands.md) 这个方案后,我们可以通过往 `Justfile` 里添加些配置来实现快速的测试验证这些需要频繁修改的 Dotfiles.
幸运的是,在有了 [使用 Justfile 简化 NixOS 相关命令](./simplify-nixos-related-commands.md)
这个方案后,我们可以通过往 `Justfile` 里添加些配置来实现快速的测试验证这些需要频繁修改的
Dotfiles.
比如我现在添加了这些 Justfile 内容:
> 我使用的 Justfile 最新版: [ryan4yin/nix-config/Justfile](https://github.com/ryan4yin/nix-config/blob/main/Justfile)
> 我使用的 Justfile 最新版:
> [ryan4yin/nix-config/Justfile](https://github.com/ryan4yin/nix-config/blob/main/Justfile)
```Makefile
###############################################################
@ -23,7 +30,10 @@ nvim-test: nvim-clean
rsync -avz --copy-links --chmod=D2755,F744 home/base/desktop/editors/neovim/astronvim_user/ ${HOME}/.config/astronvim/lua/user
```
然后在需要快速测试 Neovim 配置时,每次修改完配置后,跑一下 `just nvim-test`,我的配置就更新了。
测试完毕后,运行下 `just nvim-clean`,再重新用 `nixos-rebuild` 部署下配置,就完成了配置的还原。
然后在需要快速测试 Neovim 配置时,每次修改完配置后,跑一下 `just nvim-test`,我的配置就更
新了。测试完毕后,运行下 `just nvim-clean`,再重新用 `nixos-rebuild` 部署下配置,就完成了
配置的还原。
这种方法能生效的前提是,你的 Dotfiles 内容不是由 Nix 生成的,比如我的 Emacs/Neovim 配置都是原生的,仅通过 Nix Home-Manager 的 `home.file``xdg.configFile` 将它们链接到正确的位置。
这种方法能生效的前提是,你的 Dotfiles 内容不是由 Nix 生成的,比如我的 Emacs/Neovim 配置都
是原生的,仅通过 Nix Home-Manager 的 `home.file``xdg.configFile` 将它们链接到正确的位
置。

View file

@ -2,7 +2,8 @@
## 查看详细错误信息
如果你在部署配置时遇到了任何错误,都可以尝试在 `nixos-rebuild` 命令后面添加 `--show-trace --print-build-logs --verbose` 参数来获取详细的错误信息。举例如下:
如果你在部署配置时遇到了任何错误,都可以尝试在 `nixos-rebuild` 命令后面添加
`--show-trace --print-build-logs --verbose` 参数来获取详细的错误信息。举例如下:
```bash
cd /etc/nixos
@ -14,9 +15,11 @@ sudo nixos-rebuild switch --flake .#myhost --show-trace -L -v
## 通过 `nix repl` 查看源码、调试配置
> 注:如果你禁用了 `NIX_PATH`,那么 `<nixpkgs>` 这样的语法将无法使用,你需要改用 `nix repl -f flake:nixpkgs` 来加载 nixpkgs。
> 注:如果你禁用了 `NIX_PATH`,那么 `<nixpkgs>` 这样的语法将无法使用,你需要改用
> `nix repl -f flake:nixpkgs` 来加载 nixpkgs。
前面我们已经使用 `nix repl '<nixpkgs>'` 看过很多次源码了,这是一个非常强大的工具,可以帮助我们理解 Nix 的工作原理。
前面我们已经使用 `nix repl '<nixpkgs>'` 看过很多次源码了,这是一个非常强大的工具,可以帮助
我们理解 Nix 的工作原理。
要学会用 `nix repl`,最好先看看它的 help 信息:
@ -152,7 +155,8 @@ outputs.nixosConfigurations.ai.config.home-manager.users.ryan.home.file..config/
#......
```
能看到,通过 `nix repl` 加载好我的 flake 配置后,就能很方便地检查所有的配置项了,这对于调试非常有用。
能看到,通过 `nix repl` 加载好我的 flake 配置后,就能很方便地检查所有的配置项了,这对于调
试非常有用。
## 使用 nixpkgs 中提供的调试函数

View file

@ -1,4 +1,4 @@
# 最佳实践
Nix 非常强大且灵活,做一件事有非常多的方法,这就导致了很难找到最合适的方法来做你的工作。
里记录了一些我在使用 NixOS 中学习到的最佳实践,希望能帮到你。
Nix 非常强大且灵活,做一件事有非常多的方法,这就导致了很难找到最合适的方法来做你的工作。
里记录了一些我在使用 NixOS 中学习到的最佳实践,希望能帮到你。

View file

@ -2,29 +2,39 @@
## NIX_PATH 介绍 {#nix-path-introduction}
Nix 搜索路径由环境变量 `NIX_PATH` 控制,它的格式与 Linux 的 `PATH` 环境变量一致,由冒号分隔的多个路径组成。
Nix 搜索路径由环境变量 `NIX_PATH` 控制,它的格式与 Linux 的 `PATH` 环境变量一致,由冒号分
隔的多个路径组成。
Nix 表达式中形如 `<name>` 的路径会被解析为 `NIX_PATH` 中名为 `name` 的路径。
这种使用方式在 Flakes 特性下已经不推荐使用了,因为它会导致 Flake 的构建结果依赖一个可变的环境变量 `NIX_PATH`,可复现能力大打折扣。
这种使用方式在 Flakes 特性下已经不推荐使用了,因为它会导致 Flake 的构建结果依赖一个可变的
环境变量 `NIX_PATH`,可复现能力大打折扣。
但是在某些场景下,我们还是需要使用 `NIX_PATH`,比如我们前面多次使用了 `nix repl '<nixpkgs>'` 命令,它就是使用了从 `NIX_PATH` 搜索到的 Nixpkgs。
但是在某些场景下,我们还是需要使用 `NIX_PATH`,比如我们前面多次使用了
`nix repl '<nixpkgs>'` 命令,它就是使用了从 `NIX_PATH` 搜索到的 Nixpkgs。
## Flakes Registry 介绍 {#flakes-registry-introduction}
Flake Registry 是一个 Flake 注册中心,它可以帮助我们在使用 `nix run`, `nix shell` 等命令时,使用一个简短的 id 来代替长长的 flake 仓库地址。
Flake Registry 是一个 Flake 注册中心,它可以帮助我们在使用 `nix run`, `nix shell` 等命令
时,使用一个简短的 id 来代替长长的 flake 仓库地址。
默认情况下Nix 会从 <https://github.com/NixOS/flake-registry/blob/master/flake-registry.json> 中找到这个 id 对应的 github 仓库地址。
默认情况下Nix 会从
<https://github.com/NixOS/flake-registry/blob/master/flake-registry.json> 中找到这个 id 对
应的 github 仓库地址。
比如说我们执行 `nix run nixpkgs#ponysay hello`nix 会自动从上述 json 文件中找到 `nixpkgs` 对应的 github 仓库地址,然后下载这个仓库,再通过其中的 `flake.nix` 查找对应的 `ponysay` 包并运行它。
比如说我们执行 `nix run nixpkgs#ponysay hello`nix 会自动从上述 json 文件中找到 `nixpkgs`
对应的 github 仓库地址,然后下载这个仓库,再通过其中的 `flake.nix` 查找对应的 `ponysay`
并运行它。
## 自定义 NIX_PATH 与 Flake Registry {#custom-nix-path-and-flake-registry-2}
> **注意:新手请先跳过这部分内容!因为配置如果抄得不对,关掉 nix-channel 可能会导致一些令人头疼的错误。**
> **注意:新手请先跳过这部分内容!因为配置如果抄得不对,关掉 nix-channel 可能会导致一些令
> 人头疼的错误。**
前面说明了 `NIX_PATH` 与 Flake Registry 的作用。
在日常使用中,我们一般都会希望能在执行 `nix repl '<nixpkgs>'`, `nix run nixpkgs#ponysay hello` 等命令时,使用的 nixpkgs 与系统一致,这就需要我们自定义 `NIX_PATH` 与 Flake Registry。
另外 `nix-channel` 虽然也能与 flakes 特性共存,但实际上 flakes 已经能够完全替代它了,所以我们也可以将其关闭。
前面说明了 `NIX_PATH` 与 Flake Registry 的作用。在日常使用中,我们一般都会希望能在执行
`nix repl '<nixpkgs>'`, `nix run nixpkgs#ponysay hello` 等命令时,使用的 nixpkgs 与系统一
致,这就需要我们自定义 `NIX_PATH` 与 Flake Registry。另外 `nix-channel` 虽然也能与 flakes
特性共存,但实际上 flakes 已经能够完全替代它了,所以我们也可以将其关闭。
在你的 NixOS 配置中,添加如下 module 即可实现上述需求:

View file

@ -1,11 +1,17 @@
# 远程部署
Nix 本身的设计就很适合远程部署Nix 社区也有许多专门用于远程部署的工具,比如说 [NixOps](https://github.com/NixOS/nixops) 与 [colmena](https://github.com/zhaofengli/colmena)。另外我们前面已经用了很多次的官方工具 `nixos-rebuild`,它拥有一定的远程部署能力。
Nix 本身的设计就很适合远程部署Nix 社区也有许多专门用于远程部署的工具,比如说
[NixOps](https://github.com/NixOS/nixops) 与
[colmena](https://github.com/zhaofengli/colmena)。另外我们前面已经用了很多次的官方工具
`nixos-rebuild`,它拥有一定的远程部署能力。
此外在多架构场景下,远程部署还可以充分利用 Nix 的多架构支持,比如说在 x86_64 主机上交叉编译 aarch64/aarch64 的 NixOS 系统配置,然后通过 SSH 远程部署到对应的主机上。
我最近遇到的一个场景是,我本地交叉编译了一块 RISCV64 开发板的 NixOS 系统镜像,那么我本地已经拥有了交叉编译该系统的所有编译缓存。
但是由于 NixOS 官方几乎没有 RISCV64 的二进制缓存,我直接在开发板上执行任何未预装的程序(比如 `nix run nixpkgs#cowsay hello`)都会导致大量的编译,这会耗费我数小时的时间,是难以接受的。
而改用远程部署的话,我就能充分利用上本机的高性能 CPU 与大量编译缓存,体验就很好了。
此外在多架构场景下,远程部署还可以充分利用 Nix 的多架构支持,比如说在 x86_64 主机上交叉编
译 aarch64/aarch64 的 NixOS 系统配置,然后通过 SSH 远程部署到对应的主机上。我最近遇到的一
个场景是,我本地交叉编译了一块 RISCV64 开发板的 NixOS 系统镜像,那么我本地已经拥有了交叉编
译该系统的所有编译缓存。但是由于 NixOS 官方几乎没有 RISCV64 的二进制缓存,我直接在开发板上
执行任何未预装的程序(比如 `nix run nixpkgs#cowsay hello`)都会导致大量的编译,这会耗费我
数小时的时间,是难以接受的。而改用远程部署的话,我就能充分利用上本机的高性能 CPU 与大量编
译缓存,体验就很好了。
这里我简单介绍下如何使用 colmena 与 `nixos-rebuild` 进行远程部署。
@ -15,19 +21,24 @@ Nix 本身的设计就很适合远程部署Nix 社区也有许多专门用于
1. 为了防止远程主机的 sudo 密码验证失败,有两种方法,二选一:
1. 以远程主机的 `root` 用户身份部署,这是推荐使用的方法。
2. 在远程主机的配置中添加 `security.sudo.wheelNeedsPassword = false;` 并提前手动部署一次,从而为用户授予免密码验证的 sudo 权限。
1. **这会导致用户级别的程序能静默获取 sudo 权限,存在安全风险**!因此如果选用这种方法,建议远程部署创建一个专门的用户,不应该使用自己的常用用户!
2. 在远程主机的配置中添加 `security.sudo.wheelNeedsPassword = false;` 并提前手动部署一
次,从而为用户授予免密码验证的 sudo 权限。
1. **这会导致用户级别的程序能静默获取 sudo 权限,存在安全风险**!因此如果选用这种方
法,建议远程部署创建一个专门的用户,不应该使用自己的常用用户!
2. 为远程主机配置 SSH 公钥身份验证
1. 可使用 `users.users.<name>.openssh.authorizedKeys.keys` 配置项完成配置。
3. 在本机主机上添加好远程主机的 Known Hosts 记录,否则 colmena/nixos-rebuild 会因为无法验证远程主机的身份而部署失败。
3. 在本机主机上添加好远程主机的 Known Hosts 记录,否则 colmena/nixos-rebuild 会因为无法验
证远程主机的身份而部署失败。
1. 可使用 `programs.ssh.knownHosts` 配置项将远程主机的公钥添加到 Known Hosts 记录中。
4. 手动使用 `ssh root@<you-host>` 命令,验证能正常登录到远程主机。
1. 如果遇到任何问题,请先解决它们,再继续后续操作。
建议使用 `root` 用户进行部署,因为这更方便且不需要额外的配置,没有令人头疼的 sudo 权限问题。
建议使用 `root` 用户进行部署,因为这更方便且不需要额外的配置,没有令人头疼的 sudo 权限问
题。
假设我们现在要通过 root 用户进行远程部署,首先需要在远程主机上为该用户配置 SSH 公钥身份验证。
直接在远程主机的 Nix 配置的任一 NixOS Module 中(比如 `configuration.nix`)添加如下内容,然后重新构建系统即可:
假设我们现在要通过 root 用户进行远程部署,首先需要在远程主机上为该用户配置 SSH 公钥身份验
证。直接在远程主机的 Nix 配置的任一 NixOS Module 中(比如 `configuration.nix`)添加如下内
容,然后重新构建系统即可:
```nix{6-9}
# configuration.nix
@ -44,7 +55,8 @@ Nix 本身的设计就很适合远程部署Nix 社区也有许多专门用于
}
```
然后还需要提前在本机上将用于登录的 SSH 私钥添加到 SSH agent以便在部署配置时进行身份验证
然后还需要提前在本机上将用于登录的 SSH 私钥添加到 SSH agent以便在部署配置时进行身份验
证:
```bash
ssh-add ~/.ssh/your-private-key
@ -52,8 +64,9 @@ ssh-add ~/.ssh/your-private-key
## 通过 `colmena` 进行部署
`colmena` 不能直接使用我们已经熟悉的 `nixosConfigurations.xxx` 进行远程部署,它自定义了一个名为 `colmena` 的 flake outputs 来进行远程部署,
其内容结构与 `nixosConfigurations.xxx` 类似但不完全相同。
`colmena` 不能直接使用我们已经熟悉的 `nixosConfigurations.xxx` 进行远程部署,它自定义了一
个名为 `colmena` 的 flake outputs 来进行远程部署,其内容结构与 `nixosConfigurations.xxx`
类似但不完全相同。
在你系统的 `flake.nix` 中添加一个新的名为 `colmena` 的 outputs一个简单的例子如下
@ -102,11 +115,13 @@ ssh-add ~/.ssh/your-private-key
nix run nixpkgs#colmena apply
```
更复杂的用法,请参阅 colmena 的官方文档 <https://colmena.cli.rs/unstable/introduction.html>
更复杂的用法,请参阅 colmena 的官方文档
<https://colmena.cli.rs/unstable/introduction.html>
## 通过 `nixos-rebuild` 进行部署
`nixos-rebuild` 进行远程部署的好处在于,它的工作方式与部署到本地主机完全相同,只需要多传几个参数,指定下远程主机的 IP 地址、用户名等信息即可。
`nixos-rebuild` 进行远程部署的好处在于,它的工作方式与部署到本地主机完全相同,只需要多
传几个参数,指定下远程主机的 IP 地址、用户名等信息即可。
例如,使用以下命令将 flake 中的 `nixosConfigurations.my-nixos` 这份配置部署到远程主机:
@ -115,11 +130,14 @@ nixos-rebuild switch --flake .#nixos-text \
--target-host root@192.168.4.1 --build-host localhost --verbose
```
上述命令将会构建并部署 my-nixos 的配置到 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`
如果你觉得到处写 IP 地址不太合适,也可以在本地主机的 `~/.ssh/config``/etc/ssh/ssh_config` 中定义主机别名。例如:
如果你觉得到处写 IP 地址不太合适,也可以在本地主机的 `~/.ssh/config`
`/etc/ssh/ssh_config` 中定义主机别名。例如:
> SSH 配置可以完全通过 Nix 配置生成,这个任务就留给读者自己完成了。

View file

@ -1,9 +1,12 @@
# 运行非 NixOS 的二进制文件
NixOS 不遵循 FHS 标准,因此你从网上下载的二进制程序在 NixOS 上大概率是跑不了的。
为了在 NixOS 上跑这些非 NixOS 的二进制程序,需要做一些骚操作。有位老兄在这里总结了 10 种实现此目的的方法:[Different methods to run a non-nixos executable on Nixos](https://unix.stackexchange.com/questions/522822/different-methods-to-run-a-non-nixos-executable-on-nixos),推荐一读。
此外如果你懒得自己折腾,只想实现需求,也可以直接看看这个傻瓜式工具 [nix-alien](https://github.com/thiagokokada/nix-alien).
或者如果你熟悉 Docker直接用 Docker 跑也是个不错的选择。
NixOS 不遵循 FHS 标准,因此你从网上下载的二进制程序在 NixOS 上大概率是跑不了的。为了在
NixOS 上跑这些非 NixOS 的二进制程序,需要做一些骚操作。有位老兄在这里总结了 10 种实现此目
的的方
法:[Different methods to run a non-nixos executable on Nixos](https://unix.stackexchange.com/questions/522822/different-methods-to-run-a-non-nixos-executable-on-nixos)
推荐一读。此外如果你懒得自己折腾,只想实现需求,也可以直接看看这个傻瓜式工具
[nix-alien](https://github.com/thiagokokada/nix-alien). 或者如果你熟悉 Docker直接用
Docker 跑也是个不错的选择。
我个人用的比较多的方法是,直接创建一个 FHS 环境来运行二进制程序,这种方法非常方便易用。
@ -43,7 +46,8 @@ NixOS 不遵循 FHS 标准,因此你从网上下载的二进制程序在 NixOS
}
```
部署好上面的配置后,你就能用 `fhs` 命令进入我们定义好的 FHS 环境了,然后就可以运行你下载的二进制程序了,比如:
部署好上面的配置后,你就能用 `fhs` 命令进入我们定义好的 FHS 环境了,然后就可以运行你下载的
二进制程序了,比如:
```shell
# 进入我们定义好的 fhs 环境,它就跟其他 Linux 发行版一样了
@ -56,7 +60,11 @@ $ fhs
## 参考
- [Tips&Tricks for NixOS Desktop - NixOS Discourse][Tips&Tricks for NixOS Desktop - NixOS Discourse]: Just as the title says, it is a collection of tips and tricks for NixOS desktop.
- [nix-alien](https://github.com/thiagokokada/nix-alien): Run unpatched binaries on Nix/NixOS
- [Tips&Tricks for NixOS Desktop - NixOS
Discourse][Tips&Tricks for NixOS Desktop - NixOS Discourse]: Just as the title says, it
is a collection of tips and tricks for NixOS desktop.
- [nix-alien](https://github.com/thiagokokada/nix-alien): Run unpatched binaries on
Nix/NixOS
[Tips&Tricks for NixOS Desktop - NixOS Discourse]: https://discourse.nixos.org/t/tips-tricks-for-nixos-desktop/28488
[Tips&Tricks for NixOS Desktop - NixOS Discourse]:
https://discourse.nixos.org/t/tips-tricks-for-nixos-desktop/28488

View file

@ -1,13 +1,17 @@
# 使用 Justfile 简化 NixOS 相关命令
在使用 NixOS 的过程中,我们会经常使用 `nixos-rebuild` 命令,经常需要输入一大堆参数,比较繁琐。
在使用 NixOS 的过程中,我们会经常使用 `nixos-rebuild` 命令,经常需要输入一大堆参数,比较繁
琐。
我使用了 [just](https://github.com/casey/just) 来管理我的 flake 配置相关的命令,简化使用。
你也可以使用其他类似的工具来干这个活(比如说 Makefile 或 [cargo-make](https://github.com/sagiegurari/cargo-make)),这里我仅介绍下我的用法以供参考。
你也可以使用其他类似的工具来干这个活(比如说 Makefile 或
[cargo-make](https://github.com/sagiegurari/cargo-make)),这里我仅介绍下我的用法以供参
考。
我的 Justfile 大概内容截取如下:
> 我使用的 Justfile 最新版: [ryan4yin/nix-config/Justfile](https://github.com/ryan4yin/nix-config/blob/main/Justfile)
> 我使用的 Justfile 最新版:
> [ryan4yin/nix-config/Justfile](https://github.com/ryan4yin/nix-config/blob/main/Justfile)
```Makefile
# just is a command runner, Justfile is very similar to Makefile, but simpler.
@ -79,5 +83,6 @@ idols: aqua ruby kana
idols-debug: aqua-debug ruby-debug kana-debug
```
将上述 `Justfile` 文件存放到 NixOS 配置的根目录下,然后我们就可以使用 `just` 命令来执行相关的命令了。
比如说我这里 `just deploy` 就是部署 NixOS 配置到本地主机,`just idols` 就是部署到我的远程主机集群。
将上述 `Justfile` 文件存放到 NixOS 配置的根目录下,然后我们就可以使用 `just` 命令来执行相
关的命令了。比如说我这里 `just deploy` 就是部署 NixOS 配置到本地主机,`just idols` 就是部
署到我的远程主机集群。

View file

@ -1,13 +1,14 @@
# 跨平台编译
首先在任何 Linux 平台上,都有两种方法进行跨平台构建。
以在 x86_64 架构上构建 aarch64 架构程序为例,两种构建方法说明如下:
首先在任何 Linux 平台上,都有两种方法进行跨平台构建。以在 x86_64 架构上构建 aarch64 架构程
序为例,两种构建方法说明如下:
1. 使用 QEMU 模拟 aarch64 架构,然后在模拟器中编译程序
1. 缺点是指令集模拟,性能低下
2. 优点是能利用上 NixOS 的 binary cache不需要自己编译所有内容
2. 使用交叉编译器编译 aarch64 架构的程序
1. 缺点是无法利用 NixOS 的 binary cache需要自己编译所有内容交叉编译也有 cache但是里面基本没啥东西
1. 缺点是无法利用 NixOS 的 binary cache需要自己编译所有内容交叉编译也有 cache但是
里面基本没啥东西)
2. 优点是不需要指令集模拟,性能高
如果使用方法一,则需要在构建机的 NixOS 配置中启用 aarch64 架构的 binfmt_misc
@ -16,7 +17,8 @@
## 交叉编译
nixpkgs 包含了一系列预定义好的交叉编译工具链,其名为 `pkgsCross`,我们先通过 `nix repl` 来看看有哪些工具链:
nixpkgs 包含了一系列预定义好的交叉编译工具链,其名为 `pkgsCross`,我们先通过 `nix repl`
看看有哪些工具链:
```shell
nix repl '<nixpkgs>'
@ -61,7 +63,8 @@ pkgsCross.mipsel-linux-gnu
pkgsCross.mmix
```
如果想将一个 flake 全局的 `pkgs` 设置为交叉编译工具链,只需要在 `flake.nix` 中添加一个 Module示例如下
如果想将一个 flake 全局的 `pkgs` 设置为交叉编译工具链,只需要在 `flake.nix` 中添加一个
Module示例如下
```nix{14-20}
{
@ -92,13 +95,16 @@ pkgsCross.mmix
}
```
模块中的 `nixpkgs.crossSystem` 参数用于将 `pkgs` 设置为交叉编译工具链,这样构建出的内容全都会是 `riscv64-linux` 架构的。
模块中的 `nixpkgs.crossSystem` 参数用于将 `pkgs` 设置为交叉编译工具链,这样构建出的内容全
都会是 `riscv64-linux` 架构的。
## 通过模拟系统进行跨平台编译
第二种方法是通过模拟系统进行跨平台编译,这种方法不需要交叉编译工具链。
要使用这种方法,首先你的构建机需要在配置中启用 binfmt_misc 模块,如果你的构建机是 NixOS将如下配置添加到你的 NixOS Module 即可启用 `aarch64-linux``riscv64-linux` 两种架构的模拟构建系统:
要使用这种方法,首先你的构建机需要在配置中启用 binfmt_misc 模块,如果你的构建机是 NixOS
将如下配置添加到你的 NixOS Module 即可启用 `aarch64-linux``riscv64-linux` 两种架构的模
拟构建系统:
```nix{6}
{ ... }:
@ -134,20 +140,31 @@ pkgsCross.mmix
}
```
可以看到我们未添加任何额外的模块,仅仅是指定了 `system``riscv64-linux`.
Nix 在构建时会自动检测当前系统是否为 `riscv64-linux`,如果不是,它会自动通过 QEMU 模拟系统进行构建,对用户而言这些底层操作完全是透明的。
可以看到我们未添加任何额外的模块,仅仅是指定了 `system``riscv64-linux`. Nix 在构建时会
自动检测当前系统是否为 `riscv64-linux`,如果不是,它会自动通过 QEMU 模拟系统进行构建,对用
户而言这些底层操作完全是透明的。
## Linux binfmt_misc
前面只说了怎么用,如果你想了解更底层的细节,这里也简单介绍一下。
binfmt_misc 是 Linux 内核的一项功能全称是混杂二进制格式的内核支持Kernel Support for miscellaneous Binary Formats它能够使 Linux 支持运行几乎任何 CPU 架构的程序,包括 X86_64、ARM64、RISCV64 等。
binfmt_misc 是 Linux 内核的一项功能全称是混杂二进制格式的内核支持Kernel Support for
miscellaneous Binary Formats它能够使 Linux 支持运行几乎任何 CPU 架构的程序,包括
X86_64、ARM64、RISCV64 等。
为了能够让 binfmt_misc 运行任意格式的程序,至少需要做到两点:特定格式二进制程序的识别方式,以及其对应的解释器位置。虽然 binfmt_misc 听上去很强大,其实现的方式却意外地很容易理解,类似于 bash 解释器通过脚本文件的第一行(如#!/usr/bin/python3得知该文件需要通过什么解释器运行binfmt_misc 也预设了一系列的规则,如读取二进制文件头部特定位置的魔数,或者根据文件扩展名(如.exe、.py以判断可执行文件的格式随后调用对应的解释器去运行该程序。Linux 默认的可执行文件格式是 elf而 binfmt_misc 的出现拓宽了 Linux 的执行限制,将一点展开成一个面,使得各种各样的二进制文件都能选择它们对应的解释器执行。
为了能够让 binfmt_misc 运行任意格式的程序,至少需要做到两点:特定格式二进制程序的识别方
式,以及其对应的解释器位置。虽然 binfmt_misc 听上去很强大,其实现的方式却意外地很容易理
解,类似于 bash 解释器通过脚本文件的第一行(如#!/usr/bin/python3得知该文件需要通过什么解
释器运行binfmt_misc 也预设了一系列的规则,如读取二进制文件头部特定位置的魔数,或者根据文
件扩展名(如.exe、.py以判断可执行文件的格式随后调用对应的解释器去运行该程序。Linux 默
认的可执行文件格式是 elf而 binfmt_misc 的出现拓宽了 Linux 的执行限制,将一点展开成一个
面,使得各种各样的二进制文件都能选择它们对应的解释器执行。
注册一种格式的二进制程序需要将一行有 `:name:type:offset:magic:mask:interpreter:flags` 格式的字符串写入 `/proc/sys/fs/binfmt_misc/register` 中,格式的详细解释这里就略过了。
注册一种格式的二进制程序需要将一行有 `:name:type:offset:magic:mask:interpreter:flags` 格式
的字符串写入 `/proc/sys/fs/binfmt_misc/register` 中,格式的详细解释这里就略过了。
由于人工写入上述 binfmt_misc 的注册信息比较麻烦,社区提供了一个容器来帮助我们自动注册,这个容器就是 binfmt运行一下该容器就能安装各种格式的 binfmt_misc 模拟器了,举个例子:
由于人工写入上述 binfmt_misc 的注册信息比较麻烦,社区提供了一个容器来帮助我们自动注册,这
个容器就是 binfmt运行一下该容器就能安装各种格式的 binfmt_misc 模拟器了,举个例子:
```shell
# 注册所有架构
@ -157,14 +174,20 @@ podman run --privileged --rm tonistiigi/binfmt:latest --install all
docker run --privileged --rm tonistiigi/binfmt --install arm64,riscv64,arm
```
binfmt_misc 模块自 Linux 2.6.12-rc2 版本中引入,先后经历了几次功能上的略微改动。
Linux 4.8 中新增“F”fix binary固定二进制标志位使 mount 命名空间变更和 chroot 后的环境中依然能够正常调用解释器执行二进制程序。由于我们需要构建多架构容器必须使用“F”标志位才能 binfmt_misc 在容器中正常工作,因此内核版本需要在 4.8 以上才可以。
binfmt_misc 模块自 Linux 2.6.12-rc2 版本中引入先后经历了几次功能上的略微改动。Linux 4.8
中新增“F”fix binary固定二进制标志位使 mount 命名空间变更和 chroot 后的环境中依然能
够正常调用解释器执行二进制程序。由于我们需要构建多架构容器必须使用“F”标志位才能
binfmt_misc 在容器中正常工作,因此内核版本需要在 4.8 以上才可以。
总的来说比起一般情况显式调用解释器去执行非原生架构程序binfmt_misc 产生的一个重要意义在于透明性。有了 binfmt_misc 后用户在执行程序时不需要再关心要用什么解释器去执行好像任何架构的程序都能够直接执行一样而可配置的“F”标志位更是锦上添花使解释器程序在安装时立即就被加载进内存后续的环境改变也不会影响执行过程。
总的来说比起一般情况显式调用解释器去执行非原生架构程序binfmt_misc 产生的一个重要意义在
于透明性。有了 binfmt_misc 后,用户在执行程序时不需要再关心要用什么解释器去执行,好像任何
架构的程序都能够直接执行一样而可配置的“F”标志位更是锦上添花使解释器程序在安装时立即就
被加载进内存,后续的环境改变也不会影响执行过程。
## 自定义构建工具链
有时候我们会需要使用自定义的工具链进行构建,比如使用自己编译的 gcc或者使用自己编译的 musl libc 等等,这种修改可以通过 overlays 来实现。
有时候我们会需要使用自定义的工具链进行构建,比如使用自己编译的 gcc或者使用自己编译的
musl libc 等等,这种修改可以通过 overlays 来实现。
举个例子,我们来尝试下使用使用不同的 gcc 版本,通过 `nix repl` 来测试下:
@ -218,9 +241,11 @@ nix-repl> pkgs.pkgsCross.riscv64.stdenv.cc
}
```
上面的方法会替换掉全局的 `pkgs.gcc`,很可能会导致大量的缓存失效,从而需要在本地本地构建非常多的 Nix 包。
上面的方法会替换掉全局的 `pkgs.gcc`,很可能会导致大量的缓存失效,从而需要在本地本地构建非
常多的 Nix 包。
为了避免这个问题,更好的办法是创建一个新的 `pkgs` 实例,仅在构建我们想修改的包时才使用这个实例,`flake.nix` 示例如下:
为了避免这个问题,更好的办法是创建一个新的 `pkgs` 实例,仅在构建我们想修改的包时才使用这个
实例,`flake.nix` 示例如下:
```nix{10-19,34-37}
{

View file

@ -1,24 +1,29 @@
# Dev Environments
前面我们已经学习了构建开发环境的实现原理,但是每次都要自己写一堆重复性较高的 `flake.nix`,略显繁琐。
前面我们已经学习了构建开发环境的实现原理,但是每次都要自己写一堆重复性较高的 `flake.nix`
略显繁琐。
幸运的是,社区已经有人为我们做好了这件事,如下这个仓库中包含了绝大多数编程语言的开发环境模板,直接复制粘贴下来就能用:
幸运的是,社区已经有人为我们做好了这件事,如下这个仓库中包含了绝大多数编程语言的开发环境模
板,直接复制粘贴下来就能用:
- [the-nix-way/dev-templates](https://github.com/the-nix-way/dev-templates)
- [MordragT/nix-templates](https://github.com/MordragT/nix-templates)
如果你觉得 `flake.nix` 的结构还是太复杂了,希望能有更简单的方法,也可以考虑使用下面这个项目,它对 Nix 做了更彻底的封装,对用户提供了更简单的定义:
如果你觉得 `flake.nix` 的结构还是太复杂了,希望能有更简单的方法,也可以考虑使用下面这个项
目,它对 Nix 做了更彻底的封装,对用户提供了更简单的定义:
- [cachix/devenv](https://github.com/cachix/devenv)
如果你连任何一行 nix 代码都不想写,只想以最小的代价获得一个可复现的开发环境,这里也有一个或许能符合你需求的工具:
如果你连任何一行 nix 代码都不想写,只想以最小的代价获得一个可复现的开发环境,这里也有一个
或许能符合你需求的工具:
- [jetpack-io/devbox](https://github.com/jetpack-io/devbox)
## Python 开发环境
Python 的开发环境比 Java/Go 等语言要麻烦许多因为它默认就往全局环境装软件要往当前项目装还必须得先创建虚拟环境JS/Go 等语言里可没虚拟环境这种幺蛾子)。
这对 Nix 而言是非常不友好的行为。
Python 的开发环境比 Java/Go 等语言要麻烦许多,因为它默认就往全局环境装软件,要往当前项目
还必须得先创建虚拟环境JS/Go 等语言里可没虚拟环境这种幺蛾子)。这对 Nix 而言是非常不
友好的行为。
Python 的 pip 默认会将软件安装到全局,在 NixOS 中 `pip install` 会直接报错:
@ -37,10 +42,14 @@ note: If you believe this is a mistake, please contact your Python installation
hint: See PEP 668 for the detailed specification.
```
根据错误信息,`pip install` 直接被 NixOS 禁用掉了,测试了 `pip install --user` 也同样被禁用。为了提升环境的可复现能力Nix 把它们全部废掉了。
即使我们通过 `mkShell` 等方式创建一个新环境,这些命令照样会报错(猜测是 Nixpkgs 中的 pip 命令本身就被魔改了,只要是跑 `install` 等修改指令就直接嘎掉)。
根据错误信息,`pip install` 直接被 NixOS 禁用掉了,测试了 `pip install --user` 也同样被禁
用。为了提升环境的可复现能力Nix 把它们全部废掉了。即使我们通过 `mkShell` 等方式创建一个
新环境,这些命令照样会报错(猜测是 Nixpkgs 中的 pip 命令本身就被魔改了,只要是跑 `install`
等修改指令就直接嘎掉)。
但是很多项目的安装脚本都是基于 pip 的,这导致这些脚本都不能直接使用,而且另一方面 nixpkgs 中的内容有限,很多 pypi 中的包里边都没有,还得自己打包,相对麻烦很多,也加重了用户的心智负担。
但是很多项目的安装脚本都是基于 pip 的,这导致这些脚本都不能直接使用,而且另一方面 nixpkgs
中的内容有限,很多 pypi 中的包里边都没有,还得自己打包,相对麻烦很多,也加重了用户的心智负
担。
解决方案之一是改用 `venv` 虚拟环境,在虚拟环境里当然就能正常使用 pip 等命令了:
@ -51,15 +60,19 @@ source ./env/bin/activate
或者使用第三方工具 `virtualenv`,缺点是这个需要额外安装。
这样用 python 直接创建的 venv对一些人而言可能还是没有安全感仍然希望将这个虚拟环境也弄进 `/nix/store` 里使其不可变,通过 nix 直接安装 `requirements.txt` 或者 `poetry.toml` 中的依赖项。
这当然是可行的,有现成的 Nix 封装工具帮我们干这个活:
这样用 python 直接创建的 venv对一些人而言可能还是没有安全感仍然希望将这个虚拟环境也弄
`/nix/store` 里使其不可变,通过 nix 直接安装 `requirements.txt` 或者 `poetry.toml` 中的
依赖项。这当然是可行的,有现成的 Nix 封装工具帮我们干这个活:
> 注意即使是在这俩环境中,直接跑 `pip install` 之类的安装命令仍然是会失败的,必须通过 `flake.nix` 来安装 Python 依赖!
> 因为数据还是在 `/nix/store` 中,这类修改命令必须在 Nix 的构建阶段才能执行...
> 注意即使是在这俩环境中,直接跑 `pip install` 之类的安装命令仍然是会失败的,必须通过
> `flake.nix` 来安装 Python 依赖!因为数据还是在 `/nix/store` 中,这类修改命令必须在 Nix的
> 构建阶段才能执行...
- [DavHau/mach-nix](https://github.com/DavHau/mach-nix)
- [poetry2nix](https://github.com/nix-community/poetry2nix)
这俩工具的好处是,能利用上 Nix Flakes 的锁机制来提升可复现能力,缺点是多了一层封装,底层变得更复杂了。
这俩工具的好处是,能利用上 Nix Flakes 的锁机制来提升可复现能力,缺点是多了一层封装,底层变
得更复杂了。
最后,在一些更复杂的项目上,上述两种方案可能都行不通,这时候最佳的解决方案,就是改用容器了,比如 Docker、Podman 等,容器的限制没 Nix 这么严格,能提供最佳的兼容性。
最后,在一些更复杂的项目上,上述两种方案可能都行不通,这时候最佳的解决方案,就是改用容器
了,比如 Docker、Podman 等,容器的限制没 Nix 这么严格,能提供最佳的兼容性。

View file

@ -2,17 +2,21 @@
分布式构建可以通过多台机器来分担本地的编译压力,加快构建速度。
NixOS 官方的 cache.nixos.org 中提供了绝大多数 X86_64 架构的缓存,因此对于普通 X86_64 的用户,一般不需要分布式构建。
NixOS 官方的 cache.nixos.org 中提供了绝大多数 X86_64 架构的缓存,因此对于普通 X86_64 的用
户,一般不需要分布式构建。
分布式构建只在没有缓存可用的场景下才有较大应用价值,主要有这几种应用场景:
1. RISC-V 或 ARM64 架构的用户(尤其是 RISC-V因为官方缓存仓库中这两个架构的缓存很少导致经常需要大量本地编译。
2. 对系统进行大量定制的用户,因为官方缓存仓库中的 packages 都是默认配置,如果你改了构建参数,那么官方缓存就不适用了,这时候就需要本地编译。
1. RISC-V 或 ARM64 架构的用户(尤其是 RISC-V因为官方缓存仓库中这两个架构的缓存很少
致经常需要大量本地编译。
2. 对系统进行大量定制的用户,因为官方缓存仓库中的 packages 都是默认配置,如果你改了构建参
数,那么官方缓存就不适用了,这时候就需要本地编译。
1. 比如嵌入式场景下往往对底层内核、驱动等有定制需求,导致需要本地编译。
## 配置分布式构建
官方没有详细文档讲这个,我在文末列出了一些建议阅读的参考文档,同时如下是我的分布式构建配置(一个 NixOS Module
官方没有详细文档讲这个,我在文末列出了一些建议阅读的参考文档,同时如下是我的分布式构建配置
一个NixOS Module
```nix
{ ... }: {
@ -132,10 +136,14 @@ NixOS 官方的 cache.nixos.org 中提供了绝大多数 X86_64 架构的缓存
目前我观察到的问题有:
1. 无法在构建时指定使用哪些主机,只能在配置文件中指定一个主机列表,然后 nix 会自动选择可用的主机。
2. 在选择主机时,我发现 Nix 总是优先选择远程主机,而我本地主机的性能最强,这导致本地主机的 CPU 无法充分利用。
3. 多机远程构建是以 Derivation 为单位的,因此在构建一些比较大的包时,其他机器可能会空闲很久,一直等这个大包构建完毕,这导致了资源的浪费。
1. 在构建的 packages 较多并且可以并行执行时,可以轻松将所有主机的 CPU 都用上,这确实非常爽。
1. 无法在构建时指定使用哪些主机,只能在配置文件中指定一个主机列表,然后 nix 会自动选择可用
的主机。
2. 在选择主机时,我发现 Nix 总是优先选择远程主机,而我本地主机的性能最强,这导致本地主机的
CPU 无法充分利用。
3. 多机远程构建是以 Derivation 为单位的,因此在构建一些比较大的包时,其他机器可能会空闲很
久,一直等这个大包构建完毕,这导致了资源的浪费。
1. 在构建的 packages 较多并且可以并行执行时,可以轻松将所有主机的 CPU 都用上,这确实非
常爽。
## References

View file

@ -1,18 +1,23 @@
# 在 NixOS 上进行开发工作
由于 NixOS 自身可复现的特性,它非常适合用于搭建开发环境。
但是如果你想直接将在其他发行版上的环境搭建经验用在 NixOS 上,可能会遇到许多问题,因为 NixOS 有自己的一套逻辑在,下面我们先对此稍作说明。
由于 NixOS 自身可复现的特性,它非常适合用于搭建开发环境。但是如果你想直接将在其他发行版上
的环境搭建经验用在 NixOS 上,可能会遇到许多问题,因为 NixOS 有自己的一套逻辑在,下面我们先
对此稍作说明。
在 NixOS 上,全局环境中只建议安装一些通用的工具,比如 `git`、`vim`、`emacs`、`tmux`、`zsh` 等等,而各语言的开发环境,最好是每个项目都有一个独立的环境。
为了简便,你也可以考虑提前为常用语言创建一些通用的开发环境,在需要时切换进去。
在 NixOS 上,全局环境中只建议安装一些通用的工具,比如 `git`、`vim`、`emacs`、`tmux`、`zsh`
等等,而各语言的开发环境,最好是每个项目都有一个独立的环境。为了简便,你也可以考虑提前为常
用语言创建一些通用的开发环境,在需要时切换进去。
总而言之NixOS 上的开发环境不要一股脑都装在全局,弄成一个个相互隔离、不会互相影响的项目环境会优雅很多。
总而言之NixOS 上的开发环境不要一股脑都装在全局,弄成一个个相互隔离、不会互相影响的项目环
境会优雅很多。
在本章中我们先学习一下 Nix Flakes 开发环境的实现原理,后面的章节再按使用场景介绍一些更具体的内容。
在本章中我们先学习一下 Nix Flakes 开发环境的实现原理,后面的章节再按使用场景介绍一些更具体
的内容。
## 通过 `nix shell` 创建开发环境
在 NixOS 上,最简单的创建开发环境的方法是使用 `nix shell`,它会创建一个含有指定 Nix 包的 shell 环境。
在 NixOS 上,最简单的创建开发环境的方法是使用 `nix shell`,它会创建一个含有指定 Nix 包的
shell 环境。
示例:
@ -45,13 +50,16 @@ Hello, world!
## 创建与使用开发环境
`nix shell` 用起来非常简单,但它并不够灵活,对于更复杂的开发环境管理,我们需要使用 `pkgs.mkShell``nix develop`
`nix shell` 用起来非常简单,但它并不够灵活,对于更复杂的开发环境管理,我们需要使用
`pkgs.mkShell``nix develop`
在 Nix Flakes 中,我们可以通过 `pkgs.mkShell { ... }` 来定义一个项目环境,通过 `nix develop` 来打开一个该开发环境的交互式 Bash Shell.
在 Nix Flakes 中,我们可以通过 `pkgs.mkShell { ... }` 来定义一个项目环境,通过
`nix develop` 来打开一个该开发环境的交互式 Bash Shell.
为了更好的使用上述两个功能,我们先来看看它们的原理。
[`pkgs.mkShell` 的源码](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/build-support/mkshell/default.nix)如下:
[`pkgs.mkShell` 的源码](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/build-support/mkshell/default.nix)如
下:
```nix
{ lib, stdenv, buildEnv }:
@ -106,7 +114,9 @@ stdenv.mkDerivation ({
} // rest)
```
可以看到 `pkgs.mkShell { ... }` 本质上就是一个特殊的 DerivationNix 包),它的 `name` `buildInputs` 等参数都是可自定义的,而 `shellHook` 则是一个特殊的参数,它会在 `nix develop` 进入该环境时被执行。
可以看到 `pkgs.mkShell { ... }` 本质上就是一个特殊的 DerivationNix 包),它的 `name`
`buildInputs` 等参数都是可自定义的,而 `shellHook` 则是一个特殊的参数,它会在
`nix develop` 进入该环境时被执行。
如下是一份 `flake.nix` 文件,它定义了一个 nodejs 18 的开发环境:
@ -143,11 +153,14 @@ stdenv.mkDerivation ({
}
```
建个空文件夹,将上面的配置保存为 `flake.nix`,然后执行 `nix develop`(或者更精确点,可以用 `nix develop .#default`),首先会打印出当前 nodejs 的版本,之后 `node` `pnpm` `yarn` 等命令就都能正常使用了。
建个空文件夹,将上面的配置保存为 `flake.nix`,然后执行 `nix develop`(或者更精确点,可以用
`nix develop .#default`),首先会打印出当前 nodejs 的版本,之后 `node` `pnpm` `yarn` 等命
令就都能正常使用了。
## 在开发环境中使用 zsh/fish 等其他 shell
`pkgs.mkShell` 默认使用 `bash`,但是你也可以通过在 `shellHook` 中添加 `exec <your-shell>` 来使用 `zsh` 或者 `fish` 等其他 shell。
`pkgs.mkShell` 默认使用 `bash`,但是你也可以通过在 `shellHook` 中添加 `exec <your-shell>`
来使用 `zsh` 或者 `fish` 等其他 shell。
示例如下:
@ -186,15 +199,18 @@ stdenv.mkDerivation ({
}
```
使用上面的 `flake.nix` 配置,`nix develop` 将进入一个 nodejs 18 的开发环境,同时使用 `nushell` 作为交互式 shell.
使用上面的 `flake.nix` 配置,`nix develop` 将进入一个 nodejs 18 的开发环境,同时使用
`nushell` 作为交互式 shell.
## 通过 `pkgs.runCommand` 创建开发环境
`pkgs.mkShell` 创建的 derivation 不能直接使用,必须通过 `nix develop` 进入到该环境中。
实际上我们也可以通过 `pkgs.stdenv.mkDerivation` 来创建一个包含所需软件包的 shell wrapper, 这样就能直接通过执行运行该 wrapper 来进入到该环境中。
实际上我们也可以通过 `pkgs.stdenv.mkDerivation` 来创建一个包含所需软件包的 shell wrapper,
这样就能直接通过执行运行该 wrapper 来进入到该环境中。
直接使用 `mkDerivation` 略显繁琐Nixpkgs 提供了一些更简单的函数来帮助我们创建这类 wrapper比如 `pkgs.runCommand`.
直接使用 `mkDerivation` 略显繁琐Nixpkgs 提供了一些更简单的函数来帮助我们创建这类
wrapper比如 `pkgs.runCommand`.
示例:
@ -234,9 +250,11 @@ stdenv.mkDerivation ({
}
```
然后执行 `nix run .#dev` 或者 `nix shell .#dev --command 'dev-shell'`,就能进入一个 nushell session可以在其中正常使用 `node` `pnpm` 命令.
然后执行 `nix run .#dev` 或者 `nix shell .#dev --command 'dev-shell'`就能进入一个nushell
session可以在其中正常使用 `node` `pnpm` 命令.
这种方式生成的 wrapper 是一个可执行文件,它实际不依赖 `nix run` 命令,比如说我们可以直接通过 NixOS 的 `environment.systemPackages` 来安装这个 wrapper然后直接执行它
这种方式生成的 wrapper 是一个可执行文件,它实际不依赖 `nix run` 命令,比如说我们可以直接通
过 NixOS 的 `environment.systemPackages` 来安装这个 wrapper然后直接执行它
```nix
{pkgs, lib, ...}{
@ -263,7 +281,9 @@ stdenv.mkDerivation ({
}
```
将上述配置添加到任一 NixOS Module 中,再通过 `sudo nixos-rebuild switch` 部署后,就能直接通过 `dev-shell` 命令进入到该开发环境,这就是 `pkgs.runCommand` 相比 `pkgs.mkShell` 的特别之处。
将上述配置添加到任一 NixOS Module 中,再通过 `sudo nixos-rebuild switch` 部署后,就能直接
通过 `dev-shell` 命令进入到该开发环境,这就是 `pkgs.runCommand` 相比 `pkgs.mkShell` 的特别
之处。
相关源代码:
@ -283,14 +303,16 @@ Synopsis
# ......
```
可以看到 `nix develop` 接受的参数是 `installable`,这说明我们可以通过它进入任何一个 installable 的 Nix 包的开发环境,而不仅仅是 `pkgs.mkShell` 创建的环境。
可以看到 `nix develop` 接受的参数是 `installable`,这说明我们可以通过它进入任何一个
installable 的 Nix 包的开发环境,而不仅仅是 `pkgs.mkShell` 创建的环境。
默认情况下,`nix develop` 命令会尝试 flake outputs 中的如下属性:
- `devShells.<system>.default`
- `packages.<system>.default`
而如果我们通过 `nix develop /path/to/flake#<name>` 来指定了 flake 包地址以及 flake output name那么 `nix develop` 命令会尝试 flake outputs 中的如下属性:
而如果我们通过 `nix develop /path/to/flake#<name>` 来指定了 flake 包地址以及 flake output
name那么 `nix develop` 命令会尝试 flake outputs 中的如下属性:
- `devShells.<system>.<name>`
- `packages.<system>.<name>`
@ -338,7 +360,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
此外我们还可以正常调用 `hello` 这个 Nix 包的各构建阶段命令:
> 提前说明下,一个 Nix 包的所有构建阶段及其默认的执行顺序为:`$prePhases unpackPhase patchPhase $preConfigurePhases configurePhase $preBuildPhases buildPhase checkPhase $preInstallPhases installPhase fixupPhase installCheckPhase $preDistPhases distPhase $postPhases`
> 提前说明下,一个 Nix 包的所有构建阶段及其默认的执行顺序
> 为:`$prePhases unpackPhase patchPhase $preConfigurePhases configurePhase $preBuildPhases buildPhase checkPhase $preInstallPhases installPhase fixupPhase installCheckPhase $preDistPhases distPhase $postPhases`
```shell
# 解压源码包
@ -396,11 +419,13 @@ ryan in 🌐 aquamarine in /tmp/xxx/hello-2.12.1 via C v12.3.0-gcc via ❄️ i
Hello, world!
```
这种用法的主要应用场景是调试某个 Nix 包的构建过程,或者在某个 Nix 包的构建环境中执行一些命令。
这种用法的主要应用场景是调试某个 Nix 包的构建过程,或者在某个 Nix 包的构建环境中执行一些命
令。
## `nix build`
`nix build` 用于构建一个软件包,并在当前目录下创建一个名为 `result` 的符号链接,链接到该构建结果。
`nix build` 用于构建一个软件包,并在当前目录下创建一个名为 `result` 的符号链接,链接到该构
建结果。
一个示例:
@ -437,15 +462,19 @@ nix build "nixpkgs#ponysay"
## 使用 `nix profile` 分别管理日常娱乐环境跟开发环境
`nix profile` 是 NixOS 中用于管理用户环境的工具,它可以用于创建管理多个用户环境,并在需要时切换到不同的环境。
`nix profile` 是 NixOS 中用于管理用户环境的工具,它可以用于创建管理多个用户环境,并在需要
时切换到不同的环境。
`nix develop` 不同,`nix profile` 管理的是用户级别的系统环境,而不是临时创建的一个 shell 环境,因此它对 Jetbrains IDE / VSCode 等 IDE 的兼容性会好很多,不会出现无法在 IDE 内使用我们配置好的开发环境的情况。
`nix develop` 不同,`nix profile` 管理的是用户级别的系统环境,而不是临时创建的一个
shell 环境,因此它对 Jetbrains IDE / VSCode 等 IDE 的兼容性会好很多,不会出现无法在 IDE 内
使用我们配置好的开发环境的情况。
TODO 未完待续
## 其他命令
其他还有些 `nix flake init` 之类的命令,请自行查阅 [New Nix Commands][New Nix Commands] 学习研究,这里就不详细介绍了。
其他还有些 `nix flake init` 之类的命令,请自行查阅 [New Nix Commands][New Nix Commands] 学
习研究,这里就不详细介绍了。
## References

View file

@ -105,11 +105,13 @@
}
```
通过上面的 `flake.nix`,我可以通过 `nix develop .#kernel` 进入到内核的构建环境中,执行 `unpackPhase` 解压出内核源码。
通过上面的 `flake.nix`,我可以通过 `nix develop .#kernel` 进入到内核的构建环境中,执行
`unpackPhase` 解压出内核源码。
但是不能执行 `make menuconfig` 进行内核的配置,因为该环境中缺少 `ncurses` 等包。
所以我第二步是退出再通过 `nix develop .#fhs` 进入到另一个添加了必需包的 FHS 环境中,再执行 `make menuconfig` 进行内核的配置,以及后续的构建调试。
所以我第二步是退出再通过 `nix develop .#fhs` 进入到另一个添加了必需包的 FHS 环境中,再执行
`make menuconfig` 进行内核的配置,以及后续的构建调试。
## References

View file

@ -10,14 +10,18 @@ WIP 未完成,目前请移步如下参考文档学习 Nix 打包。
- [languages-frameworks - Nixpkgs Manual](https://github.com/NixOS/nixpkgs/tree/nixos-unstable/doc/languages-frameworks)
- [Wrapping packages - NixOS Cookbook](https://nixos.wiki/wiki/Nix_Cookbook#Wrapping_packages)
- Useful tools:
- [nurl](https://github.com/nix-community/nurl): Generate Nix fetcher calls from repository URLs
- [nix-init](https://github.com/nix-community/nix-init): Generate Nix packages from URLs with hash prefetching, dependency inference, license detection, and more
- [nurl](https://github.com/nix-community/nurl): Generate Nix fetcher calls from
repository URLs
- [nix-init](https://github.com/nix-community/nix-init): Generate Nix packages from URLs
with hash prefetching, dependency inference, license detection, and more
- 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/setup-hooks/make-wrapper.sh](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/setup-hooks/make-wrapper.sh)
- FHS related
- [pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix): `pkgs.buildFHSEnvBubblewrap`
- [pkgs/build-support/build-fhsenv-chroot/default.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix): `pkgs.buildFHSEnvChroot`
- [pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix):
`pkgs.buildFHSEnvBubblewrap`
- [pkgs/build-support/build-fhsenv-chroot/default.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix):
`pkgs.buildFHSEnvChroot`
---
@ -33,7 +37,8 @@ TODO
## Fetchers {#fetchers}
构建输入除了直接来自文件系统路径之外,还可以通过 Fetchers 来获取Fetcher 是一种特殊的函数,它的输入是一个 attribute set输出是 Nix Store 中的一个系统路径。
构建输入除了直接来自文件系统路径之外,还可以通过 Fetchers 来获取Fetcher 是一种特殊的函
数,它的输入是一个 attribute set输出是 Nix Store 中的一个系统路径。
Nix 提供了四个内置的 Fetcher分别是
@ -54,20 +59,29 @@ builtins.fetchTarball "https://github.com/NixOS/nix/archive/7c3ab5751568a0bc6343
## Derivations {#derivations}
> 官方 Nixpkgs 包仓库中的软件包已经能满足绝大部分用户的使用,在学习 NixOS 的前期不太需要深入了解 Derivation 的使用细节,有个印象就行。
> 本书会在后面 [Nix 软件打包入门](../development/packaging-101.md) 中详细介绍相关内容,这里仅做简要介绍。
> 官方 Nixpkgs 包仓库中的软件包已经能满足绝大部分用户的使用,在学习 NixOS 的前期不太需要深
> 入了解 Derivation 的使用细节,有个印象就行。本书会在后面
> [Nix 软件打包入门](../development/packaging-101.md) 中详细介绍相关内容,这里仅做简要介
> 绍。
Derivation 描述了如何构建一个软件包,是一个软件包构建流程的 Nix 语言描述,它声明了构建时需要有哪些依赖项、需要什么构建工具链、要设置哪些环境变量、哪些构建参数、先干啥后干啥等等。
Derivation 描述了如何构建一个软件包,是一个软件包构建流程的 Nix 语言描述,它声明了构建时需
要有哪些依赖项、需要什么构建工具链、要设置哪些环境变量、哪些构建参数、先干啥后干啥等等。
Derivation 的构建结果是一个 Store Object其中包含了软件包的所有二进制程序、配置文件等等内容。
Store Object 的存放路径格式为 `/nix/store/<hash>-<name>`,其中 `<hash>` 是构建结果的 hash 值,`<name>` 是它的名字。路径 hash 值确保了每个构建结果都是唯一的,因此可以多版本共存,而且不会出现依赖冲突的问题。
Derivation 的构建结果是一个 Store Object其中包含了软件包的所有二进制程序、配置文件等等内
容。Store Object 的存放路径格式为 `/nix/store/<hash>-<name>`,其中 `<hash>` 是构建结果的
hash 值,`<name>` 是它的名字。路径 hash 值确保了每个构建结果都是唯一的,因此可以多版本共
存,而且不会出现依赖冲突的问题。
`/nix/store` 是一个特殊的文件路径,它被称为 Store存放所有的 Store Objects这个路径被设置为只读只有 Nix 本身才能修改这个路径下的内容,以保证系统的可复现性。
`/nix/store` 是一个特殊的文件路径,它被称为 Store存放所有的 Store Objects这个路径被设
置为只读,只有 Nix 本身才能修改这个路径下的内容,以保证系统的可复现性。
Derivation 实质上只是一个 attribute setNix 底层会使用内置函数 `builtins.derivation` 将这个 attribute set 构建为一个 Store Object。
我们实际编写 Derivation 时,通常使用的是 `stdenv.mkDerivation`,它是前述内置函数 `builtins.derivation` 的 Nix 语言 wrapper屏蔽了底层的细节简化了用法。
Derivation 实质上只是一个 attribute setNix 底层会使用内置函数 `builtins.derivation` 将这
个 attribute set 构建为一个 Store Object。我们实际编写 Derivation 时,通常使用的是
`stdenv.mkDerivation`,它是前述内置函数 `builtins.derivation` 的 Nix 语言 wrapper屏蔽了
底层的细节,简化了用法。
一个简单的 Derivation 如下,它声明了一个名为 hello 的应用程序(摘抄自 [nixpkgs/pkgs/hello](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/applications/misc/hello/default.nix)
一个简单的 Derivation 如下,它声明了一个名为 hello 的应用程序(摘抄自
[nixpkgs/pkgs/hello](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/applications/misc/hello/default.nix)
```nix
{ callPackage

View file

@ -2,47 +2,76 @@
## NixOS 的回滚能力与 btrfs / zfs 系统快照回滚有何不同?
很多使用 Arch Linux / Ubuntu 等常规 Linux 发行版的用户,习惯于使用 btrfs / zfs 等文件系统提供的快照作为「后悔药」,这样系统出了问题能回滚修复。
而本书介绍的 NixOS 也提供了系统状态回滚能力,因此很容易会有这样的疑问:这两种系统回滚功能有何不同?
很多使用 Arch Linux / Ubuntu 等常规 Linux 发行版的用户,习惯于使用 btrfs / zfs 等文件系统
提供的快照作为「后悔药」,这样系统出了问题能回滚修复。而本书介绍的 NixOS 也提供了系统状态
回滚能力,因此很容易会有这样的疑问:这两种系统回滚功能有何不同?
这里简单解释下,主要区别在于,快照内容不包含如何从零构建这个快照的「知识」,是**不可解释的**,而且其内容与当前硬件环境强相关,很难在其他机器上复现。
这里简单解释下,主要区别在于,快照内容不包含如何从零构建这个快照的「知识」,是**不可解释
的**,而且其内容与当前硬件环境强相关,很难在其他机器上复现。
而 NixOS 的配置是一份从零构建出一个一模一样的 OS 的「知识」,是**可解释的**而且可以通过简单几行命令就自动完成这个构建。NixOS 配置本身既是一份记录你的 NixOS 系统都做过哪些变更的文档,也可直接用于自动构建出你当前的 NixOS 系统。
而 NixOS 的配置是一份从零构建出一个一模一样的 OS 的「知识」,是**可解释的**,而且可以通过
简单几行命令就自动完成这个构建。NixOS 配置本身既是一份记录你的 NixOS 系统都做过哪些变更的
文档,也可直接用于自动构建出你当前的 NixOS 系统。
NixOS 的配置文件就像是程序的**源代码**,只要源代码没丢,修改程序、审查程序,或者重新构建出一个一模一样的程序都很简单。
而系统快照就像是源代码编译出来的二进制程序,要对它做修改、审查,都要难得多。而且这个快照很大,分享或者迁移它的成本都要比源代码高得多。
NixOS 的配置文件就像是程序的**源代码**,只要源代码没丢,修改程序、审查程序,或者重新构建出
一个一模一样的程序都很简单。而系统快照就像是源代码编译出来的二进制程序,要对它做修改、审
查,都要难得多。而且这个快照很大,分享或者迁移它的成本都要比源代码高得多。
但这并不是说有了 NixOS 就不需要系统快照了,本书第一章就介绍了 NixOS 只能保证在声明式配置中声明的所有内容都是可复现的,而其他未声明式配置覆盖到的系统状态是不受它管辖的。比如 MySQL/PostgreSQL 的动态数据、用户上传的文件、系统日志等等,用户 Home 目录下的视频、音乐、图片等等,这些内容都还是需要文件系统快照或者其他手段来备份。
但这并不是说有了 NixOS 就不需要系统快照了,本书第一章就介绍了 NixOS 只能保证在声明式配置中
声明的所有内容都是可复现的,而其他未声明式配置覆盖到的系统状态是不受它管辖的。比如
MySQL/PostgreSQL 的动态数据、用户上传的文件、系统日志等等,用户 Home 目录下的视频、音乐、
图片等等,这些内容都还是需要文件系统快照或者其他手段来备份。
## Nix 与 Ansible 等传统的系统运维工具相比有何优劣?
Nix 不仅可用于管理桌面电脑的环境也有很多人用它批量管理云服务器Nix 官方的 [NixOps](https://github.com/NixOS/nixops) 与社区的 [colmena](https://github.com/zhaofengli/colmena) 都是专为这个场景开发的工具。
Nix 不仅可用于管理桌面电脑的环境也有很多人用它批量管理云服务器Nix 官方的
[NixOps](https://github.com/NixOS/nixops) 与社区的
[colmena](https://github.com/zhaofengli/colmena) 都是专为这个场景开发的工具。
Nix 与 Ansible 这类被广泛应用的传统工具比,主要优势就在:
1. Ansible 这类工具一个最大的问题就是,它每次部署都是基于系统当前状态的增量修改。而系统的当前状态就如同前面提到的系统快照,是不可解释的,也很难复现。而 NixOS 是通过配置文件声明系统的目标状态,可以做到部署结果与系统当前状态无关,重复部署也不会导致任何问题。
2. Nix Flakes 通过一个版本锁文件 `flake.lock` 锁定了所有依赖的 hash 值、版本号、数据源等信息,这极大地提升了系统的可复现能力。而传统的 Ansible 等工具没有此功能,所以它们的可复现能力很差。
1. 这也是为什么 Docker 这么受欢迎的原因——它以较低的代价提供了 Ansible 等传统运维工具提供不了的**可在各种机器上复现的系统环境**。
3. Nix 通过一层声明式的抽象屏蔽了其底层的实现细节,使用户只需要关心自己最核心的需求,从而带来了高度便捷的系统自定义能力。而 Ansible 这类工具的抽象能力要弱得多。
1. 如果你有使用过 terraform/kubernetes 等声明式配置工具,应该很容易理解这一点。需求越是复杂的情况下,声明式配置带来的好处就越大。
1. Ansible 这类工具一个最大的问题就是,它每次部署都是基于系统当前状态的增量修改。而系统的
当前状态就如同前面提到的系统快照,是不可解释的,也很难复现。而 NixOS 是通过配置文件声明
系统的目标状态,可以做到部署结果与系统当前状态无关,重复部署也不会导致任何问题。
2. Nix Flakes 通过一个版本锁文件 `flake.lock` 锁定了所有依赖的 hash 值、版本号、数据源等信
息,这极大地提升了系统的可复现能力。而传统的 Ansible 等工具没有此功能,所以它们的可复现
能力很差。
1. 这也是为什么 Docker 这么受欢迎的原因——它以较低的代价提供了 Ansible 等传统运维工具提
供不了的**可在各种机器上复现的系统环境**。
3. Nix 通过一层声明式的抽象屏蔽了其底层的实现细节,使用户只需要关心自己最核心的需求,从而
带来了高度便捷的系统自定义能力。而 Ansible 这类工具的抽象能力要弱得多。
1. 如果你有使用过 terraform/kubernetes 等声明式配置工具,应该很容易理解这一点。需求越是
复杂的情况下,声明式配置带来的好处就越大。
## Nix 与 Docker 容器技术相比有何优势?
Nix 与以 Docker 为代表的容器技术的应用场景也存在一定重合,比如说:
1. 有很多人用 Nix 来管理开发编译环境,本书就对此做过介绍。但另一方面也有像 [Dev Containers](https://github.com/devcontainers/spec) 这种基于容器搭建开发环境的技术,而且非常流行。
2. 目前整个 DevOps/SRE 领域基本已经是基于 Dockerfile 的容器技术的天下,容器中常用 Ubuntu/Debian 等发行版,宿主机也同样有很多成熟的发行版可选,改用 NixOS 有什么明显的优势呢?
1. 有很多人用 Nix 来管理开发编译环境,本书就对此做过介绍。但另一方面也有像
[Dev Containers](https://github.com/devcontainers/spec) 这种基于容器搭建开发环境的技
术,而且非常流行。
2. 目前整个 DevOps/SRE 领域基本已经是基于 Dockerfile 的容器技术的天下,容器中常用
Ubuntu/Debian 等发行版,宿主机也同样有很多成熟的发行版可选,改用 NixOS 有什么明显的优势
呢?
其中第一点「管理开发编译环境」Nix 创建的开发环境体验非常接近直接在宿主机进行开发,这要比 Dev Containers 好很多,举例如下:
其中第一点「管理开发编译环境」Nix 创建的开发环境体验非常接近直接在宿主机进行开发,这要比
Dev Containers 好很多,举例如下:
1. Nix 不使用名字空间进行文件系统、网络环境等各方面的隔离,在 Nix 创建的开发环境中也可以很方便地与宿主机文件系统(包括 /dev 宿主机外接设备)、网络环境等等进行交互。而容器要通过各种映射才能宿主机文件系统互通,即使这样也可能会遇到一些文件权限问题。
2. 因为没做啥强隔离Nix 开发环境对 GUI 程序的支持也没任何问题,在这个环境中跑个 GUI 程序的体验就跟在系统环境中跑个 GUI 程序没任何区别。
1. Nix 不使用名字空间进行文件系统、网络环境等各方面的隔离,在 Nix 创建的开发环境中也可以很
方便地与宿主机文件系统(包括 /dev 宿主机外接设备)、网络环境等等进行交互。而容器要通过
各种映射才能宿主机文件系统互通,即使这样也可能会遇到一些文件权限问题。
2. 因为没做啥强隔离Nix 开发环境对 GUI 程序的支持也没任何问题,在这个环境中跑个 GUI 程序
的体验就跟在系统环境中跑个 GUI 程序没任何区别。
也就是说Nix 能提供最接近宿主机的开发体验,不存在什么强隔离,开发人员能在这个环境中使用各种熟悉的开发调试工具,过往的开发经验基本都能无痛迁移过来。
而如果使用 Dev Containers那开发人员很可能会遭遇强隔离导致的各种文件系统不互通、网络环境问题、用户权限问题、无法使用 GUI 调试工具等等各种毛病。
也就是说Nix 能提供最接近宿主机的开发体验,不存在什么强隔离,开发人员能在这个环境中使用各
种熟悉的开发调试工具,过往的开发经验基本都能无痛迁移过来。而如果使用 Dev Containers那开
发人员很可能会遭遇强隔离导致的各种文件系统不互通、网络环境问题、用户权限问题、无法使用 GUI
调试工具等等各种毛病。
而如果我们决定了使用 Nix 来管理所有的开发环境,那么在构建 Docker 容器时也基于 Nix 去构建,显然能提供最强的一致性,同时所有环境都统一了技术架构,这也能明显降低整个基础设施的维护成本。
这就回答了前面提到的第二点,在使用 Nix 管理开发环境的前提下,容器基础镜像与云服务器都使用 NixOS 会存在明显的优势。
而如果我们决定了使用 Nix 来管理所有的开发环境,那么在构建 Docker 容器时也基于 Nix 去构建,
显然能提供最强的一致性,同时所有环境都统一了技术架构,这也能明显降低整个基础设施的维护成
本。这就回答了前面提到的第二点,在使用 Nix 管理开发环境的前提下,容器基础镜像与云服务器都
使用 NixOS 会存在明显的优势。
## error: collision between `...` and `...`
@ -84,8 +113,10 @@ and `/nix/store/370s8inz4fc9k9lqk4qzj5vyr60q166w-python3-3.11.6-env/lib/python3.
解决方法如下:
1. 将两个包拆分到两个不同的 **profiles** 中。比如说,你可以通过 `environment.systemPackages` 安装 `lldb`,通过 `home.packages` 安装 `python311`
2. 不同版本的 Python3 被视为不同的包,所以你可以将你的自定义 Python3 版本改为 `python310` 以避免冲突。
1. 将两个包拆分到两个不同的 **profiles** 中。比如说,你可以通过
`environment.systemPackages` 安装 `lldb`,通过 `home.packages` 安装 `python311`
2. 不同版本的 Python3 被视为不同的包,所以你可以将你的自定义 Python3 版本改为 `python310`
以避免冲突。
3. 使用 `override` 来覆盖包使用的库的版本,使其与另一个包使用的版本一致。
```nix

View file

@ -3,17 +3,26 @@
## 优点 {#advantages}
- **声明式配置OS as Code**
- NixOS 使用声明式配置来管理整个系统环境,可以直接用 Git 管理这些配置,只要你的配置文件不丢,系统就可以随时还原到任一历史状态(前面提过了,只有在 Nix 配置文件中声明了的状态才可被 NixOS 还原)。
- Nix Flakes 还使用了 `flake.lock` 作为版本锁文件它记录了所有相关数据的数据源地址、hash 值,这极大地提升了 Nix 的可复现能力(或者说增强了构建结果的一致性,这个设计实际是从 cargo/npm 等一些编程语言的包管理设计中借鉴来的)。
- NixOS 使用声明式配置来管理整个系统环境,可以直接用 Git 管理这些配置,只要你的配置文件
不丢,系统就可以随时还原到任一历史状态(前面提过了,只有在 Nix 配置文件中声明了的状态
才可被 NixOS 还原)。
- Nix Flakes 还使用了 `flake.lock` 作为版本锁文件,它记录了所有相关数据的数据源地
址、hash 值,这极大地提升了 Nix 的可复现能力(或者说增强了构建结果的一致性,这个设计实
际是从 cargo/npm 等一些编程语言的包管理设计中借鉴来的)。
- **高度便捷的系统自定义能力**
- 通过改几行配置,就可以简单地更换系统的各种组件。这是因为 Nix 将底层的复杂操作全部封装在了 Nix 软件包中,只给用户提供了简洁且必要的声明式参数。
- 而且这种修改非常安全,你可以很方便地来回切换各种桌面环境(比如 gnome/kde/i3/sway几乎不会遇到坑。
- 通过改几行配置,就可以简单地更换系统的各种组件。这是因为 Nix 将底层的复杂操作全部封装
在了 Nix 软件包中,只给用户提供了简洁且必要的声明式参数。
- 而且这种修改非常安全,你可以很方便地来回切换各种桌面环境(比如 gnome/kde/i3/sway
乎不会遇到坑。
- **可回滚**
- 可以随时回滚到任一历史环境NixOS 甚至默认将所有旧版本都加入到了启动项,确保系统滚挂了也能随时回退。所以 Nix 也被认为是最稳定的包管理方式。
- 可以随时回滚到任一历史环境NixOS 甚至默认将所有旧版本都加入到了启动项,确保系统滚挂了
也能随时回退。所以 Nix 也被认为是最稳定的包管理方式。
- **没有依赖冲突问题**
- 因为 Nix 中每个软件包都拥有唯一的 hash其安装路径中也会包含这个 hash 值,因此可以多版本共存。
- 因为 Nix 中每个软件包都拥有唯一的 hash其安装路径中也会包含这个 hash 值,因此可以多版
本共存。
- **社区很活跃,第三方项目也挺丰富**
- 官方包仓库 nixpkgs 贡献者众多,也有很多人分享自己的 Nix 配置,一遍浏览下来,整个生态给我一种发现新大陆的兴奋感。
- 官方包仓库 nixpkgs 贡献者众多,也有很多人分享自己的 Nix 配置,一遍浏览下来,整个生态给
我一种发现新大陆的兴奋感。
<figure>
<img src="/nixos-bootloader.avif">
@ -30,22 +39,37 @@
## 缺点 {#disadvantages}
- **学习成本高**:
- 如果你希望系统完全可复现,并且避免各种不当使用导致的坑,那就需要学习了解 Nix 的整个设计,并以声明式的方式管理系统,不能无脑 `nix-env -i`(这类似 `apt-get install`)。
- 如果你希望系统完全可复现,并且避免各种不当使用导致的坑,那就需要学习了解 Nix 的整个设
计,并以声明式的方式管理系统,不能无脑 `nix-env -i`(这类似 `apt-get install`)。
- **文档混乱**:
- 首先 Nix Flakes 目前仍然是实验性特性,介绍它本身的文档目前比较匮乏, Nix 社区绝大多数文档都只介绍了旧的 `/etc/nixos/configuration.nix`,想直接从 Nix Flakes(`flake.nix`) 开始学习的话,需要参考大量旧文档,从中提取出自己需要的内容。另外一些 Nix 当前的核心功能,官方文档都语焉不详(比如 `imports` 跟 Nixpkgs Module System想搞明白基本只能看源码了...
- 首先 Nix Flakes 目前仍然是实验性特性,介绍它本身的文档目前比较匮乏, Nix 社区绝大多数文
档都只介绍了旧的 `/etc/nixos/configuration.nix`,想直接从 Nix Flakes(`flake.nix`) 开始
学习的话,需要参考大量旧文档,从中提取出自己需要的内容。另外一些 Nix 当前的核心功能,
官方文档都语焉不详(比如 `imports` 跟 Nixpkgs Module System想搞明白基本只能看源码
了...
- **比较吃硬盘空间**:
- 为了保证系统可以随时回退nix 默认总是保留所有历史环境,这会使用更多的硬盘空间。
- 多使用的这这些空间,在桌面电脑上可能不是啥事,但是在资源受限的云服务器上可能会是个问题。
- 多使用的这这些空间,在桌面电脑上可能不是啥事,但是在资源受限的云服务器上可能会是个问
题。
- **报错信息比较隐晦**:
- 由于[Nixpkgs 中模块系统](../other-usage-of-flakes/module-system.md)的[复杂的 Mergeing 算法](https://discourse.nixos.org/t/best-resources-for-learning-about-the-nixos-module-system/1177/4),导致 NixOS 的报错信息相当糟糕。在很多情况下,不管你加不加 `--show-trace`,它都只会告诉你代码有错误(最常见且最迷惑的报错信息是 [Infinite recursion encountered](https://discourse.nixos.org/t/infinite-recursion-encountered-by-making-module-configurable/23508/2)),但究竟是错在哪?类型系统说我也不知道,这得你自己慢慢找了。目前我的经验来说,**遇到这种报错信息没任何意义的 bug最简单有效的解决方法是用「二分法」一点点还原代码**。
- 由
于[Nixpkgs 中模块系统](../other-usage-of-flakes/module-system.md)的[复杂的 Mergeing 算法](https://discourse.nixos.org/t/best-resources-for-learning-about-the-nixos-module-system/1177/4)
导致 NixOS 的报错信息相当糟糕。在很多情况下,不管你加不加 `--show-trace`,它都只会告诉
你代码有错误(最常见且最迷惑的报错信息是
[Infinite recursion encountered](https://discourse.nixos.org/t/infinite-recursion-encountered-by-making-module-configurable/23508/2)
但究竟是错在哪?类型系统说我也不知道,这得你自己慢慢找了。目前我的经验来说,**遇到这种
报错信息没任何意义的 bug最简单有效的解决方法是用「二分法」一点点还原代码**。
- 这个问题应该是 NixOS 目前最大的痛点之一。
- **底层实现更复杂**
- Nix 多做了一层声明式的抽象带来了诸多好处,而其代价就是底层的代码实现会比传统的命令式工具中的同类代码更复杂。
- 这导致实现难度更高,对底层做些修改也会更麻烦。不过这个问题带来的负担主要是在 Nix 软件包的维护者身上,普通用户接触底层比较少,负担也就小很多。
- Nix 多做了一层声明式的抽象带来了诸多好处,而其代价就是底层的代码实现会比传统的命令式工
具中的同类代码更复杂。
- 这导致实现难度更高,对底层做些修改也会更麻烦。不过这个问题带来的负担主要是在 Nix 软件
包的维护者身上,普通用户接触底层比较少,负担也就小很多。
## 简单总结下 {#summary}
总的来说,我觉得 NixOS 适合那些有一定 Linux 使用经验与编程经验,并且希望对自己的系统拥有更强掌控力的开发者。
总的来说,我觉得 NixOS 适合那些有一定 Linux 使用经验与编程经验,并且希望对自己的系统拥有更
强掌控力的开发者。
我不推荐没有任何 Linux 使用经验的新人直接上手 NixOS那可能会是一段糟糕的旅程。

View file

@ -2,40 +2,60 @@
# Nix 与 NixOS 简介
Nix 是一个声明式的软件包管理器,用户需要通过某些配置声明好期望的环境状态,而 Nix 负责达成这个目标。
Nix 是一个声明式的软件包管理器,用户需要通过某些配置声明好期望的环境状态,而 Nix 负责达成
这个目标。
> 简单解释下什么是「声明式配置」,它是指用户只需要声明好自己想要的结果——比如说希望将 i3 桌面替换成 sway 桌面Nix 就会帮用户达成这个目标。
> 用户不需要关心底层细节(比如说 sway 需要安装哪些软件包,哪些 i3 相关的软件包需要卸载掉,哪些系统配置或环境变量需要针对 sway 做调整、如果使用了 Nvidia 显卡 Sway 参数要做什么调整才能正常运行等等Nix 会自动帮用户处理这些细节(当然这有个前提,就是 sway 跟 i3 相关的 nix 包设计良好)。
> 简单解释下什么是「声明式配置」,它是指用户只需要声明好自己想要的结果——比如说希望将 i3 桌
> 面替换成 sway 桌面Nix 就会帮用户达成这个目标。用户不需要关心底层细节(比如说 sway 需要
> 安装哪些软件包,哪些 i3 相关的软件包需要卸载掉,哪些系统配置或环境变量需要针对 sway 做调
> 整、如果使用了 Nvidia 显卡 Sway 参数要做什么调整才能正常运行等等Nix 会自动帮用户处理
> 这些细节(当然这有个前提,就是 sway 跟 i3 相关的 nix 包设计良好)。
而基于 Nix 包管理器构建的 Linux 发行版 NixOS可以简单用 OS as Code 来形容,它通过声明式的 Nix 配置文件来描述整个操作系统的状态。
而基于 Nix 包管理器构建的 Linux 发行版 NixOS可以简单用 OS as Code 来形容,它通过声明式的
Nix 配置文件来描述整个操作系统的状态。
一个操作系统中有各种各样的软件包、配置文件、文本或二进制的数据,这些都是系统当前的状态,而声明式的配置能够管理到的,只是其中静态的那一部分。
而那些动态的数据——比如说 PostgreSQL/MySQL/MongoDB 的数据,显然是无法通过声明式配置管理的(总不能每次部署都直接删除掉所有未在配置中声明的新数据吧)。
因此 NixOS 实际也只支持通过声明式配置管理系统的部分状态,上面提到的各种动态数据,以及用户 Home 目录中的所有内容,都不受它管控。
在你将 NixOS 切换到上一个版本时NixOS 不会对这些不受它管理的数据做任何操作。
一个操作系统中有各种各样的软件包、配置文件、文本或二进制的数据,这些都是系统当前的状态,而
声明式的配置能够管理到的,只是其中静态的那一部分。而那些动态的数据——比如说
PostgreSQL/MySQL/MongoDB 的数据,显然是无法通过声明式配置管理的(总不能每次部署都直接删除
掉所有未在配置中声明的新数据吧)。因此 NixOS 实际也只支持通过声明式配置管理系统的部分状
态,上面提到的各种动态数据,以及用户 Home 目录中的所有内容,都不受它管控。在你将 NixOS 切
换到上一个版本时NixOS 不会对这些不受它管理的数据做任何操作。
但是用户的 Home 目录中实际包含了许多重要的配置文件(或者叫 [Dotfiles](https://wiki.archlinux.org/title/Dotfiles)),用户当然会希望能使用 Nix 将它们给管理起来。
另一个重要的社区项目 [home-manager](https://github.com/nix-community/home-manager) 就填补了这块缺失,它被设计用于管理用户 Home 目录中的配置文件以及用户级别的软件包。
但是用户的 Home 目录中实际包含了许多重要的配置文件(或者叫
[Dotfiles](https://wiki.archlinux.org/title/Dotfiles)),用户当然会希望能使用 Nix 将它们给
管理起来。另一个重要的社区项目
[home-manager](https://github.com/nix-community/home-manager) 就填补了这块缺失,它被设计用
于管理用户 Home 目录中的配置文件以及用户级别的软件包。
因为 Nix 声明式、可复现的特性Nix 不仅可用于管理桌面电脑的环境也有很多人用它管理开发编译环境、云上虚拟机、容器镜像构建等等Nix 官方的 [NixOps](https://github.com/NixOS/nixops) 与社区的 [colmena](https://github.com/zhaofengli/colmena) 都是基于 Nix 实现的运维工具。
因为 Nix 声明式、可复现的特性Nix 不仅可用于管理桌面电脑的环境,也有很多人用它管理开发编
译环境、云上虚拟机、容器镜像构建等等Nix 官方的 [NixOps](https://github.com/NixOS/nixops)
与社区的 [colmena](https://github.com/zhaofengli/colmena) 都是基于 Nix 实现的运维工具。
## 为什么选择 NixOS
好几年前就听说过 Nix 包管理器,它用 Nix 语言编写配置来管理系统依赖,此外基于 Nix 包管理器设计的 Linux 发行版 NixOS还能随时将系统回滚到任一历史状态额实际上这个回滚有些限制前面提过了。 虽然听着很牛,但是不仅要多学一门语言,装个包还得写代码,当时觉得太麻烦就没研究。
好几年前就听说过 Nix 包管理器,它用 Nix 语言编写配置来管理系统依赖,此外基于 Nix 包管理器
设计的 Linux 发行版 NixOS还能随时将系统回滚到任一历史状态额实际上这个回滚有些限制
面提过了)。 虽然听着很牛,但是不仅要多学一门语言,装个包还得写代码,当时觉得太麻烦就没研
究。
但是我最近在使用 EndeavourOS 时遇到了一系列麻烦事儿,花了大量的精力去解决,搞得我精疲力尽。
我仔细一想,遇到的这些问题归根结底还是系统没有版本控制跟回滚机制,导致出了问题不能还原,就必须得各种查资料找 Bug手动修复系统状态。
但是我最近在使用 EndeavourOS 时遇到了一系列麻烦事儿,花了大量的精力去解决,搞得我精疲力
尽。我仔细一想,遇到的这些问题归根结底还是系统没有版本控制跟回滚机制,导致出了问题不能还
原,就必须得各种查资料找 Bug手动修复系统状态。
所以我就决定干脆换成 NixOS.
切换到 NixOS 后,我对它那是相当的满意,腰也不疼了,背也不酸了...
最惊艳的是,现在我可以通过仅仅一行命令(`sudo nixos-rebuild switch --flake .`),就能在一台全新安装的 NixOS 主机上还原我的整个 i3 桌面环境以及所有我的常用软件!
切换到 NixOS 后,我对它那是相当的满意,腰也不疼了,背也不酸了... 最惊艳的是,现在我可以通
过仅仅一行命令(`sudo nixos-rebuild switch --flake .`),就能在一台全新安装的 NixOS 主机上
还原我的整个 i3 桌面环境以及所有我的常用软件!
NixOS 的回滚能力与可复现能力给了我非常大的底气,我现在再也不用怕把系统搞挂了(挂了直接回滚就恢复了),于是我又在 NixOS 尝试了 Hyprland, Waybar 等等许多新鲜玩意儿~
在以前 EndeavourOS 上我肯定是不太敢这么玩的,因为万一要是把系统玩出毛病了,就必须手动排查问题、修复系统状态,那可是相当麻烦。
NixOS 的回滚能力与可复现能力给了我非常大的底气,我现在再也不用怕把系统搞挂了(挂了直接回滚
就恢复了),于是我又在 NixOS 尝试了 Hyprland, Waybar 等等许多新鲜玩意儿~ 在以前
EndeavourOS 上我肯定是不太敢这么玩的,因为万一要是把系统玩出毛病了,就必须手动排查问题、修
复系统状态,那可是相当麻烦。
随着我对 NixOS 与 Nix 的使用越来越深入,我发现它还非常适合用于同步管理多台主机的配置。
目前我的个人配置 [ryan4yin/nix-config](https://github.com/ryan4yin/nix-config) 同步管理了许多主机的配置:
随着我对 NixOS 与 Nix 的使用越来越深入,我发现它还非常适合用于同步管理多台主机的配置。目前
我的个人配置 [ryan4yin/nix-config](https://github.com/ryan4yin/nix-config) 同步管理了许多
主机的配置:
- 桌面电脑
- 一台 Macbook Pro 2020 (Intel amd64)
@ -45,4 +65,6 @@ NixOS 的回滚能力与可复现能力给了我非常大的底气,我现在
- 三台 NixOS 虚拟机(amd64)
- 若干块 aarch64 跟 riscv64 的开发板
其中三台桌面电脑的开发环境都通过 Home Manager 管理,主要配置完全共用,在任意一台主机上修改的配置,可以通过 Git 无缝同步到其他主机上。NixOS 几乎完全帮我屏蔽了三台机器底层的 OS 与芯片架构差异,体验非常丝滑!
其中三台桌面电脑的开发环境都通过 Home Manager 管理,主要配置完全共用,在任意一台主机上修改
的配置,可以通过 Git 无缝同步到其他主机上。NixOS 几乎完全帮我屏蔽了三台机器底层的 OS 与芯
片架构差异,体验非常丝滑!

View file

@ -3,7 +3,8 @@
Nix 有多种安装方式:
1. 以包管理器的形式安装到 MacOS/Linux/WSL 三种系统上
2. 也可以直接安装 NixOS这是 Nix 官方推出的一个 Linux 发行版,使用 Nix 包管理器来管理整个系统环境。
2. 也可以直接安装 NixOS这是 Nix 官方推出的一个 Linux 发行版,使用 Nix 包管理器来管理整个
系统环境。
本书主要介绍 NixOS 与 Flakes 的使用,因此不展开讨论。
@ -11,12 +12,15 @@ NixOS 的安装步骤很简单,这里不多介绍,仅列一下我觉得比
1. [NixOS 官网](https://nixos.org/download.html)
1. [NixOS-CN 社区的保姆级安装教程](https://nixos-cn.org/tutorials/installation/)
1. [复用 flake 管理 NixOS WSL](https://zhuanlan.zhihu.com/p/627073511): 使用 WSL 的用户可以参考下这篇文章
1. [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstart): macOS 用户可以通过这个模板仓库结合本书的内容来学习使用 Nix.
1. [复用 flake 管理 NixOS WSL](https://zhuanlan.zhihu.com/p/627073511): 使用 WSL 的用户可
以参考下这篇文章
1. [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstart):
macOS 用户可以通过这个模板仓库结合本书的内容来学习使用 Nix.
## 对中国大陆用户流畅使用 NixOS 的建议
国内用户在使用 NixOS 时会存在一些网络问题,一是 NixOS 高度依赖 GitHub 作为 channel/flake 数据源——在国内访问 GitHub 相当的慢,二是 NixOS 官方的包缓存服务器在国内访问速度较慢。
国内用户在使用 NixOS 时会存在一些网络问题,一是 NixOS 高度依赖 GitHub 作为 channel/flake
数据源——在国内访问 GitHub 相当的慢,二是 NixOS 官方的包缓存服务器在国内访问速度较慢。
为了解决这些问题,你可以使用国内的镜像源,或者使用代理工具来加速访问。
@ -24,7 +28,8 @@ NixOS 的安装步骤很简单,这里不多介绍,仅列一下我觉得比
### 1. 包缓存服务器的加速访问
首先,在执行后面给出的任何 `nix` 相关命令时,你都可以通过 `--option` 选项来指定镜像源,例如:
首先,在执行后面给出的任何 `nix` 相关命令时,你都可以通过 `--option` 选项来指定镜像源,例
如:
```bash
# 使用上海交通大学的镜像源
@ -61,9 +66,14 @@ sudo systemctl daemon-reload
sudo systemctl restart nix-daemon
```
**但请注意,系统重启后 `/run/` 目录下的内容会被清空,所以每次重启后都需要重新执行上述命令**
**但请注意,系统重启后 `/run/` 目录下的内容会被清空,所以每次重启后都需要重新执行上述命
令**
更详细的说明与其他用法介绍,参见 [添加自定义缓存服务器](../nixos-with-flakes/add-custom-cache-servers.md) 一节,注意这部分内容可能需要一定的 NixOS 使用经验才能理解。
更详细的说明与其他用法介绍,参见
[添加自定义缓存服务器](../nixos-with-flakes/add-custom-cache-servers.md) 一节,注意这部分
内容可能需要一定的 NixOS 使用经验才能理解。
> 注意:使用一些商用代理或公共代理时你可能会遇到 GitHub 下载时报 HTTP 403 错误([nixos-and-flakes-book/issues/74](https://github.com/ryan4yin/nixos-and-flakes-book/issues/74)
> 可尝试通过更换代理服务器或者设置 [access-tokens](https://github.com/NixOS/nix/issues/6536) 来解决。
> 注意:使用一些商用代理或公共代理时你可能会遇到 GitHub 下载时报 HTTP 403 错误
> [nixos-and-flakes-book/issues/74](https://github.com/ryan4yin/nixos-and-flakes-book/issues/74)
> 可尝试通过更换代理服务器或者设置
> [access-tokens](https://github.com/NixOS/nix/issues/6536) 来解决。

View file

@ -2,47 +2,73 @@
## 什么是 Nix 缓存服务器 {#what-is-nix-cache-server}
Nix 提供了官方缓存服务器 <https://cache.nixos.org>,它缓存了 nixpkgs 中所有 packages 在常用 CPU 指令集下的构建结果,当你在本地执行 Nix 构建指令时,如果 Nix 在服务器中匹配到对应的缓存,就会直接下载该缓存文件,跳过耗时的本地编译构建从而大大提升构建速度。
Nix 提供了官方缓存服务器 <https://cache.nixos.org>,它缓存了 nixpkgs 中所有 packages 在常
用 CPU 指令集下的构建结果,当你在本地执行 Nix 构建指令时,如果 Nix 在服务器中匹配到对应的
缓存,就会直接下载该缓存文件,跳过耗时的本地编译构建从而大大提升构建速度。
## 为什么要添加自定义缓存服务器 {#why-add-custom-cache-servers}
> 注意:这里介绍的手段只能加速部分包的下载,许多 inputs 数据源仍然会从 Github 拉取。
> 另外如果找不到缓存,会执行本地构建,这通常仍然需要从国外下载源码与构建依赖,因此仍然会很慢。为了完全解决速度问题,仍然建议使用旁路网关或 TUN 等全局代理方案。
> 注意:这里介绍的手段只能加速部分包的下载,许多 inputs 数据源仍然会从 Github 拉取。另外如
> 果找不到缓存,会执行本地构建,这通常仍然需要从国外下载源码与构建依赖,因此仍然会很慢。为
> 了完全解决速度问题,仍然建议使用旁路网关或 TUN 等全局代理方案。
两个原因:
1. 添加一些第三方项目的缓存服务器,例如 nix-community 的缓存服务器 <https://nix-community.cachix.org>,这可以大大提升这些第三方项目的构建速度。
1. 添加一些第三方项目的缓存服务器,例如 nix-community 的缓存服务器
<https://nix-community.cachix.org>,这可以大大提升这些第三方项目的构建速度。
1. 添加离用户最近的缓存服务器镜像站,用于加速下载。
1. 官方缓存服务器在中国的访问速度非常慢,如果没有局域网全局代理的话,基本上是无法使用的。添加国内的 ustc/sjtu/tuna 等 Nix 缓存镜像源可以缓解此问题。
1. 官方缓存服务器在中国的访问速度非常慢,如果没有局域网全局代理的话,基本上是无法使用
的。添加国内的 ustc/sjtu/tuna 等 Nix 缓存镜像源可以缓解此问题。
## 如何添加自定义缓存服务器 {#how-to-add-custom-cache-servers}
Nix 中通过如下几个 options 来配置缓存服务器:
1. [substituters](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-substituters): 它是一个字符串数组每个字符串都是一个缓存服务器的地址Nix 会按照数组中的顺序依次尝试从这些服务器中查找缓存。
2. [trusted-public-keys](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-public-keys): 为了防范恶意攻击Nix 默认启用 [require-sigs](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-require-sigs) 功能,只有附带了签名、且签名能被 `trusted-public-keys` 中的任意一个公钥验证通过的缓存,才会被 Nix 使用。因此我们需要将 `substituters` 对应的公钥添加到 `trusted-public-keys` 中。
1. 国内的镜像源都是直接从官方缓存服务器中同步的,因此它们的公钥与官方缓存服务器的公钥是一致的,我们可以直接使用官方缓存服务器的公钥,无需额外配置。
2. 这种完全依赖公钥机制的验证方式,实际是将安全责任转嫁给了用户。用户如果希望使用某个第三方库,但又希望使用它的第三方缓存服务器加快构建速度,那就必须自己承担对应的安全风险,自行决策是否将该缓存服务器的公钥添加进 `trusted-public-keys`。为了完全解决这个信任问题Nix 推出了实验特性 [ca-derivations](https://nixos.wiki/wiki/Ca-derivations),它不依赖 `trusted-public-keys` 进行签名校验,有兴趣的可以自行了解。
1. [substituters](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-substituters):
它是一个字符串数组每个字符串都是一个缓存服务器的地址Nix 会按照数组中的顺序依次尝试
从这些服务器中查找缓存。
2. [trusted-public-keys](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-public-keys):
为了防范恶意攻击Nix 默认启用
[require-sigs](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-require-sigs)
功能,只有附带了签名、且签名能被 `trusted-public-keys` 中的任意一个公钥验证通过的缓存,
才会被 Nix 使用。因此我们需要将 `substituters` 对应的公钥添加到 `trusted-public-keys`
中。
1. 国内的镜像源都是直接从官方缓存服务器中同步的,因此它们的公钥与官方缓存服务器的公钥是
一致的,我们可以直接使用官方缓存服务器的公钥,无需额外配置。
2. 这种完全依赖公钥机制的验证方式,实际是将安全责任转嫁给了用户。用户如果希望使用某个第
三方库,但又希望使用它的第三方缓存服务器加快构建速度,那就必须自己承担对应的安全风
险,自行决策是否将该缓存服务器的公钥添加进 `trusted-public-keys`。为了完全解决这个信
任问题Nix 推出了实验特性
[ca-derivations](https://nixos.wiki/wiki/Ca-derivations),它不依赖
`trusted-public-keys` 进行签名校验,有兴趣的可以自行了解。
可通过如下几种方式来配置 `substituters` `trusted-public-keys` 两个参数:
1. 在 `/etc/nix/nix.conf` 中配置,这是全局配置,对所有用户生效。
1. 可在任一 NixOS Module 中通过 `nix.settings.substituters``nix.settings.trusted-public-keys` 来声明式地生成 `/etc/nix/nix.conf`.
2. 在 flake 项目的 `flake.nix` 中通过 `nixConfig.substituters` 来配置,此配置仅对当前 flake 生效。
3. 可通过 `nix` 指令的 `--option substituters="http://xxx"` 参数来临时设定,此配置仅对当前指令生效。
1. 可在任一 NixOS Module 中通过 `nix.settings.substituters`
`nix.settings.trusted-public-keys` 来声明式地生成 `/etc/nix/nix.conf`.
2. 在 flake 项目的 `flake.nix` 中通过 `nixConfig.substituters` 来配置,此配置仅对当前
flake 生效。
3. 可通过 `nix` 指令的 `--option substituters="http://xxx"` 参数来临时设定,此配置仅对当前
指令生效。
上面三种方式中,除了第一种全局配置外,其他两种都是临时配置。如果同时使用了多种方式,那么后面的配置会直接覆盖前面的配置。
上面三种方式中,除了第一种全局配置外,其他两种都是临时配置。如果同时使用了多种方式,那么后
面的配置会直接覆盖前面的配置。
但临时设置 `substituters` 存在安全风险,前面我们也解释了基于 `trusted-public-keys` 的安全验证机制存在缺陷。
将一个不可信的缓存服务器添加到 substituters 中,可能会导致包含恶意内容的缓存被复制到 Nix Store 中。
因此 Nix 对 substituters 的临时设置做出了限制,要想通过第二三种方式设定 substituers前提是满足如下任意一个条件
但临时设置 `substituters` 存在安全风险,前面我们也解释了基于 `trusted-public-keys` 的安全
验证机制存在缺陷。将一个不可信的缓存服务器添加到 substituters 中,可能会导致包含恶意内容的
缓存被复制到 Nix Store 中。因此 Nix 对 substituters 的临时设置做出了限制,要想通过第二三种
方式设定 substituers前提是满足如下任意一个条件
1. [`/etc/nix/nix.conf` 中的 `trusted-users`](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-users) 参数列表中包含当前用户。
2. [`/etc/nix/nix.conf` 中的 `trusted-substituters`](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-substituters) 参数列表中包含我们临时指定的 substituters.
1. [`/etc/nix/nix.conf` 中的 `trusted-users`](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-users)
参数列表中包含当前用户。
2. [`/etc/nix/nix.conf` 中的 `trusted-substituters`](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-trusted-substituters)
参数列表中包含我们临时指定的 substituters.
基于上述信息,如下是上述三种配置方式的示例。
首先是通过 `nix.settings` 声明式地配置系统层面的 substituters 与 trusted-public-keys, 将如下配置添加到 `/etc/nixos/configuration.nix` 或其他任一 NixOS Module 中即可:
首先是通过 `nix.settings` 声明式地配置系统层面的 substituters 与 trusted-public-keys, 将如
下配置添加到 `/etc/nixos/configuration.nix` 或其他任一 NixOS Module 中即可:
```nix{7-27}
{
@ -76,9 +102,11 @@ Nix 中通过如下几个 options 来配置缓存服务器:
}
```
第二种方案是通过 `flake.nix` 配置 substituters 与 trusted-public-keys将如下配置添加到 `flake.nix` 中即可:
第二种方案是通过 `flake.nix` 配置 substituters 与 trusted-public-keys将如下配置添加到
`flake.nix` 中即可:
> 如前所述,此配置中的 `nix.settings.trusted-users` 也是必须配置的,否则我们在这里设置的 `substituters` 将无法生效。
> 如前所述,此配置中的 `nix.settings.trusted-users` 也是必须配置的,否则我们在这里设置的
> `substituters` 将无法生效。
```nix{5-23,43-47}
{
@ -142,21 +170,29 @@ Nix 中通过如下几个 options 来配置缓存服务器:
sudo nixos-rebuild switch --option substituters "https://nix-community.cachix.org" --option trusted-public-keys "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
```
选择上述三种方案的任一一种进行配置并部署,部署成功之后,后续所有的包都会优先从国内镜像源查找缓存。
选择上述三种方案的任一一种进行配置并部署,部署成功之后,后续所有的包都会优先从国内镜像源查
找缓存。
> 如果你的系统 Hostname 不是 `my-nixos`,你需要在 `flake.nix` 中修改 `nixosConfigurations` 的名称,或者使用 `--flake /etc/nixos#my-nixos` 来指定配置名称。
> 如果你的系统 Hostname 不是 `my-nixos`,你需要在 `flake.nix` 中修改 `nixosConfigurations`
> 的名称,或者使用 `--flake /etc/nixos#my-nixos` 来指定配置名称。
### Nix options 参数的 `extra-` 前缀
前面提到的三种方式配置的 `substituters` 会相互覆盖,但比较理想的情况应该是:
1. 在系统层面的 `/etc/nix/nix.conf` 中仅配置最通用的 substituters 与 trusted-public-keys例如官方缓存服务器与国内镜像源。
2. 在每个 flake 项目的 `flake.nix` 中配置该项目特有的 substituters 与 trusted-public-keys例如 nix-community 等非官方的缓存服务器。
3. 在构建 flake 项目时,应该将 `flake.nix``/etx/nix/nix.conf` 中配置的 substituters 与 trusted-public-keys **合并**使用。
1. 在系统层面的 `/etc/nix/nix.conf` 中仅配置最通用的 substituters 与 trusted-public-keys
例如官方缓存服务器与国内镜像源。
2. 在每个 flake 项目的 `flake.nix` 中配置该项目特有的 substituters 与
trusted-public-keys例如 nix-community 等非官方的缓存服务器。
3. 在构建 flake 项目时,应该将 `flake.nix``/etx/nix/nix.conf` 中配置的 substituters 与
trusted-public-keys **合并**使用。
Nix 提供了 [`extra-` 前缀](https://nixos.org/manual/nix/stable/command-ref/conf-file.html?highlight=extra#file-format) 实现了这个**合并**功能。
Nix 提供了
[`extra-` 前缀](https://nixos.org/manual/nix/stable/command-ref/conf-file.html?highlight=extra#file-format)
实现了这个**合并**功能。
据官方文档介绍,如果 `xxx` 参数的值是一个列表,那么 `extra-xxx` 参数的值会被追加到 `xxx` 参数的值后面:
据官方文档介绍,如果 `xxx` 参数的值是一个列表,那么 `extra-xxx` 参数的值会被追加到 `xxx`
参数的值后面:
也就是说我们可以这么用:
@ -231,16 +267,21 @@ Nix 提供了 [`extra-` 前缀](https://nixos.org/manual/nix/stable/command-ref/
## 通过代理加速包下载 {#accelerate-package-downloads-via-a-proxy-server}
> 参考了 Issue: [roaming laptop: network proxy configuration - NixOS/nixpkgs](https://github.com/NixOS/nixpkgs/issues/27535#issuecomment-1178444327)
> 参考了 Issue:
> [roaming laptop: network proxy configuration - NixOS/nixpkgs](https://github.com/NixOS/nixpkgs/issues/27535#issuecomment-1178444327)
虽然前面提到了,旁路网关可以完全解决 NixOS 的包下载速度问题,但是旁路网关的配置比较麻烦,而且经常需要额外的硬件支持。
虽然前面提到了,旁路网关可以完全解决 NixOS 的包下载速度问题,但是旁路网关的配置比较麻烦,
而且经常需要额外的硬件支持。
更多的用户可能会希望能直接通过 HTTP/Socks5 代理来加速包下载,这里介绍下怎么设置。
直接在 Terminal 中使用 `export HTTPS_PROXY=http://127.0.0.1:7890` 这类方式是无法生效的,因为 nix 实际干活的是一个叫 `nix-daemon` 的后台进程,而不是直接在 Terminal 中执行的命令。
直接在 Terminal 中使用 `export HTTPS_PROXY=http://127.0.0.1:7890` 这类方式是无法生效的,因
为 nix 实际干活的是一个叫 `nix-daemon` 的后台进程,而不是直接在 Terminal 中执行的命令。
nix-daemon 的实现代码是 [nixpkgs/nixos/modules/services/system/nix-daemon.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/modules/services/system/nix-daemon.nix#L184-L191)
它通过 `systemd.services.nix-daemon.environment` 选项设置了环境变量,我们也能通过同样的手段来往 nix-daemon 的运行环境中添加代理相关的环境变量,一个示例 Module 如下:
nix-daemon 的实现代码是
[nixpkgs/nixos/modules/services/system/nix-daemon.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/modules/services/system/nix-daemon.nix#L184-L191)
它通过 `systemd.services.nix-daemon.environment` 选项设置了环境变量,我们也能通过同样的手
段来往 nix-daemon 的运行环境中添加代理相关的环境变量,一个示例 Module 如下:
```nix
{
@ -252,9 +293,11 @@ nix-daemon 的实现代码是 [nixpkgs/nixos/modules/services/system/nix-daemon.
}
```
部署此配置后,可通过 `sudo cat /proc/$(pidof nix-daemon)/environ | tr '\0' '\n'` 查看 nix-daemon 进程的所有环境变量,确认环境变量的设置是否生效。
部署此配置后,可通过 `sudo cat /proc/$(pidof nix-daemon)/environ | tr '\0' '\n'` 查看
nix-daemon 进程的所有环境变量,确认环境变量的设置是否生效。
**但是要注意当代理服务器不可用时nix-daemon 将无法访问任何缓存服务器**!所以我还是更建议使用旁路网关等透明代理方案。
**但是要注意当代理服务器不可用时nix-daemon 将无法访问任何缓存服务器**!所以我还是更建
议使用旁路网关等透明代理方案。
如果你只是临时需要使用代理,可以通过如下命令设置代理环境变量:
@ -268,7 +311,10 @@ sudo systemctl daemon-reload
sudo systemctl restart nix-daemon
```
位于 `/run/systemd/system/nix-daemon.service.d/override.conf` 的设置会在系统重启后被自动删除,或者你可以手动删除它并重启 nix-daemon 服务来恢复原始设置。
位于 `/run/systemd/system/nix-daemon.service.d/override.conf` 的设置会在系统重启后被自动删
除,或者你可以手动删除它并重启 nix-daemon 服务来恢复原始设置。
> 使用一些商用代理或公共代理时你可能会遇到 GitHub 下载时报 HTTP 403 错误([nixos-and-flakes-book/issues/74](https://github.com/ryan4yin/nixos-and-flakes-book/issues/74)
> 可尝试通过更换代理服务器或者设置 [access-tokens](https://github.com/NixOS/nix/issues/6536) 来解决。
> 使用一些商用代理或公共代理时你可能会遇到 GitHub 下载时报 HTTP 403 错误
> [nixos-and-flakes-book/issues/74](https://github.com/ryan4yin/nixos-and-flakes-book/issues/74)
> 可尝试通过更换代理服务器或者设置
> [access-tokens](https://github.com/NixOS/nix/issues/6536) 来解决。

View file

@ -1,10 +1,15 @@
# 降级与升级软件包 {#rollback-package-version}
在使用 Nix Flakes 后,目前大家用得比较多的都是 `nixos-unstable` 分支的 nixpkgs有时候就会遇到一些 bug比如我最近2023/5/6就遇到了 [chrome/vscode 闪退的问题](https://github.com/swaywm/sway/issues/7562)。
在使用 Nix Flakes 后,目前大家用得比较多的都是 `nixos-unstable` 分支的 nixpkgs有时候就会
遇到一些 bug比如我最近2023/5/6就遇到了
[chrome/vscode 闪退的问题](https://github.com/swaywm/sway/issues/7562)。
这时候就需要退回到之前的版本,在 Nix Flakes 中,所有的包版本与 hash 值与其 input 数据源的 git commit 是一一对应的关系,因此回退某个包的到历史版本,就需要锁定其 input 数据源的 git commit.
这时候就需要退回到之前的版本,在 Nix Flakes 中,所有的包版本与 hash 值与其 input 数据源的
git commit 是一一对应的关系,因此回退某个包的到历史版本,就需要锁定其 input 数据源的 git
commit.
为了实现上述需求,首先修改 `/etc/nixos/flake.nix`,示例内容如下(主要是利用 `specialArgs` 参数):
为了实现上述需求,首先修改 `/etc/nixos/flake.nix`,示例内容如下(主要是利用 `specialArgs`
参数):
```nix{8-13,19-20,27-44}
{
@ -94,6 +99,11 @@
}
```
配置完成后,通过 `sudo nixos-rebuild switch` 部署即可将 firefox/chrome/vscode 三个软件包回退到 stable 分支的版本。
配置完成后,通过 `sudo nixos-rebuild switch` 部署即可将 firefox/chrome/vscode 三个软件包回
退到 stable 分支的版本。
> 根据 @fbewivpjsbsby 补充的文章 [1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347),在子模块或者子 flakes 中用 `import` 来定制 `nixpkgs` 不是一个好的习惯,因为每次 `import` 都会重新求值并产生一个新的 nixpkgs 实例,在配置越来越多时会导致构建时间变长、内存占用变大。所以这里改为了在 `flake.nix` 中创建所有 nixpkgs 实例。
> 根据 @fbewivpjsbsby 补充的文章
> [1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347)
> 在子模块或者子 flakes 中用 `import` 来定制 `nixpkgs` 不是一个好的习惯,因为每次 `import`
> 都会重新求值并产生一个新的 nixpkgs 实例,在配置越来越多时会导致构建时间变长、内存占用变
> 大。所以这里改为了在 `flake.nix` 中创建所有 nixpkgs 实例。

View file

@ -1,23 +1,29 @@
# 开始使用 NixOS
了解了 Nix 语言的基本用法之后,我们就可以开始使用 Nix 语言来配置 NixOS 系统了。
NixOS 的系统配置路径为 `/etc/nixos/configuration.nix`,它包含系统的所有声明式配置,如时区、语言、键盘布局、网络、用户、文件系统、启动项、桌面环境等等。
了解了 Nix 语言的基本用法之后,我们就可以开始使用 Nix 语言来配置 NixOS 系统了。NixOS 的系
统配置路径为 `/etc/nixos/configuration.nix`,它包含系统的所有声明式配置,如时区、语言、键
盘布局、网络、用户、文件系统、启动项、桌面环境等等。
如果想要以可复现的方式修改系统的状态(这也是最推荐的方式),就需要手工修改 `/etc/nixos/configuration.nix` 文件,然后执行 `sudo nixos-rebuild switch` 命令来应用配置,此命令会根据配置文件生成一个新的系统环境,并将新的环境设为默认环境。
同时上一个系统环境会被保留,而且会被加入到 grub 的启动项中,这确保了即使新的环境不能启动,也能随时回退到旧环境。
如果想要以可复现的方式修改系统的状态(这也是最推荐的方式),就需要手工修改
`/etc/nixos/configuration.nix` 文件,然后执行 `sudo nixos-rebuild switch` 命令来应用配置,
此命令会根据配置文件生成一个新的系统环境,并将新的环境设为默认环境。同时上一个系统环境会被
保留,而且会被加入到 grub 的启动项中,这确保了即使新的环境不能启动,也能随时回退到旧环境。
另一方面,`/etc/nixos/configuration.nix` 是传统的 Nix 配置方式,它依赖 `nix-channel` 配置的数据源,也没有任何版本锁定机制,实际无法确保系统的可复现性。
**更推荐使用的是 Nix Flakes**,它可以确保系统的可复现性,同时也可以很方便地管理系统的配置。
另一方面,`/etc/nixos/configuration.nix` 是传统的 Nix 配置方式,它依赖 `nix-channel` 配置
的数据源,也没有任何版本锁定机制,实际无法确保系统的可复现性。 **更推荐使用的是 Nix
Flakes**,它可以确保系统的可复现性,同时也可以很方便地管理系统的配置。
我们下面首先介绍下通过 NixOS 默认的配置方式来管理系统,然后再过渡到更先进的 Nix Flakes.
## 使用 `/etc/nixos/configuration.nix` 配置系统 {#configuration-nix}
前面提过了这是传统的 Nix 配置方式,也是当前 NixOS 默认使用的配置方式,它依赖 `nix-channel` 配置的数据源,也没有任何版本锁定机制,实际无法确保系统的可复现性。
前面提过了这是传统的 Nix 配置方式,也是当前 NixOS 默认使用的配置方式,它依赖 `nix-channel`
配置的数据源,也没有任何版本锁定机制,实际无法确保系统的可复现性。
简单起见我们先使用这种方式来配置系统,后面会介绍 Flake 的使用。
比如要启用 ssh 并添加一个用户 ryan只需要在 `/etc/nixos/configuration.nix` 中添加如下配置:
比如要启用 ssh 并添加一个用户 ryan只需要在 `/etc/nixos/configuration.nix` 中添加如下配
置:
```nix{14-38}
# Edit this configuration file to define what should be installed on
@ -65,17 +71,23 @@ NixOS 的系统配置路径为 `/etc/nixos/configuration.nix`,它包含系统
这里我启用了 openssh 服务,为 ryan 用户添加了 ssh 公钥,并禁用了密码登录。
现在运行 `sudo nixos-rebuild switch` 部署修改后的配置,之后就可以通过 ssh 密钥远程登录到我的这台主机了。
现在运行 `sudo nixos-rebuild switch` 部署修改后的配置,之后就可以通过 ssh 密钥远程登录到我
的这台主机了。
> 如果你在部署配置时遇到了任何错误,都可以尝试在 `nixos-rebuild` 命令后面添加 `--show-trace --print-build-logs --verbose` 参数来获取详细的错误信息。举例如下:
> 如果你在部署配置时遇到了任何错误,都可以尝试在 `nixos-rebuild` 命令后面添加
> `--show-trace --print-build-logs --verbose` 参数来获取详细的错误信息。举例如下:
这就是 NixOS 默认的声明式系统配置,要对系统做任何可复现的变更,都只需要修改 `/etc/nixos/configuration.nix` 文件,然后运行 `sudo nixos-rebuild switch` 部署变更即可。
这就是 NixOS 默认的声明式系统配置,要对系统做任何可复现的变更,都只需要修改
`/etc/nixos/configuration.nix` 文件,然后运行 `sudo nixos-rebuild switch` 部署变更即可。
`/etc/nixos/configuration.nix` 的所有配置项,可以在这几个地方查到:
- 直接 Google比如 `Chrome NixOS` 就能找到 Chrome 相关的配置项,一般 NixOS Wiki 或 nixpkgs 仓库源码的排名会比较靠前。
- 直接 Google比如 `Chrome NixOS` 就能找到 Chrome 相关的配置项,一般 NixOS Wiki 或
nixpkgs 仓库源码的排名会比较靠前。
- 在 [NixOS Options Search](https://search.nixos.org/options) 中搜索关键字
- 系统级别的配置,可以考虑在 [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)
找找相关文档
- 直接在 [nixpkgs](https://github.com/NixOS/nixpkgs) 仓库中搜索关键字,读相关的源码。
## 参考

View file

@ -1,30 +1,39 @@
# Flakes 简介
Flakes 实验特性是 Nix 项目的一项重大进展,它引入了一种管理 Nix 表达式之间的依赖关系的策略,提高了 Nix 生态系统中的可复现性、可组合性和可用性。
虽然 Flakes 仍然是一个试验性的功能,但已经被 Nix 社区广泛采用。[^1]
Flakes 实验特性是 Nix 项目的一项重大进展,它引入了一种管理 Nix 表达式之间的依赖关系的策
略,提高了 Nix 生态系统中的可复现性、可组合性和可用性。虽然 Flakes 仍然是一个试验性的功
能,但已经被 Nix 社区广泛采用。[^1]
Flakes 特性是 Nix 项目中最有意义的变化之一。[^2]
简单的说,如果你写过点 JavaScript/Go/Rust/Python那你应该对 `package.json`/`go.mod`/`Cargo.toml`/`pyproject.toml` 这些文件不陌生,
在这些编程语言中,这些文件用来描述软件包之间的依赖关系,以及如何构建项目。
同样的,这些编程语言的包管理器还通过 `package-lock.json`/`go.sum`/`Cargo.lock`/`poetry.lock` 这些文件来锁定依赖的版本,以保证项目的可复现性。
简单的说,如果你写过点 JavaScript/Go/Rust/Python那你应该对
`package.json`/`go.mod`/`Cargo.toml`/`pyproject.toml` 这些文件不陌生,在这些编程语言中,这
些文件用来描述软件包之间的依赖关系,以及如何构建项目。同样的,这些编程语言的包管理器还通过
`package-lock.json`/`go.sum`/`Cargo.lock`/`poetry.lock` 这些文件来锁定依赖的版本,以保证项
目的可复现性。
Flakes 就是从上述这类编程语言的包管理器中借鉴了这种描述依赖关系与锁定依赖版本的思路,以提高 Nix 生态系统中的可复现性、可组合性和可用性。
Flakes 就是从上述这类编程语言的包管理器中借鉴了这种描述依赖关系与锁定依赖版本的思路,以提
高 Nix 生态系统中的可复现性、可组合性和可用性。
Flakes 提供了 `flake.nix`,它类似 `package.json`,用来描述 Nix 包之间的依赖关系,以及如何构建项目。
同时它还提供了 `flake.lock`,这是一个类似 `package-lock.json` 的文件,用来锁定依赖的版本,以保证项目的可复现性。
Flakes 提供了 `flake.nix`,它类似 `package.json`,用来描述 Nix 包之间的依赖关系,以及如何
构建项目。同时它还提供了 `flake.lock`,这是一个类似 `package-lock.json` 的文件,用来锁定依
赖的版本,以保证项目的可复现性。
另一方面Flakes 实验特性并没有破坏 Nix 用户层面的原有设计,
它新引入的 `flake.nix`/`flake.lock` 两个文件只是其他 Nix 配置的一个 Wrapper
在后面的章节的学习中我们将会看到Flakes 特性是在 Nix 原有设计的基础上提供了一种新的、更方便的管理 Nix 表达式之间的依赖关系的方式。
另一方面Flakes 实验特性并没有破坏 Nix 用户层面的原有设计,它新引入的
`flake.nix`/`flake.lock` 两个文件只是其他 Nix 配置的一个 Wrapper在后面的章节的学习中我们
将会看到Flakes 特性是在 Nix 原有设计的基础上提供了一种新的、更方便的管理 Nix 表达式之间
的依赖关系的方式。
## 注意事项 <Badge type="danger" text="caution" />
Flakes 带来的好处是显而易见的,整个 NixOS 社区都很喜欢它,目前超过半数的用户已经在大量使用 Flakes[^3],因此我们可以相当确定 Flakes 不会被废弃。
Flakes 带来的好处是显而易见的,整个 NixOS 社区都很喜欢它,目前超过半数的用户已经在大量使用
Flakes[^3],因此我们可以相当确定 Flakes 不会被废弃。
:warning:但是 Flakes 目前仍然存在一些问题因此在将它推向稳定的过程中Nix 可能会引入一些不兼容的改动,这个改动的大小目前还无法确定。
:warning:但是 Flakes 目前仍然存在一些问题因此在将它推向稳定的过程中Nix 可能会引入一些
不兼容的改动,这个改动的大小目前还无法确定。
总的来说,我仍然推荐大家使用 Flakes毕竟这本书本身也是围绕 NixOS 与 Flakes 编写的,但是也要做好准备——未来可能需要解决一些不兼容变更带来的问题。
总的来说,我仍然推荐大家使用 Flakes毕竟这本书本身也是围绕 NixOS 与 Flakes 编写的,但是也
要做好准备——未来可能需要解决一些不兼容变更带来的问题。
## Flakes 入门
@ -40,39 +49,67 @@ Flakes 带来的好处是显而易见的,整个 NixOS 社区都很喜欢它,
我深入了解了下 Flakes 现状与未来计划相关的资料,大概有这些:
- [[RFC 0136] A Plan to Stabilize Flakes and the New CLI Incrementally](https://github.com/NixOS/rfcs/pull/136): 一份渐进式地将 Flakes 与 new CLI 两个实验性特性推向稳定的 RFC已 Merge.
- [CLI stabilization effort](https://github.com/NixOS/nix/issues/7701): 一份追踪 New CLI 稳定化工作进度的 Issue.
- [Why are flakes still experimental? - NixOS Discourse](https://discourse.nixos.org/t/why-are-flakes-still-experimental/29317): 最近的一次关于 Flakes 稳定性的讨论,可以看到大家的疑惑,以及社区对 Flakes 的态度。
- [Flakes are such an obviously good thing - Graham Christensen](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/): NixOS 社区成员的文章,记录了他对 Flakes 的看法,以及对社区当初添加 Flakes 特性时的不当举措的懊悔。
- [ teaching Nix 3 CLI and Flakes #281 - nix.dev](https://github.com/NixOS/nix.dev/issues/281): 社区关于是否应该在 NixOS 官方文档中介绍 Flakes 的讨论,当前结论是官方文档不应该推广使用 unstable 功能。
- [Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9): NixOS Foundation 的一份 Roadmap其中提到了 Flakes 的计划:`Stabilize flakes and release Nix 3.0. Flakes are widely used (there are more GitHub repos being created with a flake.nix than a default.nix) but theyre still marked as experimental, which is not a good situation. The same applies to the new nix CLI.`
- [[RFC 0136] A Plan to Stabilize Flakes and the New CLI Incrementally](https://github.com/NixOS/rfcs/pull/136):
一份渐进式地将 Flakes 与 new CLI 两个实验性特性推向稳定的 RFC已 Merge.
- [CLI stabilization effort](https://github.com/NixOS/nix/issues/7701): 一份追踪 New CLI
稳定化工作进度的 Issue.
- [Why are flakes still experimental? - NixOS Discourse](https://discourse.nixos.org/t/why-are-flakes-still-experimental/29317):
最近的一次关于 Flakes 稳定性的讨论,可以看到大家的疑惑,以及社区对 Flakes 的态度。
- [Flakes are such an obviously good thing - Graham Christensen](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/):
NixOS 社区成员的文章,记录了他对 Flakes 的看法,以及对社区当初添加 Flakes 特性时的不当举
措的懊悔。
- [ teaching Nix 3 CLI and Flakes #281 - nix.dev](https://github.com/NixOS/nix.dev/issues/281):
社区关于是否应该在 NixOS 官方文档中介绍 Flakes 的讨论,当前结论是官方文档不应该推广使用
unstable 功能。
- [Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9):
NixOS Foundation 的一份 Roadmap其中提到了 Flakes 的计
划:`Stabilize flakes and release Nix 3.0. Flakes are widely used (there are more GitHub repos being created with a flake.nix than a default.nix) but theyre still marked as experimental, which is not a good situation. The same applies to the new nix CLI.`
读完上述内容后,个人猜测,**Flakes 有可能(仅是可能)会在未来两年内成为稳定特性**。
## Nix 的新 CLI 与旧的 CLI {#the-new-cli-and-the-classic-cli}
Nix 于 2020 年推出了 `nix-command` & `flakes` 两个实验特性,它们提供了全新的命令行工具(即 New CLI、标准的 Nix 包结构定义(即 Flakes 特性)、类似 cargo/npm 的 `flake.lock` 版本锁文件等等。这两个特性极大地增强了 Nix 的能力因此虽然至今2024/2/1它们仍然是实验性特性但是已经被 Nix 社区广泛使用。
Nix 于 2020 年推出了 `nix-command` & `flakes` 两个实验特性,它们提供了全新的命令行工具(即
New CLI、标准的 Nix 包结构定义(即 Flakes 特性)、类似 cargo/npm 的 `flake.lock` 版本锁
文件等等。这两个特性极大地增强了 Nix 的能力因此虽然至今2024/2/1它们仍然是实验性特
性,但是已经被 Nix 社区广泛使用。
当前 Nix 的 New CLI`nix-command` 实验特性) 与 Flakes 实验特性是强绑定的关系,虽然现在已经有明确的拆分计划正在推进中了,但要用 Flakes 基本上就必须得用 New CLI.
而本书作为一本 NixOS & Flakes 新手指南,就有必要介绍下 Flakes 实验特性所依赖的 New CLI 与旧的 CLI 的区别。
当前 Nix 的 New CLI`nix-command` 实验特性) 与 Flakes 实验特性是强绑定的关系,虽然现
在已经有明确的拆分计划正在推进中了,但要用 Flakes 基本上就必须得用 New CLI. 而本书作为一本
NixOS & Flakes 新手指南,就有必要介绍下 Flakes 实验特性所依赖的 New CLI 与旧的 CLI 的区
别。
这里列举下在启用了 New CLI 与 Flakes(`nix-command` & `flakes`) 实验特性后,已经不需要用到的旧的 Nix 命令行工具与相关概念。
在查找资料时,如果看到它们直接忽略掉就行(`nix-collect-garbage` 除外,该命令目前暂无替代):
这里列举下在启用了 New CLI 与 Flakes(`nix-command` & `flakes`) 实验特性后,已经不需要用到
的旧的 Nix 命令行工具与相关概念。在查找资料时,如果看到它们直接忽略掉就行
`nix-collect-garbage` 除外,该命令目前暂无替代):
1. `nix-channel`: 与 apt/yum/pacman 等其他 Linux 发行版的包管理工具类似,传统的 Nix 也以 stable/unstable/test 等 channel 的形式来管理软件包的版本,可通过此命令修改 Nix 的 channel 信息。
1. Nix Flakes 在 `flake.nix` 中通过 `inputs` 声明依赖包的数据源,通过 `flake.lock` 锁定依赖版本,完全取代掉了 `nix-channel` 的功能。
2. `nix-env`: 用于管理用户环境的软件包,是传统 Nix 的核心命令行工具。它从 `nix-channel` 定义的数据源中安装软件包,所以安装的软件包版本受 channel 影响。
1. 通过 `nix-env` 安装的包不会被自动记录到 Nix 的声明式配置中,是完全脱离掌控的,无法在其他主机上复现,因此不推荐使用。
1. `nix-channel`: 与 apt/yum/pacman 等其他 Linux 发行版的包管理工具类似,传统的 Nix 也以
stable/unstable/test 等 channel 的形式来管理软件包的版本,可通过此命令修改 Nix 的
channel 信息。
1. Nix Flakes 在 `flake.nix` 中通过 `inputs` 声明依赖包的数据源,通过 `flake.lock` 锁定
依赖版本,完全取代掉了 `nix-channel` 的功能。
2. `nix-env`: 用于管理用户环境的软件包,是传统 Nix 的核心命令行工具。它从 `nix-channel`
义的数据源中安装软件包,所以安装的软件包版本受 channel 影响。
1. 通过 `nix-env` 安装的包不会被自动记录到 Nix 的声明式配置中,是完全脱离掌控的,无法在
其他主机上复现,因此不推荐使用。
2. New CLI 中对应的命令为 `nix profile`,我个人不太推荐初学者直接尝试它.
3. `nix-shell`: nix-shell 用于创建一个临时的 shell 环境
1. 这玩意儿可能有点复杂了,因此在 New CLI 中它被拆分成了三个子命令 `nix develop`, `nix shell` 以及 `nix run`,我们会在「[构建开发环境](../development/intro.md)」一章详细介绍这三个命令。
4. `nix-build`: 用于构建 Nix 包,它会将构建结果放到 `/nix/store` 路径下,但是不会记录到 Nix 的声明式配置中。
1. 这玩意儿可能有点复杂了,因此在 New CLI 中它被拆分成了三个子命令 `nix develop`,
`nix shell` 以及 `nix run`,我们会在「[构建开发环境](../development/intro.md)」一章
详细介绍这三个命令。
4. `nix-build`: 用于构建 Nix 包,它会将构建结果放到 `/nix/store` 路径下,但是不会记录到
Nix 的声明式配置中。
1. 在 New CLI 中对应的命令为 `nix build`
5. `nix-collect-garbage`: 垃圾回收指令,用于清理 `/nix/store` 中未被使用的 Store Objects.
1. 在 New CLI 中有个相似的指令 `nix store gc --debug`,但它不会清理 profile 生成的历史版本,因此此命令暂无替代。
1. 在 New CLI 中有个相似的指令 `nix store gc --debug`,但它不会清理 profile 生成的历史
版本,因此此命令暂无替代。
6. 以及其他使用地较少的命令,就不一一列出了.
1. 详细的命令对比列表可以看看 [Try to explain nix commands](https://qiita-com.translate.goog/Sumi-Sumi/items/6de9ee7aab10bc0dbead?_x_tr_sl=auto&_x_tr_tl=en&_x_tr_hl=en)
1. 详细的命令对比列表可以看看
[Try to explain nix commands](https://qiita-com.translate.goog/Sumi-Sumi/items/6de9ee7aab10bc0dbead?_x_tr_sl=auto&_x_tr_tl=en&_x_tr_hl=en)
[^1]: [Flakes - NixOS Wiki](https://nixos.wiki/index.php?title=Flakes)
[^2]: [Flakes are such an obviously good thing](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/)
[^3]: [Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9)
[^2]:
[Flakes are such an obviously good thing](https://grahamc.com/blog/flakes-are-an-obviously-good-thing/)
[^3]:
[Draft: 1 year roadmap - NixOS Foundation](https://nixos-foundation.notion.site/1-year-roadmap-0dc5c2ec265a477ea65c549cd5e568a9)

View file

@ -13,20 +13,35 @@ $ tree
下面分别说明下这四个文件的功能:
- `flake.lock`: 自动生成的版本锁文件,它记录了整个 flake 所有输入的数据源、hash 值、版本号,确保系统可复现。
- `flake.lock`: 自动生成的版本锁文件,它记录了整个 flake 所有输入的数据源、hash 值、版本
号,确保系统可复现。
- `flake.nix`: flake 的入口文件,执行 `sudo nixos-rebuild switch` 时会识别并部署它。
- `configuration.nix`: 在 flake.nix 中被作为系统模块导入,目前所有系统级别的配置都写在此文件中。
- 此配置文件中的所有配置项,参见官方文档 [Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration)
- `home.nix`: 在 flake.nix 中被 home-manager 作为 ryan 用户的配置导入,也就是说它包含了 ryan 这个用户的所有 Home Manager 配置,负责管理其 Home 文件夹。
- 此配置文件的所有配置项,参见 [Appendix A. Configuration Options - Home Manager](https://nix-community.github.io/home-manager/options.xhtml)
- `configuration.nix`: 在 flake.nix 中被作为系统模块导入,目前所有系统级别的配置都写在此文
件中。
- 此配置文件中的所有配置项,参见官方文档
[Configuration - NixOS Manual](https://nixos.org/manual/nixos/unstable/index.html#ch-configuration)
- `home.nix`: 在 flake.nix 中被 home-manager 作为 ryan 用户的配置导入,也就是说它包含了
ryan 这个用户的所有 Home Manager 配置,负责管理其 Home 文件夹。
- 此配置文件的所有配置项,参见
[Appendix A. Configuration Options - Home Manager](https://nix-community.github.io/home-manager/options.xhtml)
通过修改上面几个配置文件就可以实现对系统与 Home 目录状态的修改。
但是随着配置的增多,单纯依靠 `configuration.nix``home.nix` 会导致配置文件臃肿,难以维护。
更好的解决方案是通过 Nix 的模块机制,将配置文件拆分成多个模块,分门别类地编写维护。
通过修改上面几个配置文件就可以实现对系统与 Home 目录状态的修改。但是随着配置的增多,单纯依
`configuration.nix``home.nix` 会导致配置文件臃肿,难以维护。更好的解决方案是通过
Nix 的模块机制,将配置文件拆分成多个模块,分门别类地编写维护。
在前面的 Nix 语法一节有介绍过:「`import` 的参数如果为文件夹路径,那么会返回该文件夹下的 `default.nix` 文件的执行结果」,实际 Nix 还提供了一个 `imports` 参数,它可以接受一个 `.nix` 文件列表,并将该列表中的所有配置**合并**Merge到当前的 attribute set 中。注意这里的用词是「合并」,它表明 `imports` 如果遇到重复的配置项,不会简单地按执行顺序互相覆盖,而是更合理地处理。比如说我在多个 modules 中都定义了 `program.packages = [...]`,那么 `imports` 会将所有 modules 中的 `program.packages` 这个 list 合并。不仅 list 能被正确合并attribute set 也能被正确合并,具体行为各位看官可以自行探索。
在前面的 Nix 语法一节有介绍过:「`import` 的参数如果为文件夹路径,那么会返回该文件夹下的
`default.nix` 文件的执行结果」,实际 Nix 还提供了一个 `imports` 参数,它可以接受一个
`.nix` 文件列表,并将该列表中的所有配置**合并**Merge到当前的 attribute set 中。注意这
里的用词是「合并」,它表明 `imports` 如果遇到重复的配置项,不会简单地按执行顺序互相覆盖,
而是更合理地处理。比如说我在多个 modules 中都定义了 `program.packages = [...]`,那么
`imports` 会将所有 modules 中的 `program.packages` 这个 list 合并。不仅 list 能被正确合
attribute set 也能被正确合并,具体行为各位看官可以自行探索。
> 我只在 [nixpkgs-unstable 官方手册 - evalModules parameters](https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules-parameters) 中找到一句关于 `imports` 的描述:`A list of modules. These are merged together to form the final configuration.`,可以意会一下...Nix 的文档真的一言难尽...这么核心的参数文档就这么一句...
> 我只在
> [nixpkgs-unstable 官方手册 - evalModules parameters](https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules-parameters)
> 中找到一句关于 `imports` 的描
> 述:`A list of modules. These are merged together to form the final configuration.`,可
> 以意会一下...Nix 的文档真的一言难尽...这么核心的参数文档就这么一句...
我们可以借助 `imports` 参数,将 `home.nix``configuration.nix` 拆分成多个 `.nix` 文件。
@ -34,7 +49,8 @@ $ tree
- [Misterio77/nix-starter-configs](https://github.com/Misterio77/nix-starter-configs)
再举个更复杂一点的例子,如下是我之前 i3wm 配置的目录结构 [ryan4yin/nix-config/i3-kickstarter](https://github.com/ryan4yin/nix-config/tree/i3-kickstarter)
再举个更复杂一点的例子,如下是我之前 i3wm 配置的目录结构
[ryan4yin/nix-config/i3-kickstarter](https://github.com/ryan4yin/nix-config/tree/i3-kickstarter)
```shell
├── flake.lock
@ -89,15 +105,20 @@ $ tree
└── wallpaper.jpg # 桌面壁纸,在 i3wm 配置中被引用
```
Nix Flakes 对目录结构没有任何要求,你可以参考上面的例子,摸索出适合你自己的目录结构。其中关键点就是通过 `imports` 参数导入其他 `.nix` 文件。
Nix Flakes 对目录结构没有任何要求,你可以参考上面的例子,摸索出适合你自己的目录结构。其中
关键点就是通过 `imports` 参数导入其他 `.nix` 文件。
## `lib.mkOverride`, `lib.mkDefault` and `lib.mkForce`
你可能会发现有些人在 Nix 文件中使用 `lib.mkDefault` `lib.mkForce` 来定义值,顾名思义,`lib.mkDefault` 和 `lib.mkForce` 用于设置选项的默认值,或者强制设置选项的值。
你可能会发现有些人在 Nix 文件中使用 `lib.mkDefault` `lib.mkForce` 来定义值,顾名思
义,`lib.mkDefault` 和 `lib.mkForce` 用于设置选项的默认值,或者强制设置选项的值。
直接这么说可能不太好理解,官方文档也没啥对这几个函数的详细解释,最直接的理解方法,是看源码。
直接这么说可能不太好理解,官方文档也没啥对这几个函数的详细解释,最直接的理解方法,是看源
码。
开个新窗口,输入命令 `nix repl -f '<nixpkgs>'` 进入 REPL 解释器,然后输入 `:e lib.mkDefault`,就可以看到 `lib.mkDefault` 的源码了(不太懂 `:e` 是干啥的?请直接输入 `:?` 查看帮助信息学习下)。
开个新窗口,输入命令 `nix repl -f '<nixpkgs>'` 进入 REPL 解释器,然后输入
`:e lib.mkDefault`,就可以看到 `lib.mkDefault` 的源码了(不太懂 `:e` 是干啥的?请直接输入
`:?` 查看帮助信息学习下)。
源码截取如下:
@ -118,15 +139,18 @@ Nix Flakes 对目录结构没有任何要求,你可以参考上面的例子,
# ......
```
所以 `lib.mkDefault` 就是用于设置选项的默认值,它的优先级是 1000`lib.mkForce` 则用于强制设置选项的值,它的优先级是 50。
如果你直接设置选项的值,那么它的优先级就是 1000`lib.mkDefault` 一样)。
所以 `lib.mkDefault` 就是用于设置选项的默认值,它的优先级是 1000`lib.mkForce` 则用于
强制设置选项的值,它的优先级是 50。如果你直接设置选项的值那么它的优先级就是 1000
`lib.mkDefault` 一样)。
`priority` 的值越低,它实际的优先级就越高,所以 `lib.mkForce` 的优先级比 `lib.mkDefault` 高。
而如果你定义了多个优先级相同的值Nix 会报错说存在参数冲突,需要你手动解决。
`priority` 的值越低,它实际的优先级就越高,所以 `lib.mkForce` 的优先级比 `lib.mkDefault`
高。而如果你定义了多个优先级相同的值Nix 会报错说存在参数冲突,需要你手动解决。
这几个函数在模块化 NixOS 配置中非常有用因为你可以在低层级的模块base module中设置默认值然后在高层级的模块high-level module中设置优先级更高的值。
这几个函数在模块化 NixOS 配置中非常有用因为你可以在低层级的模块base module中设置默认
然后在高层级的模块high-level module中设置优先级更高的值。
举个例子,我在这里定义了一个默认值:<https://github.com/ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-server.nix#L32>
举个例子,我在这里定义了一个默认
值:<https://github.com/ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-server.nix#L32>
```nix{6}
{ lib, pkgs, ... }:
@ -140,7 +164,8 @@ Nix Flakes 对目录结构没有任何要求,你可以参考上面的例子,
}
```
然后在桌面机器的配置中,我强制覆盖了默认值: <https://github.com/ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-desktop.nix#L18>
然后在桌面机器的配置中,我强制覆盖了默认值:
<https://github.com/ryan4yin/nix-config/blob/c515ea9/modules/nixos/core-desktop.nix#L18>
```nix{10}
{ lib, pkgs, ... }:
@ -160,15 +185,21 @@ Nix Flakes 对目录结构没有任何要求,你可以参考上面的例子,
## `lib.mkOrder`, `lib.mkBefore``lib.mkAfter`
`lib.mkBefore``lib.mkAfter` 用于设置**列表类型**的合并顺序,它们跟 `lib.mkDefault``lib.mkForce` 一样,也被用于模块化配置。
`lib.mkBefore``lib.mkAfter` 用于设置**列表类型**的合并顺序,它们跟 `lib.mkDefault`
`lib.mkForce` 一样,也被用于模块化配置。
> 列表类型的定义我没找到官方文档但我简单理解应该就是合并结果与合并先后顺序有关的类型。按这个理解list 跟 string 类型都是列表类型,实际测试这几个函数也确实能用在这两个类型上。
> 列表类型的定义我没找到官方文档,但我简单理解,应该就是合并结果与合并先后顺序有关的类型。
> 按这个理解list 跟 string 类型都是列表类型,实际测试这几个函数也确实能用在这两个类型
> 上。
前面说了如果你定义了多个优先级相同的值Nix 会报错说存在参数冲突,需要你手动解决。
但是如果你定义的是**列表类型**的值Nix 就不会报错了,因为 Nix 会把你定义的多个值合并成一个列表,而 `lib.mkBefore``lib.mkAfter` 就是用于设置这个列表的合并顺序的。
但是如果你定义的是**列表类型**的值Nix 就不会报错了,因为 Nix 会把你定义的多个值合并成一
个列表,而 `lib.mkBefore``lib.mkAfter` 就是用于设置这个列表的合并顺序的。
还是先来看看源码,开个终端键入 `nix repl -f '<nixpkgs>'` 进入 REPL 解释器,然后输入 `:e lib.mkBefore`,就可以看到 `lib.mkBefore` 的源码了(不太懂 `:e` 是干啥的?请直接输入 `:?` 查看帮助信息学习下)。
还是先来看看源码,开个终端键入 `nix repl -f '<nixpkgs>'` 进入 REPL 解释器,然后输入
`:e lib.mkBefore`,就可以看到 `lib.mkBefore` 的源码了(不太懂 `:e` 是干啥的?请直接输入
`:?` 查看帮助信息学习下)。
```nix
# ......
@ -185,7 +216,8 @@ Nix Flakes 对目录结构没有任何要求,你可以参考上面的例子,
# ......
```
能看到 `lib.mkBefore` 只是个 `lib.mkOrder 500` 的别名,而 `lib.mkAfter` 则是个 `lib.mkOrder 1500` 的别名。
能看到 `lib.mkBefore` 只是个 `lib.mkOrder 500` 的别名,而 `lib.mkAfter` 则是个
`lib.mkOrder 1500` 的别名。
为了更直观地理解这两个函数,现在来创建一个 flake 测试下:
@ -235,7 +267,8 @@ Nix Flakes 对目录结构没有任何要求,你可以参考上面的例子,
}
```
上面的例子包含了在多行字符串、单行字符串,以及列表三种类型上应用 `lib.mkBefore``lib.mkAfter`,下面测试下结果:
上面的例子包含了在多行字符串、单行字符串,以及列表三种类型上应用 `lib.mkBefore`
`lib.mkAfter`,下面测试下结果:
```bash
# 示例一:多行字符串合并
@ -269,7 +302,8 @@ echo 'insert after default';"
可以看到,`lib.mkBefore` 会将后面的值插入到前面,而 `lib.mkAfter` 会将后面的值插入到前面。
> 对模块系统更深入的介绍,参见 [模块系统与自定义 options](../other-usage-of-flakes/module-system.md).
> 对模块系统更深入的介绍,参见
> [模块系统与自定义 options](../other-usage-of-flakes/module-system.md).
## References

View file

@ -2,9 +2,11 @@
## 启用 NixOS 的 Flakes 支持 {#enable-nix-flakes}
与 NixOS 当前默认的配置方式相比Flakes 提供了更好的可复现性,同时它清晰的包结构定义原生支持了以其他 Git 仓库为依赖,便于代码分享,因此本书更建议使用 Flakes 来管理系统配置。
与 NixOS 当前默认的配置方式相比Flakes 提供了更好的可复现性,同时它清晰的包结构定义原生支
持了以其他 Git 仓库为依赖,便于代码分享,因此本书更建议使用 Flakes 来管理系统配置。
目前 Flakes 作为一个实验特性,仍未被默认启用,我们需要手动修改 `/etc/nixos/configuration.nix` 文件,启用 Flakes 特性以及配套的船新 nix 命令行工具:
目前 Flakes 作为一个实验特性,仍未被默认启用,我们需要手动修改
`/etc/nixos/configuration.nix` 文件,启用 Flakes 特性以及配套的船新 nix 命令行工具:
```nix{12,15}
{ config, pkgs, ... }:
@ -35,11 +37,13 @@
然后运行 `sudo nixos-rebuild switch` 应用修改后,即可使用 Flakes 特性来管理系统配置。
nix 的新命令行工具还提供了一些方便的功能,比如说你现在可以使用 `nix repl` 命令打开一个 nix 交互环境,有兴趣的话,可以使用它复习测试一遍前面学过的所有 Nix 语法。
nix 的新命令行工具还提供了一些方便的功能,比如说你现在可以使用 `nix repl` 命令打开一个 nix
交互环境,有兴趣的话,可以使用它复习测试一遍前面学过的所有 Nix 语法。
## 将系统配置切换到 flake.nix {#switch-to-flake-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 的编写,先查下有哪些模板:
@ -54,7 +58,8 @@ nix flake init -t templates#full
cat flake.nix
```
我们参照该模板创建文件 `/etc/nixos/flake.nix` 并编写好配置内容,后续系统的所有修改都将全部由 Nix Flakes 接管,示例内容如下:
我们参照该模板创建文件 `/etc/nixos/flake.nix` 并编写好配置内容,后续系统的所有修改都将全部
由 Nix Flakes 接管,示例内容如下:
```nix{16}
{
@ -79,34 +84,45 @@ cat flake.nix
}
```
这里我们定义了一个名为 `my-nixos` 的系统,它的配置文件为 `/etc/nixos/` 文件夹下的 `./configuration.nix`,也就是说我们仍然沿用了旧的配置。
这里我们定义了一个名为 `my-nixos` 的系统,它的配置文件为 `/etc/nixos/` 文件夹下的
`./configuration.nix`,也就是说我们仍然沿用了旧的配置。
现在执行 `sudo nixos-rebuild switch` 应用配置,系统应该没有任何变化,因为我们仅仅是切换到了 Nix Flakes配置内容与之前还是一致的。
现在执行 `sudo nixos-rebuild switch` 应用配置,系统应该没有任何变化,因为我们仅仅是切换到
了 Nix Flakes配置内容与之前还是一致的。
切换完毕后,我们就可以通过 Flakes 特性来管理系统了。
目前我们的 flake 包含这几个文件:
- `/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 生成,描述了系统的硬件信息
- `/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 生成,描述了系统
的硬件信息
到这里为止, `/etc/nixos/flake.nix` 仅仅是 `/etc/nixos/configuration.nix` 的一个 thin wrapper它自身并没有提供任何新的功能也没有引入任何破坏性的变更。
在本书后面的内容中,我们会逐渐看到这样一个 wrapper 带来了哪些好处。
到这里为止, `/etc/nixos/flake.nix` 仅仅是 `/etc/nixos/configuration.nix` 的一个 thin
wrapper它自身并没有提供任何新的功能也没有引入任何破坏性的变更。在本书后面的内容中
们会逐渐看到这样一个 wrapper 带来了哪些好处。
> 注意:**本书描述的配置管理方式并非「Everything in a single file」更推荐将配置内容分门别类地存放到不同的 nix 文件中**,然后在 `flake.nix``modules` 参数列表中引入这些配置文件,并通过 Git 管理它们。
> 这样做的好处是,可以更好地组织配置文件,提高配置的可维护性。后面的 [模块化 NixOS 配置](./modularize-the-configuration.md) 一节将会详细介绍如何模块化你的 NixOS 配置,[其他实用技巧 - 使用 Git 管理 NixOS 配置](./other-useful-tips.md) 将会介绍几种使用 Git 管理 NixOS 配置的最佳实践。
> 注意:**本书描述的配置管理方式并非「Everything in a single file」更推荐将配置内容分门
> 别类地存放到不同的 nix 文件中**,然后在 `flake.nix``modules` 参数列表中引入这些配置
> 文件,并通过 Git 管理它们。这样做的好处是,可以更好地组织配置文件,提高配置的可维护性。
> 后面的 [模块化 NixOS 配置](./modularize-the-configuration.md) 一节将会详细介绍如何模块化
> 你的 NixOS 配置,[其他实用技巧 - 使用 Git 管理 NixOS 配置](./other-useful-tips.md) 将会
> 介绍几种使用 Git 管理 NixOS 配置的最佳实践。
## `flake.nix` 配置详解 {#flake-nix-configuration-explained}
上面我们创建了一个 `flake.nix` 文件并通过它来管理系统配置,
但你对它的结构还是一头雾水,
下面我们来详细解释一下这个文件的内容。
上面我们创建了一个 `flake.nix` 文件并通过它来管理系统配置,但你对它的结构还是一头雾水,下
面我们来详细解释一下这个文件的内容。
### 1. flake inputs
首先看看其中的 `inputs` 属性,它是一个 attribute set其中定义了这个 flake 的所有依赖项,这些依赖项会在被拉取后,作为参数传递给 `outputs` 函数:
首先看看其中的 `inputs` 属性,它是一个 attribute set其中定义了这个 flake 的所有依赖项,
这些依赖项会在被拉取后,作为参数传递给 `outputs` 函数:
```nix{2-5,7}
{
@ -121,16 +137,21 @@ cat flake.nix
}
```
`inputs` 中的每一项依赖有许多类型与定义方式,可以是另一个 flake也可以是一个普通的 Git 仓库,又或者一个本地路径。
[Flakes 的其他玩法 - Flake 的 inputs](../other-usage-of-flakes/inputs.md) 中详细介绍了常见的依赖项类型与定义方式。
`inputs` 中的每一项依赖有许多类型与定义方式,可以是另一个 flake也可以是一个普通的 Git 仓
库,又或者一个本地路径。
[Flakes 的其他玩法 - Flake 的 inputs](../other-usage-of-flakes/inputs.md) 中详细介绍了常见
的依赖项类型与定义方式。
这里我们只定义了 `nixpkgs` 这一个依赖项,使用的是 flake 中最常见的引用方式,即 `github:owner/name/reference`,这里的 `reference` 可以是分支名、commit-id 或 tag。
这里我们只定义了 `nixpkgs` 这一个依赖项,使用的是 flake 中最常见的引用方式,即
`github:owner/name/reference`,这里的 `reference` 可以是分支名、commit-id 或 tag。
`nixpkgs``inputs` 中被定义后,就可以在后面的 `outputs` 函数的参数中使用此依赖项中的内容了,我们的示例中正是这么干的。
`nixpkgs``inputs` 中被定义后,就可以在后面的 `outputs` 函数的参数中使用此依赖项中的内
容了,我们的示例中正是这么干的。
### 2. flake outputs
再来看看 `outputs`,它是一个以 `inputs` 中的依赖项为参数的函数,函数的返回值是一个 attribute set这个返回的 attribute set 即为该 flake 的构建结果:
再来看看 `outputs`,它是一个以 `inputs` 中的依赖项为参数的函数,函数的返回值是一个
attribute set这个返回的 attribute set 即为该 flake 的构建结果:
```nix{10-18}
{
@ -154,13 +175,16 @@ cat flake.nix
}
```
flake 有很多的用途,也可以有很多不同类型的 outputs[Flake 的 outputs](../other-usage-of-flakes/outputs.md) 一节有更详细的介绍。
这里我们只用到了 `nixosConfigurations` 这一类型的 outputs它用于配置 NixOS 系统。
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 系统。
在我们运行 `sudo nixos-rebuild switch` 命令时,它会从 `/etc/nixos/flake.nix``outputs`
函数返回值中查找 `nixosConfigurations.my-nixos` (其中的 `my-nixos` 将会是你当前系统的
hostname这一属性并使用其中的定义来配置你的 NixOS 系统。
实际我们也可以自定义 flake 的位置与 NixOS 配置的名称,而不是使用默认值。
只需要在 `nixos-rebuild` 命令后面添加 `--flake` 参数即可,一个例子:
实际我们也可以自定义 flake 的位置与 NixOS 配置的名称,而不是使用默认值。只需要在
`nixos-rebuild` 命令后面添加 `--flake` 参数即可,一个例子:
```nix
sudo nixos-rebuild switch --flake /path/to/your/flake#your-hostname
@ -169,7 +193,8 @@ 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 为配置名称进行查找。
2. `#` 是一个分隔符,其后的 `your-hostname` 则是 NixOS 配置的名称。`nixos-rebuild` 默认会
以你当前系统的 hostname 为配置名称进行查找。
你甚至能直接引用一个远程的 GitHub 仓库作为你的 flake 来源,示例如下:
@ -181,14 +206,19 @@ sudo nixos-rebuild switch --flake github:owner/repo#your-hostname
**一个 Flake 可以依赖其他 Flakes从而使用它们提供的功能**。
默认情况下,一个 flake 会在其每个依赖项(即 `inputs` 中的每一项)的根目录下寻找 `flake.nix` 文件并**懒惰求值**lazy evaluation它们的 `outputs` 函数,接着将这些函数返回的 attribute sets 作为参数传递给它自身的 `outputs` 函数,这样我们就能在当前 flake 中使用它所依赖的其他 flakes 提供的功能了。
默认情况下,一个 flake 会在其每个依赖项(即 `inputs` 中的每一项)的根目录下寻找
`flake.nix` 文件并**懒惰求值**lazy evaluation它们的 `outputs` 函数,接着将这些函数返回
的 attribute sets 作为参数传递给它自身的 `outputs` 函数,这样我们就能在当前 flake 中使用它
所依赖的其他 flakes 提供的功能了。
更精确地说,对每个依赖项的 `outputs` 函数的求值都是懒惰lazy也就是说一个 flake 的 `outputs` 函数只有在被真正使用到的时候才会被求值,这样就能避免不必要的计算,从而提高效率。
更精确地说,对每个依赖项的 `outputs` 函数的求值都是懒惰lazy也就是说一个 flake 的
`outputs` 函数只有在被真正使用到的时候才会被求值,这样就能避免不必要的计算,从而提高效率。
上面的描述可能有点绕,我们还是结合本节中使用的 `flake.nix` 示例来看看这个过程。
我们的 `flake.nix` 声明了 `inputs.nixpkgs` 这个依赖项,因此
[nixpkgs/flake.nix] 会在我们执行 `sudo nixos-rebuild switch` 这个命令时被求值。
从 Nixpkgs 仓库的源码中能看到它的 flake outputs 定义中有返回 `lib` 这个属性,我们的例子中就使用了 `lib` 属性中的 `nixosSystem` 这个函数来配置我们的 NixOS 系统:
上面的描述可能有点绕,我们还是结合本节中使用的 `flake.nix` 示例来看看这个过程。我们的
`flake.nix` 声明了 `inputs.nixpkgs` 这个依赖项,因此 [nixpkgs/flake.nix] 会在我们执行
`sudo nixos-rebuild switch` 这个命令时被求值。从 Nixpkgs 仓库的源码中能看到它的 flake
outputs 定义中有返回 `lib` 这个属性,我们的例子中就使用了 `lib` 属性中的 `nixosSystem`
个函数来配置我们的 NixOS 系统:
```nix{8-13}
{
@ -208,29 +238,38 @@ sudo nixos-rebuild switch --flake github:owner/repo#your-hostname
}
```
`nixpkgs.lib.nixosSystem` 后面跟的 attribute set 就是该函数的参数,我们这里只设置了两个参数:
`nixpkgs.lib.nixosSystem` 后面跟的 attribute set 就是该函数的参数,我们这里只设置了两个参
数:
1. `system`: 这个很好懂,就是系统架构参数。
2. `modules`: 此函数是一个 modules 的列表NixOS 的实际系统配置都定义在这些 modules 中。
`/etc/nixos/configuration.nix` 这个配置文件本身就是一个 Nixpkgs Module因此可以直接将其添加到 `modules` 列表中使用。
`/etc/nixos/configuration.nix` 这个配置文件本身就是一个 Nixpkgs Module因此可以直接将其添
加到 `modules` 列表中使用。
新手阶段了解这些就足够了,探究 `nixpkgs.lib.nixosSystem` 函数的具体实现需要对 Nixpkgs 的模块系统有一定的了解。
读者可以在学习了 [模块化 NixOS 配置](./modularize-the-configuration.md) 一节后,再回过头来从 [nixpkgs/flake.nix] 中找到 `nixpkgs.lib.nixosSystem` 的定义,跟踪它的源码,研究其实现方式。
新手阶段了解这些就足够了,探究 `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) 一节中会详细介绍这套模块系统的工作方式,这里只介绍些基础知识。
> 在后面的 [模块化 NixOS 配置](./modularize-the-configuration.md) 一节中会详细介绍这套模块
> 系统的工作方式,这里只介绍些基础知识。
为什么 `/etc/nixos/configuration.nix` 这个配置文件会符合 Nixpkgs Module 定义,从而能直接在 `flake.nix` 中引用它呢?
可能会有读者觉得这有点出乎意料。
为什么 `/etc/nixos/configuration.nix` 这个配置文件会符合 Nixpkgs Module 定义,从而能直接在
`flake.nix` 中引用它呢?可能会有读者觉得这有点出乎意料。
这实际是因为 Nixpkgs 中包含了大量 NixOS 的实现源码,这些源码大都使用 Nix 语言编写。
为了编写维护如此多的 Nix 代码,并且使用户能灵活地自定义其 NixOS 系统的各项功能,就必须要有一套 Nix 代码的模块化系统。
这实际是因为 Nixpkgs 中包含了大量 NixOS 的实现源码,这些源码大都使用 Nix 语言编写。为了编
写维护如此多的 Nix 代码,并且使用户能灵活地自定义其 NixOS 系统的各项功能,就必须要有一套
Nix 代码的模块化系统。
这套 Nix 代码的模块系统的实现也同样在 Nixpkgs 仓库中,它主要被用于 NixOS 系统配置的模块化,但也有其他的应用,比如 nix-darwin 跟 home-manager 都大量使用了这套模块系统。
这套 Nix 代码的模块系统的实现也同样在 Nixpkgs 仓库中,它主要被用于 NixOS 系统配置的模块
化,但也有其他的应用,比如 nix-darwin 跟 home-manager 都大量使用了这套模块系统。
既然 NixOS 是基于这套模块系统构建的,那它的配置文件(包括 `/etc/nixos/configuration.nix`)是一个 Nixpkgs Module也就显得非常自然了。
既然 NixOS 是基于这套模块系统构建的,那它的配置文件(包括 `/etc/nixos/configuration.nix`
是一个Nixpkgs Module也就显得非常自然了。
在学习后面的内容之前,我们需要先简单了解下这套模块系统的工作方式。
@ -251,17 +290,23 @@ sudo nixos-rebuild switch --flake github:owner/repo#your-hostname
}
```
可以看到它的定义实际是一个 Nix 函数,该函数有 5 个**由模块系统自动生成、自动注入、无需额外声明的参数**
可以看到它的定义实际是一个 Nix 函数,该函数有 5 个**由模块系统自动生成、自动注入、无需额外
声明的参数**
1. `lib`: **nixpkgs 自带的函数库,提供了许多操作 Nix 表达式的实用函数**
- 详见 <https://nixos.org/manual/nixpkgs/stable/#id-1.4>
2. `config`: 包含了当前环境中所有 option 的值,在后面学习模块系统时会大量使用它
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` 中基本都能看到它
- 入门阶段可以认为它的默认值为 `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}
@ -276,20 +321,27 @@ Nixpkgs 的模块系统提供了两种方式来传递非默认参数:
1. `specialArgs`: NixOS Manual 跟 Nixpkgs Manual 中分别有与它有关的只言片语
- Nixpkgs Manual: [Module System - Nixpkgs]
- NixOS Manual: [nixpkgs/nixos-23.11/nixos/doc/manual/development/option-types.section.md#L237-L244]
- NixOS Manual:
[nixpkgs/nixos-23.11/nixos/doc/manual/development/option-types.section.md#L237-L244]
1. `_module.args`:
- NixOS Manual: [Appendix A. Configuration Options](https://nixos.org/manual/nixos/stable/options#opt-_module.args)
- NixOS Manual:
[Appendix A. Configuration Options](https://nixos.org/manual/nixos/stable/options#opt-_module.args)
- Source Code: [nixpkgs/nixos-23.11/lib/modules.nix - _module.args]
总之,`specialArgs` 与 `_module.args` 需要的值都是一个 attribute set它们的功能也相同是将其 attribute set 中的所有参数传递到所有子模块中。
这两者的区别在于:
总之,`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` 才行**。
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`
NixOS 社区比较推荐优先使用 `_module.args` 这个 options仅在无法使用 `_module.args` 时才改
`specialArgs`
假设你想将某个依赖项传递到子模块中使用,可以使用 `specialArgs` 参数将 `inputs` 传递到所有子模块中:
假设你想将某个依赖项传递到子模块中使用,可以使用 `specialArgs` 参数将 `inputs` 传递到所有
子模块中:
```nix{13}
{
@ -338,7 +390,9 @@ NixOS 社区比较推荐优先使用 `_module.args` 这个 options仅在无
}
```
选择上述两种方式之一修改你的配置,然后在 `/etc/nixos/configuration.nix` 中就可以使用 `inputs` 这个参数了,模块系统会自动匹配到 `specialArgs` 中定义的 `inputs`,并将其注入到所有需要该参数的子模块中:
选择上述两种方式之一修改你的配置,然后在 `/etc/nixos/configuration.nix` 中就可以使用
`inputs` 这个参数了,模块系统会自动匹配到 `specialArgs` 中定义的 `inputs`,并将其注入到所
有需要该参数的子模块中:
```nix{3}
# Nix 会通过名称匹配,
@ -355,11 +409,14 @@ NixOS 社区比较推荐优先使用 `_module.args` 这个 options仅在无
## 从其他 flake 来源安装系统软件 {#install-system-packages-from-other-flakes}
管系统最常见的需求就是装软件,我们在上一节已经见识过如何通过 `environment.systemPackages` 来安装 `pkgs` 中的包,这些包都来自官方的 nixpkgs 仓库。
管系统最常见的需求就是装软件,我们在上一节已经见识过如何通过 `environment.systemPackages`
来安装 `pkgs` 中的包,这些包都来自官方的 nixpkgs 仓库。
现在我们学习下如何安装其他 flake 来源的软件包,这比直接从 nixpkgs 安装要灵活很多,最主要的用途是安装 Nixpkgs 中还未添加或未更新的某软件的最新版本。
现在我们学习下如何安装其他 flake 来源的软件包,这比直接从 nixpkgs 安装要灵活很多,最主要的
用途是安装 Nixpkgs 中还未添加或未更新的某软件的最新版本。
以 [helix](https://github.com/helix-editor/helix) 编辑器为例,这里演示下如何直接编译安装 helix 的 master 分支。
以 [helix](https://github.com/helix-editor/helix) 编辑器为例,这里演示下如何直接编译安装
helix 的 master 分支。
首先在 `flake.nix` 中添加 helix 这个 inputs 数据源:
@ -407,30 +464,40 @@ NixOS 社区比较推荐优先使用 `_module.args` 这个 options仅在无
}
```
改好后再 `sudo nixos-rebuild switch` 部署,就能安装好 Helix 程序了。
这次部署用时会比以往长挺多,因为 Nix 会从源码编译整个 Helix 程序。
改好后再 `sudo nixos-rebuild switch` 部署,就能安装好 Helix 程序了。这次部署用时会比以往长
挺多,因为 Nix 会从源码编译整个 Helix 程序。
部署完毕后,可直接在终端使用 `hx` 命令测试验证。
另外,如果你只是想尝试一下 Helix 的最新版本,再决定要不要真正地将它安装到系统里,有更简单的办法,一行命令就行(但如前所述,源码编译会很费时间):
另外,如果你只是想尝试一下 Helix 的最新版本,再决定要不要真正地将它安装到系统里,有更简单
的办法,一行命令就行(但如前所述,源码编译会很费时间):
```bash
nix run github:helix-editor/helix/master
```
我们会在后面的 [新一代 Nix 命令行工具的使用](../other-usage-of-flakes/the-new-cli.md) 中详细介绍 `nix run` 的用法。
我们会在后面的 [新一代 Nix 命令行工具的使用](../other-usage-of-flakes/the-new-cli.md) 中详
细介绍 `nix run` 的用法。
## 使用其他 Flakes 包提供的功能
其实这才是 Flakes 最主要的功能,一个 Flake 可以依赖其他 Flakes从而使用它们提供的功能——就如同我们在写 TypeScript/Go/Rust 等程序时使用其他 Library 提供的功能一样。
其实这才是 Flakes 最主要的功能,一个 Flake 可以依赖其他 Flakes从而使用它们提供的功能——就
如同我们在写 TypeScript/Go/Rust 等程序时使用其他 Library 提供的功能一样。
上面使用 Helix 的官方 Flake 中提供的最新版本就是一个例子,其他更多的用例会在后面提到,这里引用几个后面会讲的例子:
上面使用 Helix 的官方 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 中的包。
- [Getting Started with Home Manager](./start-using-home-manager.md): 这里引入了社区的
Home-Manager 作为依赖项,从而能直接使用该 Flake 提供的功能。
- [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
[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

@ -2,7 +2,8 @@
## 查看详细错误信息
如果你在部署配置时遇到了任何错误,都可以尝试在 `nixos-rebuild` 命令后面添加 `--show-trace --print-build-logs --verbose` 参数来获取详细的错误信息。举例如下:
如果你在部署配置时遇到了任何错误,都可以尝试在 `nixos-rebuild` 命令后面添加
`--show-trace --print-build-logs --verbose` 参数来获取详细的错误信息。举例如下:
```bash
cd /etc/nixos
@ -14,22 +15,29 @@ sudo nixos-rebuild switch --flake .#myhost --show-trace -L -v
## 使用 Git 管理 NixOS 配置 {#git-manage-nixos-config}
NixOS 的配置文件是纯文本,因此跟普通的 dotfiles 一样可以使用 Git 管理,这样可以方便的回滚到历史版本,或者在多台机器上同步配置。
NixOS 的配置文件是纯文本,因此跟普通的 dotfiles 一样可以使用 Git 管理,这样可以方便的回滚
到历史版本,或者在多台机器上同步配置。
> 注意:使用 Git 后,所有未被 Git 跟踪的文件都会被 Nix 忽略,如果发现 Nix 报错说某某文件 not found或许是因为你没 `git add`
> 注意:使用 Git 后,所有未被 Git 跟踪的文件都会被 Nix 忽略,如果发现 Nix 报错说某某文件
> not found或许是因为你没 `git add`
另外一点是Nix Flakes 配置也不一定需要放在 `/etc/nixos` 目录下,可以放在任意目录下,只要在部署时指定正确的路径即可。
另外一点是Nix Flakes 配置也不一定需要放在 `/etc/nixos` 目录下,可以放在任意目录下,只要
在部署时指定正确的路径即可。
> 我们在前面第 3 小节的代码注释中有说明过,可以通过 `sudo nixos-rebuild switch --flake .#xxx``--flake` 参数指定 Flakes 配置的文件夹路径,并通过 `#` 后面的值来指定使用的 outputs 名称。
> 我们在前面第 3 小节的代码注释中有说明过,可以通过
> `sudo nixos-rebuild switch --flake .#xxx``--flake` 参数指定 Flakes 配置的文件夹路
> 径,并通过 `#` 后面的值来指定使用的 outputs 名称。
比如我的使用方式是将 Nix Flakes 配置放在 `~/nixos-config` 目录下,然后在 `/etc/nixos` 目录下创建一个软链接:
比如我的使用方式是将 Nix Flakes 配置放在 `~/nixos-config` 目录下,然后在 `/etc/nixos` 目录
下创建一个软链接:
```shell
sudo mv /etc/nixos /etc/nixos.bak # 备份原来的配置
sudo ln -s ~/nixos-config/ /etc/nixos
```
然后就可以在 `~/nixos-config` 目录下使用 Git 管理配置了,配置使用普通的用户级别权限即可,不要求 owner 为 root.
然后就可以在 `~/nixos-config` 目录下使用 Git 管理配置了,配置使用普通的用户级别权限即可,
不要求 owner 为 root.
另一种方法是直接删除掉 `/etc/nixos`,并在每次部署时指定配置文件路径:
@ -42,7 +50,8 @@ cd ~/nixos-config
sudo nixos-rebuild switch --flake .#my-nixos
```
两种方式都可以,看个人喜好。搞定之后,系统的回滚也变得非常简单,只需要切换到上一个 commit 即可:
两种方式都可以,看个人喜好。搞定之后,系统的回滚也变得非常简单,只需要切换到上一个 commit
即可:
```shell
cd ~/nixos-config
@ -52,11 +61,13 @@ git checkout HEAD^1
sudo nixos-rebuild switch --flake .#my-nixos
```
Git 的更多操作这里就不介绍了,总之一般情况下的回滚都能直接通过 Git 完成,只在系统完全崩溃的情况下,才需要通过重启进入 grub从上一个历史版本启动系统。
Git 的更多操作这里就不介绍了,总之一般情况下的回滚都能直接通过 Git 完成,只在系统完全崩溃
的情况下,才需要通过重启进入 grub从上一个历史版本启动系统。
## 查看与清理历史数据 {#view-and-delete-history}
如前所述NixOS 的每次部署都会生成一个新的版本,所有版本都会被添加到系统启动项中,除了重启电脑外,我们也可以通过如下命令查询当前可用的所有历史版本:
如前所述NixOS 的每次部署都会生成一个新的版本,所有版本都会被添加到系统启动项中,除了重启
电脑外,我们也可以通过如下命令查询当前可用的所有历史版本:
```shell
nix profile history --profile /nix/var/nix/profiles/system

View file

@ -1,8 +1,11 @@
# 安装使用 Home Manager
前面简单提过NixOS 自身的配置文件只能管理系统级别的配置,而用户级别的配置则需要使用 home-manager 来管理。
前面简单提过NixOS 自身的配置文件只能管理系统级别的配置,而用户级别的配置则需要使用
home-manager 来管理。
根据官方文档 [Home Manager Manual](https://nix-community.github.io/home-manager/index.xhtml),要将 home manager 作为 NixOS 模块安装,首先需要创建 `/etc/nixos/home.nix`,配置方法如下:
根据官方文档
[Home Manager Manual](https://nix-community.github.io/home-manager/index.xhtml),要将 home
manager 作为 NixOS 模块安装,首先需要创建 `/etc/nixos/home.nix`,配置方法如下:
```nix
{ config, pkgs, ... }:
@ -167,7 +170,8 @@
}
```
添加好 `/etc/nixos/home.nix` 后,还需要在 `/etc/nixos/flake.nix` 中导入该配置,它才能生效,可以使用如下命令,在当前文件夹中生成一个示例配置以供参考:
添加好 `/etc/nixos/home.nix` 后,还需要在 `/etc/nixos/flake.nix` 中导入该配置,它才能生
效,可以使用如下命令,在当前文件夹中生成一个示例配置以供参考:
```shell
nix flake new example -t github:nix-community/home-manager#nixos
@ -224,40 +228,55 @@ nix flake new example -t github:nix-community/home-manager#nixos
然后执行 `sudo nixos-rebuild switch` 应用配置,即可完成 home-manager 的安装。
> 如果你的系统 Hostname 不是 `my-nixos`,你需要在 `flake.nix` 中修改 `nixosConfigurations` 的名称,或者使用 `--flake /etc/nixos#my-nixos` 来指定配置名称。
> 如果你的系统 Hostname 不是 `my-nixos`,你需要在 `flake.nix` 中修改 `nixosConfigurations`
> 的名称,或者使用 `--flake /etc/nixos#my-nixos` 来指定配置名称。
安装完成后,所有用户级别的程序、配置,都可以通过 `/etc/nixos/home.nix` 管理,并且执行 `sudo nixos-rebuild switch` 时也会自动应用 home-manager 的配置。 **不需要手动运行 `home-manager switch` 这个命令**!
安装完成后,所有用户级别的程序、配置,都可以通过 `/etc/nixos/home.nix` 管理,并且执行
`sudo nixos-rebuild switch` 时也会自动应用 home-manager 的配置。 **不需要手动运行
`home-manager switch` 这个命令**!
`home.nix` 中 Home Manager 的配置项有这几种查找方式:
- [Home Manager - Appendix A. Configuration Options](https://nix-community.github.io/home-manager/options.xhtml): 一份包含了所有配置项的列表,建议在其中关键字搜索。
- [Home Manager Option Search](https://mipmip.github.io/home-manager-option-search/): 一个更方便的 option 搜索工具。
- [home-manager](https://github.com/nix-community/home-manager): 有些配置项在官方文档中没有列出,或者文档描述不够清晰,可以直接在这份 home-manager 的源码中搜索阅读对应的源码。
- [Home Manager - Appendix A. Configuration Options](https://nix-community.github.io/home-manager/options.xhtml):
一份包含了所有配置项的列表,建议在其中关键字搜索。
- [Home Manager Option Search](https://mipmip.github.io/home-manager-option-search/): 一
个更方便的 option 搜索工具。
- [home-manager](https://github.com/nix-community/home-manager): 有些配置项在官方文档中没
有列出,或者文档描述不够清晰,可以直接在这份 home-manager 的源码中搜索阅读对应的源码。
## Home Manager vs NixOS
有许多的软件包或者软件配置, 既可以使用 NixOS Module 配置(`configuration.nix`),也可以使用 Home Manager 配置(`home.nix`), 这带来一个选择难题:**将软件包或者配置文件写在 NixOS Module 里还是 Homa Manager 配置里面有何区别? 该如何决策?**
有许多的软件包或者软件配置, 既可以使用 NixOS Module 配置(`configuration.nix`),也可以使用
Home Manager 配置(`home.nix`), 这带来一个选择难题:**将软件包或者配置文件写在 NixOS Module
里还是 Homa Manager 配置里面有何区别? 该如何决策?**
首先看看区别, NixOS Module 中安装的软件包跟配置文件都是整个系统全局的, 全局的配置通常会被存放在 `/etc` 中, 系统全局安装的软件也在任何用户环境下都可使用。
首先看看区别, NixOS Module 中安装的软件包跟配置文件都是整个系统全局的, 全局的配置通常会被
存放在 `/etc` 中, 系统全局安装的软件也在任何用户环境下都可使用。
相对的,通过 Home Manager 安装的配置项将会被链接到对应用户的 Home 目录, 其安装的软件也仅在对应的用户环境下可用, 切换到其他用户后这些配置跟软件就都用不了了。
相对的,通过 Home Manager 安装的配置项将会被链接到对应用户的 Home 目录, 其安装的软件也仅在
对应的用户环境下可用, 切换到其他用户后这些配置跟软件就都用不了了。
根据这种特性, 一般的推荐用法是:
- NixOS Module: 安装系统的核心组件, 以及所有用户都需要用到的其他软件包或配置
- 比如说如果你希望某个软件包能在你切换到 root 用户时仍能正常使用, 或者使某个配置能在系统全局生效, 那就得用 NixOS Module 来安装它
- 比如说如果你希望某个软件包能在你切换到 root 用户时仍能正常使用, 或者使某个配置能在系统
全局生效, 那就得用 NixOS Module 来安装它
- Home Manager: 其他所有的配置与软件, 都建议用 Home Manager 来安装
这样做的好处是:
1. 系统层面安装的软件与后台服务常常以 root 特权用户的身份运行,尽量避免在系统层面安装不必要的软件,可以减少系统的安全风险。
1. Home Manager 的许多配置都可以在 NixOS, macOS 以及其他 Linux 发行版上通用,尽可能选用 Home Manager 来安装软件与配置系统,可以提高配置的可移植性。
1. 如果你需要多用户,通过 Home Manager 安装的软件与配置,可以更好地隔离不同用户的环境,避免不同用户之间的配置与软件版本冲突。
1. 系统层面安装的软件与后台服务常常以 root 特权用户的身份运行,尽量避免在系统层面安装不必
要的软件,可以减少系统的安全风险。
1. Home Manager 的许多配置都可以在 NixOS, macOS 以及其他 Linux 发行版上通用,尽可能选用
Home Manager 来安装软件与配置系统,可以提高配置的可移植性。
1. 如果你需要多用户,通过 Home Manager 安装的软件与配置,可以更好地隔离不同用户的环境,避
免不同用户之间的配置与软件版本冲突。
## 如何以特权身份使用 Home Manager 安装的软件包?
对这个问题,首先想到的一般都是直接切换到 `root` 用户, 可切换用户后,当前用户通过 `home.nix` 安装的软件包都将不可用。
让我们以 `kubectl` 为例(已通过 `home.nix` 预先安装好),来演示一下:
对这个问题,首先想到的一般都是直接切换到 `root` 用户, 可切换用户后,当前用户通过
`home.nix` 安装的软件包都将不可用。让我们以 `kubectl` 为例(已通过 `home.nix` 预先安装
好),来演示一下:
```sh
# 1. kubectl 当前可用
@ -286,7 +305,8 @@ Error: nu::shell::external_command
/home/ryan/nix-config> exit
```
但是,我们可以通过 `sudo` 命令,临时授予当前用户访问系统资源的特权,从而在不切换到 `root` 用户的情况下,使用 `home.nix` 安装的软件包:
但是,我们可以通过 `sudo` 命令,临时授予当前用户访问系统资源的特权,从而在不切换到 `root`
用户的情况下,使用 `home.nix` 安装的软件包:
```sh
sudo kubectl

View file

@ -1,6 +1,7 @@
# 更新系统 {#update-nixos-system}
在使用了 Nix Flakes 后,要更新系统也很简单,先更新 flake.lock 文件,然后部署即可。在配置文件夹中执行如下命令:
在使用了 Nix Flakes 后,要更新系统也很简单,先更新 flake.lock 文件,然后部署即可。在配置文
件夹中执行如下命令:
```shell
# 更新 flake.lock更新所有依赖项
@ -13,4 +14,5 @@ nix flake lock --update-input home-manager
sudo nixos-rebuild switch --flake .
```
另外有时候安装新的包,跑 `sudo nixos-rebuild switch` 时可能会遇到 sha256 不匹配的报错,也可以尝试通过 `nix flake update` 更新 flake.lock 来解决(原理暂时不太清楚)。
另外有时候安装新的包,跑 `sudo nixos-rebuild switch` 时可能会遇到 sha256 不匹配的报错,也
可以尝试通过 `nix flake update` 更新 flake.lock 来解决(原理暂时不太清楚)。

View file

@ -1,6 +1,7 @@
# pkgs.callPackage
`pkgs.callPackage` 被用于参数化构建 Nix 包,为了理解它的用处,我们首先考虑下不使用 `pkgs.callPackage` 的情况下,我们要如何定义一个 Nix 包(也就是 Derivation
`pkgs.callPackage` 被用于参数化构建 Nix 包,为了理解它的用处,我们首先考虑下不使用
`pkgs.callPackage` 的情况下,我们要如何定义一个 Nix 包(也就是 Derivation
## 1. 不使用 `pkgs.callPackage` 的情况
@ -23,12 +24,15 @@ nix-repl> pkgs.writeShellScriptBin "hello" '' echo "hello, xxx!" ''
«derivation /nix/store/zhgar12vfhbajbchj36vbbl3mg6762s8-hello.drv»
```
上面这个 Derivation 的定义很短,就一行,但 nixpkgs 中大部分的 Derivation 的定义都要比这复杂很多。
前面我们介绍并大量使用了 `import xxx.nix` 来从其他 Nix 文件中导入 Nix 表达式,我们可以在这里也使用这种方法来提升代码的可维护性:
上面这个 Derivation 的定义很短,就一行,但 nixpkgs 中大部分的 Derivation 的定义都要比这复
杂很多。前面我们介绍并大量使用了 `import xxx.nix` 来从其他 Nix 文件中导入 Nix 表达式,我们
可以在这里也使用这种方法来提升代码的可维护性:
1. 将上面这一行 Derivation 的定义存放到单独的文件 `hello.nix` 中。
1. 但 `hello.nix` 自身的上下文中不包含 `pkgs` 这个变量,所以需要修改下其内容,将 `pkgs` 作为参数传递给 `hello.nix`
1. 在需要使用这个 Derivation 的地方,使用 `import ./hello.nix pkgs` 来导入它并使用 `pkgs` 作为参数来执行其中定义的函数。
1. 但 `hello.nix` 自身的上下文中不包含 `pkgs` 这个变量,所以需要修改下其内容,将 `pkgs`
作为参数传递给 `hello.nix`
1. 在需要使用这个 Derivation 的地方,使用 `import ./hello.nix pkgs` 来导入它并使用 `pkgs`
作为参数来执行其中定义的函数。
仍然使用 `nix repl` 来验证一下,能看到它的执行结果仍然是一个 Derivation
@ -50,14 +54,18 @@ nix-repl> import ./hello.nix pkgs
## 2. 使用 `pkgs.callPackage` 的情况
在前面不使用 `pkgs.callPackage` 的例子中,我们直接将 `pkgs` 作为参数传到了 `hello.nix` 中,这样做的缺点有:
在前面不使用 `pkgs.callPackage` 的例子中,我们直接将 `pkgs` 作为参数传到了 `hello.nix`
中,这样做的缺点有:
1. `hello` 这个 derivation 的所有其他依赖项都只能从 `pkgs` 中获取,耦合度太高。
1. 比如说我们如果需要其他自定义依赖项,就必须修改 `pkgs` 或者修改 `hello.nix` 的内容,而这两个都很麻烦。
1. 在 `hello.nix` 变复杂的情况下,很难判断 `hello.nix` 到底依赖了 `pkgs` 中的哪些 Derivation很难分析 Derivation 之间的依赖关系。
1. 比如说我们如果需要其他自定义依赖项,就必须修改 `pkgs` 或者修改 `hello.nix` 的内容,
而这两个都很麻烦。
1. 在 `hello.nix` 变复杂的情况下,很难判断 `hello.nix` 到底依赖了 `pkgs` 中的哪些
Derivation很难分析 Derivation 之间的依赖关系。
`pkgs.callPackage` 作为一个参数化构建 Derivation 的工具函数,可解决上述两个问题。
首先看看源码中此函数的定义与注释 [nixpkgs/lib/customisation.nix#L101-L121](https://github.com/NixOS/nixpkgs/blob/fe138d3/lib/customisation.nix#L101-L121)
`pkgs.callPackage` 作为一个参数化构建 Derivation 的工具函数,可解决上述两个问题。首先看
看源码中此函数的定义与注释
[nixpkgs/lib/customisation.nix#L101-L121](https://github.com/NixOS/nixpkgs/blob/fe138d3/lib/customisation.nix#L101-L121)
```nix
/* Call the package function in the file `fn` with the required
@ -93,17 +101,25 @@ nix-repl> import ./hello.nix pkgs
# ...... 省略后面的内容 ......
```
简单的说,它的使用格式是 `pkgs.callPackage fn args`,其中 `fn` 是一个 nix 文件或者函数,`args` 是一个 attribute set它的工作流程是
简单的说,它的使用格式是 `pkgs.callPackage fn args`,其中 `fn` 是一个 nix 文件或者函
数,`args` 是一个 attribute set它的工作流程是
1. `pkgs.callPackage fn args` 会先判断 `fn` 是一个函数还是一个文件,如果是文件就先通过 `import xxx.nix` 导入其中定义的函数。
1. 第一步执行完毕得到的是一个函数,其参数通常会有 `lib`, `stdenv`, `fetchurl` 等参数,可能还会带有一些自定义参数。
2. 之后,`pkgs.callPackage fn args` 会将 `args``pkgs` 这个 attribute set 合并。如果存在冲突,`args` 中的参数会覆盖 `pkgs` 中的参数。
3. 再之后,`pkgs.callPackage fn args` 会从上一步得到的 attribute set 中提取出 `fn` 函数的参数,并使用它们来执行 `fn` 函数。
1. `pkgs.callPackage fn args` 会先判断 `fn` 是一个函数还是一个文件,如果是文件就先通过
`import xxx.nix` 导入其中定义的函数。
1. 第一步执行完毕得到的是一个函数,其参数通常会有 `lib`, `stdenv`, `fetchurl` 等参数,
可能还会带有一些自定义参数。
2. 之后,`pkgs.callPackage fn args` 会将 `args``pkgs` 这个 attribute set 合并。如果存
在冲突,`args` 中的参数会覆盖 `pkgs` 中的参数。
3. 再之后,`pkgs.callPackage fn args` 会从上一步得到的 attribute set 中提取出 `fn` 函数的
参数,并使用它们来执行 `fn` 函数。
4. 函数执行结果是一个 Derivation也就是一个 Nix 包。
那可以作为 `pkgs.callPackage` 参数的 nix 文件具体长啥样呢,可以去看看我们前面在 [Nixpkgs 高级用法 - 简介](./intro.md) 中举例过的 `hello.nix` `fcitx5-rime.nix` `vscode/with-extensions.nix` `firefox/common.nix`,它们都可以被 `pkgs.callPackage` 导入。
那可以作为 `pkgs.callPackage` 参数的 nix 文件具体长啥样呢,可以去看看我们前面在
[Nixpkgs 高级用法 - 简介](./intro.md) 中举例过的 `hello.nix` `fcitx5-rime.nix`
`vscode/with-extensions.nix` `firefox/common.nix`,它们都可以被 `pkgs.callPackage` 导入。
比如说我们自定义了一个 NixOS 内核配置 `kernel.nix`,并且将开发版名称与内核源码作为了可变更参数:
比如说我们自定义了一个 NixOS 内核配置 `kernel.nix`,并且将开发版名称与内核源码作为了可变更
参数:
```nix
{
@ -130,7 +146,8 @@ nix-repl> import ./hello.nix pkgs
})
```
那么就可以在任意 Nixpkgs Module 中使用 `pkgs.callPackage ./hello.nix {}` 来导入并使用它,并且替换它的任意参数。
那么就可以在任意 Nixpkgs Module 中使用 `pkgs.callPackage ./hello.nix {}` 来导入并使用它,
并且替换它的任意参数。
```nix
{ lib, pkgs, pkgsKernel, kernel-src, ... }:
@ -149,13 +166,18 @@ nix-repl> import ./hello.nix pkgs
}
```
就如上面所展示的,通过 `pkgs.callPackage` 我们可以给 `kernel.nix` 定义的函数传入不同的 `src``boardName`,来生成不同的内核包,这样就可以使用同一份 `kernel.nix` 来适配不同的内核源码与不同的开发板了。
就如上面所展示的,通过 `pkgs.callPackage` 我们可以给 `kernel.nix` 定义的函数传入不同的
`src``boardName`,来生成不同的内核包,这样就可以使用同一份 `kernel.nix` 来适配不同的内
核源码与不同的开发板了。
`pkgs.callPackage` 的优势在于:
1. Derivation 的定义被参数化,定义中的所有函数参数就是 Derivation 的所有依赖项,这样就可以很方便的分析 Derivation 之间的依赖关系。
2. Derivation 的所有依赖项与其他自定义参数都可以很方便地被替换(通过使用 `pkgs.callPackage` 的第二个参数Derivation 定义的可复用性大大提升。
3. 在实现了前两条功能的情况下,并未增加代码的复杂度,所有 `pkgs` 中的依赖项都可以被自动注入,不需要手动传递。
1. Derivation 的定义被参数化,定义中的所有函数参数就是 Derivation 的所有依赖项,这样就可以
很方便的分析 Derivation 之间的依赖关系。
2. Derivation 的所有依赖项与其他自定义参数都可以很方便地被替换(通过使用
`pkgs.callPackage` 的第二个参数Derivation 定义的可复用性大大提升。
3. 在实现了前两条功能的情况下,并未增加代码的复杂度,所有 `pkgs` 中的依赖项都可以被自动注
入,不需要手动传递。
因此我们总是推荐使用 `pkgs.callPackage` 来定义 Derivation。

View file

@ -1,13 +1,22 @@
# Nixpkgs 的高级用法 {#nixpkgs-advanced-usage}
callPackage、Overriding 与 Overlays 是在使用 Nix 时偶尔会用到的技术,它们都是用来自定义 Nix 包的构建方法的。
callPackage、Overriding 与 Overlays 是在使用 Nix 时偶尔会用到的技术,它们都是用来自定义
Nix 包的构建方法的。
我们知道许多程序都有大量构建参数需要配置,不同的用户会希望使用不同的构建参数,这时候就需要 Overriding 与 Overlays 来实现。我举几个我遇到过的例子:
我们知道许多程序都有大量构建参数需要配置,不同的用户会希望使用不同的构建参数,这时候就需要
Overriding 与 Overlays 来实现。我举几个我遇到过的例子:
1. [fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix): fcitx5-rime 的 `rimeDataPkgs` 默认使用 `rime-data` 包,但是也可以通过 override 来自定义该参数的值,以加载自定义的 rime 配置(比如加载小鹤音形输入法配置)。
2. [vscode/with-extensions.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/applications/editors/vscode/with-extensions.nix): vscode 的这个包也可以通过 override 来自定义 `vscodeExtensions` 参数的值来安装自定义插件。
1. [nix-vscode-extensions](https://github.com/nix-community/nix-vscode-extensions): 就是利用该参数实现的 vscode 插件管理
3. [firefox/common.nix](https://github.com/NixOS/nixpkgs/blob/416ffcd08f1f16211130cd9571f74322e98ecef6/pkgs/applications/networking/browsers/firefox/common.nix): firefox 同样有许多可自定义的参数
1. [fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix):
fcitx5-rime 的 `rimeDataPkgs` 默认使用 `rime-data` 包,但是也可以通过 override 来自定义
该参数的值,以加载自定义的 rime 配置(比如加载小鹤音形输入法配置)。
2. [vscode/with-extensions.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/applications/editors/vscode/with-extensions.nix):
vscode 的这个包也可以通过 override 来自定义 `vscodeExtensions` 参数的值来安装自定义插
件。
1. [nix-vscode-extensions](https://github.com/nix-community/nix-vscode-extensions): 就
是利用该参数实现的 vscode 插件管理
3. [firefox/common.nix](https://github.com/NixOS/nixpkgs/blob/416ffcd08f1f16211130cd9571f74322e98ecef6/pkgs/applications/networking/browsers/firefox/common.nix):
firefox 同样有许多可自定义的参数
4. 等等
总之如果需要自定义上述这类 Nix 包的构建参数,或者实施某些比较底层的修改,我们就得用到 callPackage、Overriding 与 Overlays 这些特性。
总之如果需要自定义上述这类 Nix 包的构建参数,或者实施某些比较底层的修改,我们就得用到
callPackage、Overriding 与 Overlays 这些特性。

View file

@ -1,12 +1,19 @@
# 多 nixpkgs 实例的妙用
我们在前面 [降级与升级软件包](../nixos-with-flakes/downgrade-or-upgrade-packages.md) 一节中见过,怎么通过 `import nixpkgs {...}` 这样的方法实例化多个不同的 nixpkgs 实例,再通过 `specialArgs` 在所有子模块中使用这些 nixpkgs 实例。
这种方法有很多的用途,常见的有:
我们在前面 [降级与升级软件包](../nixos-with-flakes/downgrade-or-upgrade-packages.md) 一节
中见过,怎么通过 `import nixpkgs {...}` 这样的方法实例化多个不同的 nixpkgs 实例,再通过
`specialArgs` 在所有子模块中使用这些 nixpkgs 实例。这种方法有很多的用途,常见的有:
1. 通过实例化 commit id 不同的 nixpkgs 实例,用于安装不同版本的软件包。前面的 [降级与升级软件包](../nixos-with-flakes/downgrade-or-upgrade-packages.md) 一节中就是这样使用的。
2. 如果希望使用 overlays但是又不想影响到默认的 nixpkgs 实例,可以通过实例化一个新的 nixpkgs 实例,然后在这个实例上使用 overlays。
- 上一节 Overlays 中提到的 `nixpkgs.overlays = [...];` 是直接修改全局的 nixpkgs 实例,如果你的 overlays 改了比较底层的包,可能会影响到其他模块。坏处之一是会导致大量的本地编译(因为二进制缓存失效了),二是被影响的包功能可能也会出问题。
3. 在跨系统架构的编译中,你可以通过实例化多个 nixpkgs 实例来在不同的地方分别选用 QEMU 模拟编译与交叉编译,或者添加不同的 gcc 编译参数。
1. 通过实例化 commit id 不同的 nixpkgs 实例,用于安装不同版本的软件包。前面的
[降级与升级软件包](../nixos-with-flakes/downgrade-or-upgrade-packages.md) 一节中就是这
样使用的。
2. 如果希望使用 overlays但是又不想影响到默认的 nixpkgs 实例,可以通过实例化一个新的
nixpkgs 实例,然后在这个实例上使用 overlays。
- 上一节 Overlays 中提到的 `nixpkgs.overlays = [...];` 是直接修改全局的 nixpkgs 实例,
如果你的 overlays 改了比较底层的包,可能会影响到其他模块。坏处之一是会导致大量的本地
编译(因为二进制缓存失效了),二是被影响的包功能可能也会出问题。
3. 在跨系统架构的编译中,你可以通过实例化多个 nixpkgs 实例来在不同的地方分别选用 QEMU 模拟
编译与交叉编译,或者添加不同的 gcc 编译参数。
总之,实例化多个 nixpkgs 实例是非常有用的。
@ -65,11 +72,15 @@
我们学习 Nix 语法时就学过:
> `import` 表达式以其他 Nix 文件的路径作为参数,返回该 Nix 文件的执行结果。
> `import` 的参数如果为文件夹路径,那么会返回该文件夹下的 `default.nix` 文件的执行结果。
> `import` 表达式以其他 Nix 文件的路径作为参数,返回该 Nix 文件的执行结果。 `import` 的参
> 数如果为文件夹路径,那么会返回该文件夹下的 `default.nix` 文件的执行结果。
`nixpkgs` 是一个 Git 仓库,它的根目录下刚好有一个 `default.nix` 文件,那么答案就呼之欲出了:`import nixpkgs` 就是返回 [nixpkgs/default.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/default.nix) 文件的执行结果。
从这个文件开始探索,就能找到 `import nixpkgs` 的实现代码是 [pkgs/top-level/impure.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/top-level/impure.nix),这里截取部分内容:
`nixpkgs` 是一个 Git 仓库,它的根目录下刚好有一个 `default.nix` 文件,那么答案就呼之欲出
了:`import nixpkgs` 就是返回
[nixpkgs/default.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/default.nix) 文件
的执行结果。从这个文件开始探索,就能找到 `import nixpkgs` 的实现代码是
[pkgs/top-level/impure.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/top-level/impure.nix)
这里截取部分内容:
```nix
# ... skip some lines
@ -110,11 +121,17 @@ import ./. (builtins.removeAttrs args [ "system" ] // {
})
```
因此 `import nixpkgs {...}` 实际就是调用了上面这个函数,后面的 attribute set 就是这个参数的参数。
因此 `import nixpkgs {...}` 实际就是调用了上面这个函数,后面的 attribute set 就是这个参数
的参数。
## 注意事项
在创建多 nixpkgs 实例的时候需要注意一些细节,这里列举一些常见的问题:
1. 根据 @fbewivpjsbsby 补充的文章 [1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347),在子模块或者子 flakes 中用 `import` 来定制 `nixpkgs` 不是一个好的习惯,因为每次 `import` 都会重新求值并产生一个新的 nixpkgs 实例,在配置越来越多时会导致构建时间变长、内存占用变大。所以这里改为了在 `flake.nix` 中创建所有 nixpkgs 实例。
2. 在混合使用 QEMU 模拟编译与交叉编译时,搞得不好可能会导致许多包被重复编译多次,要注意避免这种情况。
1. 根据 @fbewivpjsbsby 补充的文章
[1000 instances of nixpkgs](https://discourse.nixos.org/t/1000-instances-of-nixpkgs/17347)
在子模块或者子 flakes 中用 `import` 来定制 `nixpkgs` 不是一个好的习惯,因为每次
`import` 都会重新求值并产生一个新的 nixpkgs 实例,在配置越来越多时会导致构建时间变长、
内存占用变大。所以这里改为了在 `flake.nix` 中创建所有 nixpkgs 实例。
2. 在混合使用 QEMU 模拟编译与交叉编译时,搞得不好可能会导致许多包被重复编译多次,要注意避
免这种情况。

View file

@ -1,23 +1,30 @@
# Overlays
前面介绍的 `pkgs.xxx.override { ... }``pkgs.xxx.overrideAttrs (finalAttrs: previousAttrs: { ... });` 都不会修改 pkgs 实例中原有的 Derivation而是返回一个新的 Derivation因此它们只适合作为局部参数使用。
但如果你需要覆写的 Derivation 还被其他 Nix 包所依赖,那其他 Nix 包使用的仍然会是未被修改的 Derivation.
前面介绍的 `pkgs.xxx.override { ... }`
`pkgs.xxx.overrideAttrs (finalAttrs: previousAttrs: { ... });` 都不会修改 pkgs 实例中原有
的 Derivation而是返回一个新的 Derivation因此它们只适合作为局部参数使用。但如果你需要覆
写的 Derivation 还被其他 Nix 包所依赖,那其他 Nix 包使用的仍然会是未被修改的 Derivation.
为了解决这个问题Nix 提供了 overlays 这个功能。
简单的说Overlays 可以全局修改 pkgs 中的 Derivation.
为了解决这个问题Nix 提供了 overlays 这个功能。简单的说Overlays 可以全局修改 pkgs 中的
Derivation.
在传统的 Nix 环境中Nix 默认会自动使用 `~/.config/nixpkgs/overlays.nix` `~/.config/nixpkgs/overlays/*.nix` 这类路径下的所有 overlays 配置。
在传统的 Nix 环境中Nix 默认会自动使用 `~/.config/nixpkgs/overlays.nix`
`~/.config/nixpkgs/overlays/*.nix` 这类路径下的所有 overlays 配置。
但是在使用了 Flakes 特性后为了确保系统的可复现性Flake 不能依赖任何 Git 仓库之外的配置,所以这种旧的配置方式就不再适用了。
但是在使用了 Flakes 特性后为了确保系统的可复现性Flake 不能依赖任何 Git 仓库之外的配
置,所以这种旧的配置方式就不再适用了。
在使用 `flake.nix` 配置你的 NixOS 时Home Manager 与 NixOS 都提供了 `nixpkgs.overlays` 这个 option 来引入 overlays, 相关文档:
在使用 `flake.nix` 配置你的 NixOS 时Home Manager 与 NixOS 都提供了 `nixpkgs.overlays`
个 option 来引入 overlays, 相关文档:
- [home-manager docs - `nixpkgs.overlays`](https://nix-community.github.io/home-manager/options.xhtml#opt-nixpkgs.overlays)
- [nixpkgs source code - `nixpkgs.overlays`](https://github.com/NixOS/nixpkgs/blob/30d7dd7e7f2cba9c105a6906ae2c9ed419e02f17/nixos/modules/misc/nixpkgs.nix#L169)
举个例子,如下内容就是一个加载 Overlays 的 Module它既可以用做 Home Manager Module也可以用做 NixOS Module因为这俩定义完全是一致的
举个例子,如下内容就是一个加载 Overlays 的 Module它既可以用做 Home Manager Module也可
以用做 NixOS Module因为这俩定义完全是一致的
> 不过我使用发现Home Manager 毕竟是个外部组件,而且现在全都用的 unstable 分支,这导致 Home Manager Module 有时候会有点小毛病,因此更建议以 NixOS Module 的形式引入 overlays
> 不过我使用发现Home Manager 毕竟是个外部组件,而且现在全都用的 unstable 分支,这导致
> Home Manager Module 有时候会有点小毛病,因此更建议以 NixOS Module 的形式引入 overlays
```nix
# ./overlays/default.nix
@ -97,10 +104,13 @@
## 多个使用不同 overlays 的 Nixpkgs 实例
上面介绍的 `nixpkgs.overlays = [...];` 是直接修改全局的默认 nixpkgs 实例,如果你的 overlays 改了比较底层的包,可能会影响到其他模块。坏处之一是会导致大量的本地编译(因为二进制缓存失效了),二是被影响的包功能可能也会出问题。
上面介绍的 `nixpkgs.overlays = [...];` 是直接修改全局的默认 nixpkgs 实例,如果你的
overlays 改了比较底层的包,可能会影响到其他模块。坏处之一是会导致大量的本地编译(因为二进
制缓存失效了),二是被影响的包功能可能也会出问题。
如果你只是想在某个地方使用 overlays而不想影响到全局的 nixpkgs 实例,可以通过实例化多个 nixpkgs 实例来实现。
下一节 [多 nixpkgs 实例的妙用](./multiple-nixpkgs.md) 将会介绍如何做到这一点。
如果你只是想在某个地方使用 overlays而不想影响到全局的 nixpkgs 实例,可以通过实例化多个
nixpkgs 实例来实现。下一节 [多 nixpkgs 实例的妙用](./multiple-nixpkgs.md) 将会介绍如何做到
这一点。
## 参考

View file

@ -1,6 +1,7 @@
# Overriding
简单的说,所有 nixpkgs 中的 Nix 包都可以通过 `<pkg>.override {}` 来自定义某些构建参数,它返回一个使用了自定义参数的新 Derivation. 举个例子:
简单的说,所有 nixpkgs 中的 Nix 包都可以通过 `<pkg>.override {}` 来自定义某些构建参数,它
返回一个使用了自定义参数的新 Derivation. 举个例子:
```nix
pkgs.fcitx5-rime.override {rimeDataPkgs = [
@ -8,15 +9,20 @@ pkgs.fcitx5-rime.override {rimeDataPkgs = [
];}
```
上面这个 Nix 表达式的执行结果就是一个新的 Derivation它的 `rimeDataPkgs` 参数被覆盖为 `[./rime-data-flypy]`,而其他参数则沿用原来的值。
上面这个 Nix 表达式的执行结果就是一个新的 Derivation它的 `rimeDataPkgs` 参数被覆盖为
`[./rime-data-flypy]`,而其他参数则沿用原来的值。
如何知道 `fcitx5-rime` 这个包有哪些参数可以覆写呢?有几种方法:
1. 直接在 GitHub 的 nixpkgs 源码中找:[fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix)
1. 注意要选择正确的分支,加入你用的是 nixos-unstable 分支,那就要在 nixos-unstable 分支中找。
2. 通过 `nix repl` 交互式查看:`nix repl -f '<nixpkgs>'`,然后输入 `:e pkgs.fcitx5-rime`,会通过编辑器打开这个包的源码,然后就可以看到这个包的所有参数了。
1. 直接在 GitHub 的 nixpkgs 源码中
找:[fcitx5-rime.nix](https://github.com/NixOS/nixpkgs/blob/e4246ae1e7f78b7087dce9c9da10d28d3725025f/pkgs/tools/inputmethods/fcitx5/fcitx5-rime.nix)
1. 注意要选择正确的分支,加入你用的是 nixos-unstable 分支,那就要在 nixos-unstable 分支
中找。
2. 通过 `nix repl` 交互式查看:`nix repl -f '<nixpkgs>'`,然后输入 `:e pkgs.fcitx5-rime`
会通过编辑器打开这个包的源码,然后就可以看到这个包的所有参数了。
通过上述两种方法,都可以看到 `fcitx5-rime` 这个包拥有如下输入参数,它们都是可以通过 `override` 修改的:
通过上述两种方法,都可以看到 `fcitx5-rime` 这个包拥有如下输入参数,它们都是可以通过
`override` 修改的:
```nix
{ lib, stdenv
@ -37,8 +43,10 @@ stdenv.mkDerivation rec {
}
```
除了覆写参数,还可以通过 `overrideAttrs` 来覆写使用 `stdenv.mkDerivation` 构建的 Derivation 的属性。
以 [pkgs.hello](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/applications/misc/hello/default.nix) 为例,首先通过前述方法查看这个包的源码:
除了覆写参数,还可以通过 `overrideAttrs` 来覆写使用 `stdenv.mkDerivation` 构建的
Derivation 的属性。以
[pkgs.hello](https://github.com/NixOS/nixpkgs/blob/nixos-23.05/pkgs/applications/misc/hello/default.nix)
为例,首先通过前述方法查看这个包的源码:
```nix
{ callPackage
@ -73,9 +81,11 @@ helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
});
```
上面这个例子中,`doCheck` 就是一个新的 Derivation它的 `doCheck` 参数被改写为 `false`,而其他参数则沿用原来的值。
上面这个例子中,`doCheck` 就是一个新的 Derivation它的 `doCheck` 参数被改写为 `false`,而
其他参数则沿用原来的值。
除了包源码中自定义的参数值外,我们也可以通过 `overrideAttrs` 直接改写 `stdenv.mkDerivation` 内部的默认参数,比如:
除了包源码中自定义的参数值外,我们也可以通过 `overrideAttrs` 直接改写
`stdenv.mkDerivation` 内部的默认参数,比如:
```nix
helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
@ -83,7 +93,8 @@ helloWithDebug = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: {
});
```
具体的内部参数可以通过 `nix repl -f '<nixpkgs>'` 然后输入 `:e stdenv.mkDerivation` 来查看其源码。
具体的内部参数可以通过 `nix repl -f '<nixpkgs>'` 然后输入 `:e stdenv.mkDerivation` 来查看
其源码。
## 参考

View file

@ -1,6 +1,7 @@
# Flake 的 inputs {#flake-inputs}
`flake.nix` 中的 `inputs` 是一个 attribute set用来指定当前 Flake 的依赖inputs 有很多种类型,举例如下:
`flake.nix` 中的 `inputs` 是一个 attribute set用来指定当前 Flake 的依赖inputs 有很多种
类型,举例如下:
```nix
{

View file

@ -1,3 +1,4 @@
# Nix Flakes 的其他玩法 {#nix-flakes-usage}
到这里我们已经写了不少 Nix Flakes 配置来管理 NixOS 系统了,这里再简单介绍下 Nix Flakes 更细节的内容,以及常用的 nix flake 命令。
到这里我们已经写了不少 Nix Flakes 配置来管理 NixOS 系统了,这里再简单介绍下 Nix Flakes 更
细节的内容,以及常用的 nix flake 命令。

View file

@ -1,34 +1,45 @@
# 模块系统与自定义 options {#module-system}
我们在前面的 NixOS 配置中通过设置各种 `options` 的值来配置 NixOS 或者 Home Manager这些 `options` 实际都在这两个位置定义:
我们在前面的 NixOS 配置中通过设置各种 `options` 的值来配置 NixOS 或者 Home Manager这些
`options` 实际都在这两个位置定义:
- NixOS: [nixpkgs/nixos/modules](https://github.com/NixOS/nixpkgs/tree/23.11/nixos/modules), 我们在 <https://search.nixos.org/options> 中能看到的所有 NixOS options 都是在这里定义的。
- Home Manager: [home-manager/modules](https://github.com/nix-community/home-manager/blob/release-23.11/modules): 可在 <https://nix-community.github.io/home-manager/options.xhtml> 中找到其所有的 options.
- NixOS:
[nixpkgs/nixos/modules](https://github.com/NixOS/nixpkgs/tree/23.11/nixos/modules), 我们
<https://search.nixos.org/options> 中能看到的所有 NixOS options 都是在这里定义的。
- Home Manager:
[home-manager/modules](https://github.com/nix-community/home-manager/blob/release-23.11/modules):
可在 <https://nix-community.github.io/home-manager/options.xhtml> 中找到其所有的options.
> 如果你还使用 nix-darwin那么它的配置也是类似的其模块系统的实现位于 [nix-darwin/modules](https://github.com/LnL7/nix-darwin/tree/master/modules)
> 如果你还使用 nix-darwin那么它的配置也是类似的其模块系统的实现位于
> [nix-darwin/modules](https://github.com/LnL7/nix-darwin/tree/master/modules)
而上述 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]
因为 Nixpkgs 的模块系统文档没人写,文档中直接建议读另一份专门针对 NixOS 模块系统的编写指南,确实写得清晰一些,但也很难说它对新手有多友好:
因为 Nixpkgs 的模块系统文档没人写,文档中直接建议读另一份专门针对 NixOS 模块系统的编写指
南,确实写得清晰一些,但也很难说它对新手有多友好:
- [Writing NixOS Modules - Nixpkgs]
总之,模块系统是由 Nixpkgs 实现的,并不是 Nix 包管理器的一部分,因此它的文档也不在 Nix 包管理器的文档中。
另外 NixOS 与 Home Manager 都是基于 Nixpkgs 的模块系统实现的。
总之,模块系统是由 Nixpkgs 实现的,并不是 Nix 包管理器的一部分,因此它的文档也不在 Nix 包
管理器的文档中。另外 NixOS 与 Home Manager 都是基于 Nixpkgs 的模块系统实现的。
## 模块系统有什么用? {#what-is-module-system}
我们作为一个普通用户,使用 NixOS 与 Home Manager 基于模块系统实现的各种 options 就已经能满足我们大部分的需求了。
那么深入学习模块系统对于我们来说,还有什么好处呢?
我们作为一个普通用户,使用 NixOS 与 Home Manager 基于模块系统实现的各种 options 就已经能满
足我们大部分的需求了。那么深入学习模块系统对于我们来说,还有什么好处呢?
我们在前面介绍配置的模块化时,提到了核心点是将配置拆分为多个模块,再通过 `imports = [ ... ];` 来导入这些模块。这其实就是模块系统最基础的用法。
但仅仅使用 `imports = [ ... ];`,我们只能将模块中定义的配置原封不动地导入到当前模块中,无法对其做任何定制,灵活性很差。
在配置简单的情况下,这种方式已经足够了,但如果我们的配置比较复杂,那么这种方式就显得力不从心了。
我们在前面介绍配置的模块化时,提到了核心点是将配置拆分为多个模块,再通过
`imports = [ ... ];` 来导入这些模块。这其实就是模块系统最基础的用法。但仅仅使用
`imports = [ ... ];`,我们只能将模块中定义的配置原封不动地导入到当前模块中,无法对其做任何
定制,灵活性很差。在配置简单的情况下,这种方式已经足够了,但如果我们的配置比较复杂,那么这
种方式就显得力不从心了。
这里举个例子来说明其弊端,
譬如说我通过一份配置管理了 A、B、C 跟 D 共 4 台 NixOS 主机,我希望能在尽量减少配置重复的前提下实现如下功能:
这里举个例子来说明其弊端,譬如说我通过一份配置管理了 A、B、C 跟 D 共 4 台 NixOS 主机,我希
望能在尽量减少配置重复的前提下实现如下功能:
- A、B、C 跟 D 都需要启用 docker 服务,设置开机自启
- A 需要将 docker 的存储驱动改为 `btrfs`,其他不变
@ -36,7 +47,8 @@
- C 是位于美国的服务器,无特殊要求
- D 是桌面主机,需要为 docker 设置 HTTP 代理加速下载
如果单纯使用 `imports`,那么我们可能得将配置拆分成如下几个模块,然后在每台主机上导入不同的模块:
如果单纯使用 `imports`,那么我们可能得将配置拆分成如下几个模块,然后在每台主机上导入不同的
模块:
```bash
tree
@ -47,12 +59,15 @@
└── docker-proxy.nix # 导入了 docker-default.nix设置 HTTP 代理
```
是否感觉到这样的配置很冗余?这还是一个简单的例子,如果我们的机器更多,不同机器的配置差异更大,那么这种配置的冗余性就会更加明显。
是否感觉到这样的配置很冗余?这还是一个简单的例子,如果我们的机器更多,不同机器的配置差异更
大,那么这种配置的冗余性就会更加明显。
显然,我们需要借助其他的手段来解决这个配置冗余的问题,自定义一些我们自己的 `options` 就是一个很不错的选择。
显然,我们需要借助其他的手段来解决这个配置冗余的问题,自定义一些我们自己的 `options` 就是
一个很不错的选择。
在深入学习模块系统之前,我再强调一下,如下内容不是必须学习与使用的,有很多 NixOS 用户并未自定义任何 `options`,只是简单地使用 `imports` 就能满足他们的需求了。
如果你是新手,可以考虑在遇到类似上面这种,`imports` 解决不了的问题时再来学习这部分内容,这是完全 OK 的。
在深入学习模块系统之前,我再强调一下,如下内容不是必须学习与使用的,有很多 NixOS 用户并未
自定义任何 `options`,只是简单地使用 `imports` 就能满足他们的需求了。如果你是新手,可以考
虑在遇到类似上面这种,`imports` 解决不了的问题时再来学习这部分内容,这是完全 OK 的。
## 基本结构与用法 {#basic-structure-and-usage}
@ -76,12 +91,14 @@ Nixpkgs 中定义的模块,其基本结构如下:
}
```
其中的 `imports = [ ... ];` 我们已经很熟悉了,但另外两个部分,我们还没有接触过,这里简单介绍下:
其中的 `imports = [ ... ];` 我们已经很熟悉了,但另外两个部分,我们还没有接触过,这里简单介
绍下:
- `options = { ... };`: 它类似编程语言中的变量声明,用于声明一些可配置的选项。
- `config = { ... };`: 它类似编程语言中的变量赋值,用于为 `options` 中声明的选项赋值。
最典型的用法是:在同一 Nixpkgs 模块中,依据 `options = { ... };` 中声明的 `options` 当前的值,在 `config = { .. };` 中为其他的 `options` 赋值,这样就实现了参数化配置的功能。
最典型的用法是:在同一 Nixpkgs 模块中,依据 `options = { ... };` 中声明的 `options` 当前的
值,在 `config = { .. };` 中为其他的 `options` 赋值,这样就实现了参数化配置的功能。
直接看个例子更容易理解:
@ -132,7 +149,8 @@ in {
上面这个模块定义了三个 `options`
- `programs.foo.enable`: 用于控制是否启用此模块
- `programs.foo.package`: 用于自定义 foo 这个包,比如说使用不同版本、设置不同编译参数等等。
- `programs.foo.package`: 用于自定义 foo 这个包,比如说使用不同版本、设置不同编译参数等
等。
- `programs.foo.extraConfig`: 用于自定义 foo 的配置文件。
然后在 `config` 中,根据 `options` 中声明的这三个变量的值,做了不同的设置:
@ -143,7 +161,8 @@ in {
- 将 `programs.foo.package` 添加到 `home.packages` 中,以将其安装到用户环境中。
- 将 `programs.foo.extraConfig` 的值写入到 `~/.config/foo/foorc` 中。
这样,我们就可以在另一个 nix 文件中导入这个模块,并通过设置这里定义的 `options` 来实现对 foo 的自定义配置了,示例:
这样,我们就可以在另一个 nix 文件中导入这个模块,并通过设置这里定义的 `options` 来实现对
foo 的自定义配置了,示例:
```nix
# ./bar.nix
@ -164,7 +183,9 @@ in {
}
```
上面这个例子中我们为 `options` 赋值的方式实际上是一种**缩写**,当一个模块中只声明了 `options`,而没有声明 `config` (以及其他模块系统的特殊参数)时,我们可以省略掉 `config` 前缀,直接使用 `options` 的名称进行赋值。
上面这个例子中我们为 `options` 赋值的方式实际上是一种**缩写**,当一个模块中只声明了
`options`,而没有声明 `config` (以及其他模块系统的特殊参数)时,我们可以省略掉 `config`
前缀,直接使用 `options` 的名称进行赋值。
## 模块系统的赋值与延迟求值 {#module-system-assignment-and-lazy-evaluation}
@ -208,16 +229,18 @@ in {
}
```
上述配置中的示例 1、2、3 中,`config.warnings` 的值都依赖于 `config.foo` 的值,但它们的实现方式却不同。
将上述配置保存为 `flake.nix`,然后使用命令 `nix eval .#nixosConfigurations.test.config.warnings` 分别测试示例 1、2、3
可以发现示例 1、3 都能正常工作,而示例 2 则会报错 `error: infinite recursion encountered`
上述配置中的示例 1、2、3 中,`config.warnings` 的值都依赖于 `config.foo` 的值,但它们的实
现方式却不同。将上述配置保存为 `flake.nix`,然后使用命令
`nix eval .#nixosConfigurations.test.config.warnings` 分别测试示例 1、2、3可以发现示例
1、3 都能正常工作,而示例 2 则会报错 `error: infinite recursion encountered`
下面分别解释说明下:
1. 示例一计算流程:`config.warnings` => `config.foo` => `config`
1. 首先Nix 尝试计算 `config.warnings` 的值,但发现它依赖于 `config.foo`.
2. 接着Nix 尝试计算 `config.foo` 的值,它依赖于其外层的 `config`.
3. Nix 尝试计算 `config` 的值,`config` 中未被 `config.foo` 真正使用的内容都会被 Nix 延迟求值,因此这里不会递归依赖 `config.warnings`
3. Nix 尝试计算 `config` 的值,`config` 中未被 `config.foo` 真正使用的内容都会被 Nix 延
迟求值,因此这里不会递归依赖 `config.warnings`
4. `config.foo` 求值结束,接着 `config.warnings` 被赋值,计算结束。
2. 示例二:`config` => `config.foo` => `config`
1. 首先Nix 尝试计算 `config` 的值,但发现它依赖于 `config.foo`.
@ -225,18 +248,24 @@ in {
3. Nix 尝试计算 `config` 的值,这又跳转到步骤 1于是进入无限递归最终报错。
3. 示例三:跟示例二唯一的区别是改用了 `lib.mkIf` 解决了无限递归问题。
其关键就在于 `lib.mkIf` 这个函数,使用它定义的 `config` 会被 Nix 延迟求值,也就是说会在 `config.foo` 求值结束后,才会真正计算 `config = lib.mkIf ...` 的值。
其关键就在于 `lib.mkIf` 这个函数,使用它定义的 `config` 会被 Nix 延迟求值,也就是说会在
`config.foo` 求值结束后,才会真正计算 `config = lib.mkIf ...` 的值。
Nixpkgs 中的模块系统提供了一系列类似 `lib.mkIf` 的函数,用于实现参数化配置与智能的模块合并:
Nixpkgs 中的模块系统提供了一系列类似 `lib.mkIf` 的函数,用于实现参数化配置与智能的模块合
并:
1. `lib.mkIf`: 上面已经介绍过了。
1. `lib.mkOverride` / `lib.mkdDefault` / `lib.mkForce`: 在前面 [模块化 NixOS 配置](../nixos-with-flakes/modularize-the-configuration.md) 中已经介绍过了。
1. `lib.mkOverride` / `lib.mkdDefault` / `lib.mkForce`: 在前面
[模块化 NixOS 配置](../nixos-with-flakes/modularize-the-configuration.md) 中已经介绍过
了。
1. `lib.mkOrder`, `lib.mkBefore``lib.mkAfter`: 同上
1. 查看 [Option Definitions - NixOS][Option Definitions - NixOS] 了解更多与 options 赋值definition相关的函数。
1. 查看 [Option Definitions - NixOS][Option Definitions - NixOS] 了解更多与 options 赋值
definition相关的函数。
## Options 声明与类型检查 {#option-declarations-and-type-checking}
模块系统的赋值是我们最常用的功能,而如果我们需要自定义一些 `options`,还需要深入了解下 options 的声明与类型检查。
模块系统的赋值是我们最常用的功能,而如果我们需要自定义一些 `options`,还需要深入了解下
options 的声明与类型检查。
这个我觉得就还挺简单的,比赋值要简单挺多了,直接看官方文档就能懂个大概,这里就不再赘述了:
@ -245,12 +274,15 @@ Nixpkgs 中的模块系统提供了一系列类似 `lib.mkIf` 的函数,用于
## 传递非默认参数到模块系统中 {#pass-non-default-parameters-to-the-module-system}
我们在 [使用 Flakes 来管理你的 NixOS](../nixos-with-flakes/nixos-with-flakes-enabled.md#pass-non-default-parameters-to-submodules) 中已经介绍了如何使用 `specialArgs``_module.args` 来传递额外的参数给其他 Modules 函数,这里不再赘述。
我们在
[使用 Flakes 来管理你的 NixOS](../nixos-with-flakes/nixos-with-flakes-enabled.md#pass-non-default-parameters-to-submodules)
中已经介绍了如何使用 `specialArgs``_module.args` 来传递额外的参数给其他 Modules 函数,
这里不再赘述。
## 如何选择性地导入模块 {#selectively-import-modules}
在上面的例子中,我们已经介绍了如何通过自定义的 options 来决定是否启用某个功能,
但我们的代码实现都是在同一个 nix 文件中的,那么如果我们的模块是分散在不同的文件中的,该如何实现呢?
在上面的例子中,我们已经介绍了如何通过自定义的 options 来决定是否启用某个功能,但我们的代
码实现都是在同一个 nix 文件中的,那么如果我们的模块是分散在不同的文件中的,该如何实现呢?
我们先来看看一些常见的错误用法,然后再来介绍正确的使用方式。
@ -293,23 +325,28 @@ Nixpkgs 中的模块系统提供了一系列类似 `lib.mkIf` 的函数,用于
}
```
但这样是行不通的。
你可以尝试使用上述 `flake.nix` 运行 `nix eval .#nixosConfigurations.test.config.warnings`,会遇到报错 `error: The option 'imports' does not exist.`
但这样是行不通的。你可以尝试使用上述 `flake.nix` 运行
`nix eval .#nixosConfigurations.test.config.warnings`,会遇到报错
`error: The option 'imports' does not exist.`
这是因为 `config` 是一个普通的 attribute set`imports` 是模块系统的特殊参数。
并不存在 `config.imports` 这样的 options 定义。
这是因为 `config` 是一个普通的 attribute set`imports` 是模块系统的特殊参数。并不存在
`config.imports` 这样的 options 定义。
### 正确用法一 - 为所有需要条件导入的模块定义各自的 `options` {#correct-usage-1}
这是最推荐的方式。NixOS 系统中的模块都是这样实现的,在 <https://search.nixos.org/options> 中搜索 `enable` 能看到非常多的可通过 `enable` option 启用或关闭的系统模块。
这是最推荐的方式。NixOS 系统中的模块都是这样实现的,在 <https://search.nixos.org/options>
中搜索 `enable` 能看到非常多的可通过 `enable` option 启用或关闭的系统模块。
具体的写法已经在前面的 [基本结构与用法](#basic-structure-and-usage) 中介绍过了,这里不再赘述。
具体的写法已经在前面的 [基本结构与用法](#basic-structure-and-usage) 中介绍过了,这里不再赘
述。
它的缺点是,所有需要条件导入的 Nix 模块都要做改造,把其中的配置声明全部移到 `config = { ...};` 代码块中,代码复杂度会增加,同时也对新手不太友好。
它的缺点是,所有需要条件导入的 Nix 模块都要做改造,把其中的配置声明全部移到
`config = { ...};` 代码块中,代码复杂度会增加,同时也对新手不太友好。
### 正确用法二 - 在 `imports = [];` 中使用 `lib.optionals` {#correct-usage-2}
这种方式的主要好处是,它要比前面介绍的方法简单许多,不需要对模块内容做任何修改,只需要在 `imports` 中使用 `lib.optionals` 来决定是否导入某个模块即可。
这种方式的主要好处是,它要比前面介绍的方法简单许多,不需要对模块内容做任何修改,只需要在
`imports` 中使用 `lib.optionals` 来决定是否导入某个模块即可。
> `lib.optionals` 函数的详细文档: <https://noogle.dev/f/lib/optionals>
@ -347,14 +384,18 @@ Nixpkgs 中的模块系统提供了一系列类似 `lib.mkIf` 的函数,用于
{ warnings = ["foo"];}
```
将上述两个 nix 文件保存到一个文件夹中,然后在文件夹中运行 `nix eval .#nixosConfigurations.test.config.warnings`,运行正常:
将上述两个 nix 文件保存到一个文件夹中,然后在文件夹中运行
`nix eval .#nixosConfigurations.test.config.warnings`,运行正常:
```bash
nix eval .#nixosConfigurations.test.config.warnings
[ "foo" ]
```
这里需要注意的一点是,**不能在 `imports =[ ... ];` 中使用由 `_module.args` 传递的参数**,我们在前面 [传递非默认参数到模块系统中 ](../nixos-with-flakes/nixos-with-flakes-enabled#pass-non-default-parameters-to-submodules) 一章中已经做过详细说明。
这里需要注意的一点是,**不能在 `imports =[ ... ];` 中使用由 `_module.args` 传递的参数**
我们在前面
[传递非默认参数到模块系统中 ](../nixos-with-flakes/nixos-with-flakes-enabled#pass-non-default-parameters-to-submodules)
一章中已经做过详细说明。
## References
@ -365,8 +406,13 @@ Nixpkgs 中的模块系统提供了一系列类似 `lib.mkIf` 的函数,用于
- [Writing NixOS Modules - Nixpkgs][Writing NixOS Modules - Nixpkgs]
[lib/modules.nix]: https://github.com/NixOS/nixpkgs/blob/23.11/lib/modules.nix#L995
[Module System - Nixpkgs]: https://github.com/NixOS/nixpkgs/blob/23.11/doc/module-system/module-system.chapter.md
[Writing NixOS Modules - Nixpkgs]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/writing-modules.chapter.md
[Option Definitions - NixOS]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-def.section.md
[Option Declarations - NixOS]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-declarations.section.md
[Options Types - NixOS]: https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-types.section.md
[Module System - Nixpkgs]:
https://github.com/NixOS/nixpkgs/blob/23.11/doc/module-system/module-system.chapter.md
[Writing NixOS Modules - Nixpkgs]:
https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/writing-modules.chapter.md
[Option Definitions - NixOS]:
https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-def.section.md
[Option Declarations - NixOS]:
https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-declarations.section.md
[Options Types - NixOS]:
https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/doc/manual/development/option-types.section.md

View file

@ -1,15 +1,19 @@
# Flake 的 outputs {#flake-outputs}
`flake.nix` 中的 `outputs` 是一个 attribute set是整个 Flake 的构建结果,每个 Flake 都可以有许多不同的 outputs。
`flake.nix` 中的 `outputs` 是一个 attribute set是整个 Flake 的构建结果,每个 Flake 都可
以有许多不同的 outputs。
一些特定名称的 outputs 有特殊用途,会被某些 Nix 命令识别处理,比如:
- Nix packages: 名称为 `apps.<system>.<name>`, `packages.<system>.<name>``legacyPackages.<system>.<name>` 的 outputs都是 Nix 包,通常都是一个个应用程序。
- Nix packages: 名称为 `apps.<system>.<name>`, `packages.<system>.<name>`
`legacyPackages.<system>.<name>` 的 outputs都是 Nix 包,通常都是一个个应用程序。
- 可以通过 `nix build .#name` 来构建某个 nix 包
- Nix Helper Functions: 名称为 `lib` 的 outputs 是 Flake 函数库,可以被其他 Flake 作为 inputs 导入使用。
- Nix Helper Functions: 名称为 `lib` 的 outputs 是 Flake 函数库,可以被其他 Flake 作为
inputs 导入使用。
- Nix development environments: 名称为 `devShells` 的 outputs 是 Nix 开发环境
- 可以通过 `nix develop` 命令来使用该 Output 创建开发环境
- NixOS configurations: 名称为 `nixosConfigurations.<hostname>` 的 outputs是 NixOS 的系统配置。
- NixOS configurations: 名称为 `nixosConfigurations.<hostname>` 的 outputs是 NixOS 的系
统配置。
- `nixos-rebuild switch .#<hostname>` 可以使用该 Output 来部署 NixOS 系统
- Nix templates: 名称为 `templates` 的 outputs 是 flake 模板
- 可以通过执行命令 `nix flake init --template <reference>` 使用模板初始化一个 Flake 包

View file

@ -1,7 +1,9 @@
# 新一代 Nix 命令行工具的使用 {#flake-commands-usage}
在启用了 `nix-command` & `flakes` 功能后,我们就可以使用 Nix 提供的新一代 Nix 命令行工具 [New Nix Commands][New Nix Commands] 了,
这里主要介绍 `nix shell``nix run` 两个命令,其他重要的命令(如 `nix shell` `nix build`)将在「在 NixOS 上进行开发工作」一章中再详细介绍。
在启用了 `nix-command` & `flakes` 功能后,我们就可以使用 Nix 提供的新一代 Nix 命令行工具
[New Nix Commands][New Nix Commands] 了,这里主要介绍 `nix shell``nix run` 两个命令,
其他重要的命令(如 `nix shell` `nix build`)将在「在 NixOS 上进行开发工作」一章中再详细介
绍。
## `nix shell`
@ -36,7 +38,8 @@ Hello, world!
## `nix run`
`nix run` 则是创建一个含有指定 Nix 包的环境,并在该环境中直接运行该 Nix 包(临时运行该程序,不将它安装到系统环境中):
`nix run` 则是创建一个含有指定 Nix 包的环境,并在该环境中直接运行该 Nix 包(临时运行该程
序,不将它安装到系统环境中):
```shell
# hello 不存在
@ -50,7 +53,8 @@ Hello, world!
因为 `nix run` 会直接将 Nix 包运行起来,所以作为其参数的 Nix 包必须能生成一个可执行程序。
根据 `nix run --help` 的说明,`nix run` 会执行 `<out>/bin/<name>` 这个命令,其中 `<out>` 是一个 Derivation 的根目录,`<name>` 则按如下顺序进行选择尝试:
根据 `nix run --help` 的说明,`nix run` 会执行 `<out>/bin/<name>` 这个命令,其中 `<out>`
是一个 Derivation 的根目录,`<name>` 则按如下顺序进行选择尝试:
- Derivation 的 `meta.mainProgram` 属性
- Derivation 的 `pname` 属性
@ -76,7 +80,8 @@ echo "Hello Nix" | nix run "github:NixOS/nixpkgs/nixos-unstable#ponysay"
## `nix run``nix shell` 的常见用途
那显然就是用来跑些临时命令,比如说我在新 NixOS 主机上恢复环境,但是还没有装 Git我可以直接用如下命令临时使用 Git 克隆我的配置仓库:
那显然就是用来跑些临时命令,比如说我在新 NixOS 主机上恢复环境,但是还没有装 Git我可以直
接用如下命令临时使用 Git 克隆我的配置仓库:
```bash
nix run nixpkgs#git clone git@github.com:ryan4yin/nix-config.git

View file

@ -2,48 +2,62 @@
## NixOS 初学者之痛 - 文档与 Flakes
NixOS 是个非常特殊的 Linux 发行版,它构建在 Nix 包管理器之上,设计哲学也跟传统的 Ubuntu, CentOS, Arch Linux 等发行版大相径庭。
NixOS 是个非常特殊的 Linux 发行版,它构建在 Nix 包管理器之上,设计哲学也跟传统的 Ubuntu,
CentOS, Arch Linux 等发行版大相径庭。
NixOS 相比其他发行版最大的优势,是它的可复现能力(即在多台机器上复现出一致的系统环境的能力)以及声明式配置。
NixOS 相比其他发行版最大的优势,是它的可复现能力(即在多台机器上复现出一致的系统环境的能
力)以及声明式配置。
NixOS 很强大,但它的强大也带来了系统复杂度的提升,提高了使用门槛。
一方面你在其他 Linux 发行版上积累很多经验很难在 NixOS 上复用,另一方面 NixOS 又一直因为官方文档与社区文档的散乱陈旧而饱受诟病。
这些问题都困扰着许多 NixOS 新手。
NixOS 很强大,但它的强大也带来了系统复杂度的提升,提高了使用门槛。一方面你在其他 Linux 发
行版上积累很多经验很难在 NixOS 上复用,另一方面 NixOS 又一直因为官方文档与社区文档的散乱陈
旧而饱受诟病。这些问题都困扰着许多 NixOS 新手。
再说到 Nix 包管理器的实验特性 Flakes它借鉴了 npm/cargo 等包管理器的设计思路,使用 flake.nix 记录所有外部依赖项,使用 flake.lock 锁定所有依赖的版本,极大地增强了 Nix 包管理器及 NixOS 的可复现能力跟配置可组合能力。
再说到 Nix 包管理器的实验特性 Flakes它借鉴了 npm/cargo 等包管理器的设计思路,使用
flake.nix 记录所有外部依赖项,使用 flake.lock 锁定所有依赖的版本,极大地增强了 Nix 包管理
器及 NixOS 的可复现能力跟配置可组合能力。
因为 Flakes 的好处很大,社区非常喜欢它。据官方调查,目前 GitHub 新建的 nix 仓库超过半数都使用了 Flakes传统的 Nix 配置方式已经不再是主流。
因为 Flakes 的好处很大,社区非常喜欢它。据官方调查,目前 GitHub 新建的 nix 仓库超过半数都
使用了 Flakes传统的 Nix 配置方式已经不再是主流。
但是另一方面 Flakes 作为一个实验性能力存在不确定性,官方文档为了保持稳定性,几乎未包含任何 Flakes 相关的内容。
这使许多 Nix/NixOS 用户感到相当困惑——他们看到大家都在用 Flakes也想学习下它但却发现无处学起只能到处拼凑零散的资料、翻 Nixpkgs 源码,或者找前辈高人请教。
但是另一方面 Flakes 作为一个实验性能力存在不确定性,官方文档为了保持稳定性,几乎未包含任何
Flakes 相关的内容。这使许多 Nix/NixOS 用户感到相当困惑——他们看到大家都在用 Flakes也想学
习下它,但却发现无处学起,只能到处拼凑零散的资料、翻 Nixpkgs 源码,或者找前辈高人请教。
## 本书的由来
本书最初源于我入坑 NixOS 时的一份零散学习笔记。
我在今年2023 4 月份入坑 NixOS 时就深深地爱上了它的设计哲学,同时在朋友的推荐下我了解到了 Nix 的 Flakes 实验特性。
在对比了 Flakes 与传统的 NixOS 配置方式后,我意识到只有带上了 Flakes 的 NixOS 才符合我对它的期待。
于是我完全忽略掉了传统的 Nix 配置方式,在入门阶段就直接学习使用 Flakes 来配置我的 NixOS 系统。
我在今年2023 4 月份入坑 NixOS 时就深深地爱上了它的设计哲学,同时在朋友的推荐下我了解到
了 Nix 的 Flakes 实验特性。在对比了 Flakes 与传统的 NixOS 配置方式后,我意识到只有带上了
Flakes 的 NixOS 才符合我对它的期待。于是我完全忽略掉了传统的 Nix 配置方式,在入门阶段就直
接学习使用 Flakes 来配置我的 NixOS 系统。
在学习的过程中,我发现适合新手的 Flakes 文档几乎没有,大量的文档都是传统的 Nix 配置方法,我需要从 NixOS Wiki、Zero to Nix、Nixpkgs Manual、
Nixpkgs 源码等各种资料中提取出我需要的信息,同时还要忽略掉所有非 Flakes 的内容。
这个学习过程非常曲折痛苦。
为了避免后面再次踩坑,我在学习过程中记录了大量的零散笔记。
在学习的过程中,我发现适合新手的 Flakes 文档几乎没有,大量的文档都是传统的 Nix 配置方法,
我需要从 NixOS Wiki、Zero to Nix、Nixpkgs Manual、Nixpkgs 源码等各种资料中提取出我需要的信
息,同时还要忽略掉所有非 Flakes 的内容。这个学习过程非常曲折痛苦。为了避免后面再次踩坑,我
在学习过程中记录了大量的零散笔记。
在拥有了一定使用经验后,今年 5 月初的时候我将自己的主力 PC 切换到了 NixOS然后将这份写了大半个月的 NixOS 新手笔记整理润色后发布到了我的博客[^1] ,并分享到了 NixOS 中文社区。
中文社区的朋友们表示写得很棒,在他们的建议下,我又将这篇文章翻译成了英文并分享到了 Reddit收到了非常强烈的正反馈[^2]。
在拥有了一定使用经验后,今年 5 月初的时候我将自己的主力 PC 切换到了 NixOS然后将这份写了
大半个月的 NixOS 新手笔记整理润色后发布到了我的博客[^1] ,并分享到了 NixOS 中文社区。中文
社区的朋友们表示写得很棒,在他们的建议下,我又将这篇文章翻译成了英文并分享到了 Reddit
到了非常强烈的正反馈[^2]。
这份笔记分享出来后好评不断,这让我备感振奋,继续完善它的热情也高涨。
在我的持续更新下这份笔记的内容不断增多,逐渐扩充到了 2 万多字,有读者反馈阅读体验不太好,于是在他的建议下[^3]
我将文章内容迁移到了一个 GitHub 仓库,搭建了一个专门的文档站点,方便大家阅读与贡献。
同时也调整了内容的表述,去掉了一些过于个人化的内容,使其更贴近一本新手指南的风格,而不是一份随性而为的个人笔记。
这份笔记分享出来后好评不断,这让我备感振奋,继续完善它的热情也高涨。在我的持续更新下这份笔
记的内容不断增多,逐渐扩充到了 2 万多字,有读者反馈阅读体验不太好,于是在他的建议下[^3]
我将文章内容迁移到了一个 GitHub 仓库,搭建了一个专门的文档站点,方便大家阅读与贡献。同时也
调整了内容的表述,去掉了一些过于个人化的内容,使其更贴近一本新手指南的风格,而不是一份随性
而为的个人笔记。
至此,一本中英双语的开源书籍诞生了,我给它取名叫 <NixOS & Flakes Book>中文名叫《NixOS 与 Flakes 新手指南》。
至此,一本中英双语的开源书籍诞生了,我给它取名叫 <NixOS & Flakes Book>中文名叫《NixOS 与
Flakes 新手指南》。
这本开源书籍的内容是我在使用 NixOS 的过程中,以及与读者的沟通中一步步优化的,读者的好评带来的成就感是我更新的最大动力,一些读者的反馈也对它的「进化」产生了很大的帮助。
我最初只是想分享一下自己的 NixOS 折腾心得,内容也写得比较随意,没想到最后却成了一本开源书籍,国外的阅读量甚至是国内的两倍,而且还得到了许多 stars ,这真是完全没预料到的。
这本开源书籍的内容是我在使用 NixOS 的过程中,以及与读者的沟通中一步步优化的,读者的好评带
来的成就感是我更新的最大动力,一些读者的反馈也对它的「进化」产生了很大的帮助。我最初只是想
分享一下自己的 NixOS 折腾心得,内容也写得比较随意,没想到最后却成了一本开源书籍,国外的阅
读量甚至是国内的两倍,而且还得到了许多 stars ,这真是完全没预料到的。
感谢所有对本书做出过贡献、提出过建议的朋友们,感谢所有读者的支持与鼓励,没有你们,这本书的内容可能会一直停留在我个人的博客上,也不会有今天的样子。
感谢所有对本书做出过贡献、提出过建议的朋友们,感谢所有读者的支持与鼓励,没有你们,这本书的
内容可能会一直停留在我个人的博客上,也不会有今天的样子。
## 捐赠
@ -56,21 +70,26 @@ Nixpkgs 源码等各种资料中提取出我需要的信息,同时还要忽略
## 反馈与讨论
我不是什么 NixOS 专家到目前为止2024-02我只使用了不到 9 个月的 NixOS所以书中肯定存在一些误解或者不当的例子。
如果你发现了任何错误或者有任何问题/建议,可以直接通过开 issue 或者加入 [GitHub Discussions](https://github.com/ryan4yin/nixos-and-flakes-book/discussions) 讨论,我很乐意根据大家的反馈持续优化本书的内容。
我不是什么 NixOS 专家到目前为止2024-02我只使用了不到 9 个月的 NixOS所以书中肯定存
在一些误解或者不当的例子。如果你发现了任何错误或者有任何问题/建议,可以直接通过开 issue 或
者加入 [GitHub Discussions](https://github.com/ryan4yin/nixos-and-flakes-book/discussions)
讨论,我很乐意根据大家的反馈持续优化本书的内容。
我写这本小书的原因只是因为没有人为当时还是新手的我做这件事,如上所述,社区的文档太乱了,所以我选择自己动手,丰衣足食。
即使我知道我可能会犯错,但这总比什么都不做要好得多。
我写这本小书的原因只是因为没有人为当时还是新手的我做这件事,如上所述,社区的文档太乱了,所
以我选择自己动手,丰衣足食。即使我知道我可能会犯错,但这总比什么都不做要好得多。
我希望这本书能帮助更多的人,让他们能够体验到 NixOS 的乐趣。希望你们喜欢它!
## 本书的特点
1. 以 NixOS 与 Flakes 为核心进行讲解,摈弃了传统的 Nix 配置方式
2. 新手友好,内容尽可能地从拥有一定 Linux 使用经验与编程经验的 NixOS 初学者角度出发进行讲解
2. 新手友好,内容尽可能地从拥有一定 Linux 使用经验与编程经验的 NixOS 初学者角度出发进行讲
3. step-by-step渐进式地学习
4. 本书的大部分章节的末尾都给出了其中内容的参考链接,方便读者进一步深入学习,也方便读者对内容的可信度进行评估
5. 内容连贯,组织良好,比较成体系。读者既可以渐进式地阅读本书,也可以快速定位自己需要的信息
4. 本书的大部分章节的末尾都给出了其中内容的参考链接,方便读者进一步深入学习,也方便读者对
内容的可信度进行评估
5. 内容连贯,组织良好,比较成体系。读者既可以渐进式地阅读本书,也可以快速定位自己需要的信
## 本书的历史反馈与相关讨论
@ -88,5 +107,8 @@ Nixpkgs 源码等各种资料中提取出我需要的信息,同时还要忽略
- [[2023-06-24] NixOS 与 Flakes | 一份非官方的新手指南 - 0xffff 社区](https://0xffff.one/d/1547-nixos-yu-flakes-yi-fen-fei-guan)
[^1]: [NixOS 与 Nix Flakes 新手入门](https://thiscute.world/posts/nixos-and-flake-basics/)
[^2]: [NixOS & Nix Flakes - A Guide for Beginners - Reddit](https://www.reddit.com/r/NixOS/comments/13dxw9d/nixos_nix_flakes_a_guide_for_beginners/)
[^3]: [Updates: NixOS & Nix Flakes - A Guide for Beginners - Reddit](https://www.reddit.com/r/NixOS/comments/14fvz1q/comment/jp4xhj3/?context=3)
[^2]:
[NixOS & Nix Flakes - A Guide for Beginners - Reddit](https://www.reddit.com/r/NixOS/comments/13dxw9d/nixos_nix_flakes_a_guide_for_beginners/)
[^3]:
[Updates: NixOS & Nix Flakes - A Guide for Beginners - Reddit](https://www.reddit.com/r/NixOS/comments/14fvz1q/comment/jp4xhj3/?context=3)

View file

@ -1,17 +1,25 @@
# Nix 语言入门
Nix 语言是 Nix 包管理器的基础,要想玩得转 NixOS 与 Nix Flakes享受到它们带来的诸多好处就必须学会这门语言。
Nix 语言是 Nix 包管理器的基础,要想玩得转 NixOS 与 Nix Flakes享受到它们带来的诸多好处
就必须学会这门语言。
Nix 是一门比较简单的函数式语言,在已有一定编程基础的情况下,过一遍这些语法用时应该在 2 个小时以内。
Nix 是一门比较简单的函数式语言,在已有一定编程基础的情况下,过一遍这些语法用时应该在 2 个
小时以内。
NixOS-CN 社区已经有了一份不错的 Nix 语言教程,我不打算重复造轮子,请直接阅读 [**Nix 语言概览 - NixOS-CN**](https://nixos-cn.org/tutorials/lang) 来快速入门。
NixOS-CN 社区已经有了一份不错的 Nix 语言教程,我不打算重复造轮子,请直接阅读
[**Nix 语言概览 - NixOS-CN**](https://nixos-cn.org/tutorials/lang) 来快速入门。
先把语法过一遍,有个大概的印象就行,后面需要用到时再边用边复习语法知识。
## 补充说明
1. 如果你英文尚可,我建议直接阅读官方的入门教程 [Nix language basics - nix.dev](https://nix.dev/tutorials/nix-language) 了解 Nix 语言的基础语法。
2. 另外需要注意的是NixOS-CN 的语言教程跟 nix.dev 都未介绍完整的 Nix 语法,仅适合新手快速入门。**如果你遇到任何自己未接触过的语法,请通过官方文档 [Nix Language - Nix Reference Manual] 查阅 Nix 语言的完整语法**
3. <https://noogle.dev/> 是社区的一个 Nix 函数库搜索器,可以帮助你快速查找你需要的函数以及它们的用法,非常实用。
1. 如果你英文尚可,我建议直接阅读官方的入门教程
[Nix language basics - nix.dev](https://nix.dev/tutorials/nix-language) 了解 Nix 语言的
基础语法。
2. 另外需要注意的是NixOS-CN 的语言教程跟 nix.dev 都未介绍完整的 Nix 语法,仅适合新手快速
入门。**如果你遇到任何自己未接触过的语法,请通过官方文档 [Nix Language - Nix Reference
Manual] 查阅 Nix 语言的完整语法**
3. <https://noogle.dev/> 是社区的一个 Nix 函数库搜索器,可以帮助你快速查找你需要的函数以及
它们的用法,非常实用。
[Nix Language - Nix Reference Manual]: https://nixos.org/manual/nix/stable/language/