mirror of
https://codeberg.org/mhwombat/nix-book.git
synced 2025-12-26 16:24:56 +08:00
temp
This commit is contained in:
parent
6a1eee3d27
commit
095401025c
8 changed files with 128 additions and 383 deletions
|
|
@ -54,8 +54,6 @@ include::generic-flake/main.adoc[leveloffset=+1]
|
|||
|
||||
include::hello-flake-return/main.adoc[leveloffset=+1]
|
||||
|
||||
include::modify-hello-flake/main-generated.adoc[leveloffset=+1]
|
||||
|
||||
include::new-flake/main.adoc[leveloffset=+1]
|
||||
|
||||
include::recipes/main.adoc[leveloffset=+1]
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
{
|
||||
description = "a very simple and friendly flake";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
in
|
||||
{
|
||||
devShells = rec {
|
||||
default = pkgs.mkShell {
|
||||
packages = [ pkgs.cowsay ];
|
||||
};
|
||||
};
|
||||
|
||||
packages = rec {
|
||||
hello = pkgs.stdenv.mkDerivation rec {
|
||||
name = "hello-flake";
|
||||
|
||||
src = ./.;
|
||||
|
||||
unpackPhase = "true";
|
||||
|
||||
buildPhase = ":";
|
||||
|
||||
installPhase =
|
||||
''
|
||||
mkdir -p $out/bin
|
||||
cp $src/hello-flake $out/bin/hello-flake
|
||||
chmod +x $out/bin/hello-flake
|
||||
'';
|
||||
|
||||
buildInputs = [ pkgs.cowsay ];
|
||||
};
|
||||
default = hello;
|
||||
};
|
||||
|
||||
apps = rec {
|
||||
hello = flake-utils.lib.mkApp { drv = self.packages.${system}.hello; };
|
||||
default = hello;
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
{
|
||||
description = "a very simple and friendly flake";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
in
|
||||
{
|
||||
devShells = rec {
|
||||
default = pkgs.mkShell {
|
||||
packages = [ pkgs.cowsay ];
|
||||
};
|
||||
};
|
||||
|
||||
packages = rec {
|
||||
hello = pkgs.stdenv.mkDerivation rec {
|
||||
name = "hello-flake";
|
||||
|
||||
src = ./.;
|
||||
|
||||
unpackPhase = "true";
|
||||
|
||||
buildPhase = ":";
|
||||
|
||||
installPhase =
|
||||
''
|
||||
mkdir -p $out/bin
|
||||
cp $src/hello-flake $out/bin/hello-flake
|
||||
chmod +x $out/bin/hello-flake
|
||||
|
||||
# modify the hello-flake script so it can find cowsay
|
||||
COWSAY=$(type -p cowsay)
|
||||
sed "s_cowsay_"$COWSAY"_" --in-place $out/bin/hello-flake
|
||||
'';
|
||||
|
||||
buildInputs = [ pkgs.cowsay ];
|
||||
};
|
||||
default = hello;
|
||||
};
|
||||
|
||||
apps = rec {
|
||||
hello = flake-utils.lib.mkApp { drv = self.packages.${system}.hello; };
|
||||
default = hello;
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1,256 +0,0 @@
|
|||
= Modifying the flake
|
||||
|
||||
== The Nix development shell
|
||||
|
||||
Let's make a simple modification to the script. This will give you an
|
||||
opportunity to check your understanding of flakes.
|
||||
|
||||
The first step is to enter a development shell.
|
||||
|
||||
////
|
||||
The user would have done this in an earlier section.
|
||||
However, my adoc0 scripts clean up after themselves, so we need to do it again.
|
||||
$ git clone https://codeberg.org/mhwombat/hello-flake
|
||||
$ cd hello-flake
|
||||
////
|
||||
|
||||
....
|
||||
$ nix develop
|
||||
....
|
||||
|
||||
The `flake.nix` file specifies all of the tools that are needed during
|
||||
development of the package. The `nix develop` command puts us in a shell
|
||||
with those tools. As it turns out, we didn't need any extra tools
|
||||
(beyond the standard environment) for development yet, but that's
|
||||
usually not the case. Also, we will soon need another tool.
|
||||
|
||||
A development environment only allows you to _develop_ the package.
|
||||
Don't expect the package _outputs_ (e.g. executables) to be available
|
||||
until you build them. However, our script doesn't need to be compiled,
|
||||
so can't we just run it?
|
||||
|
||||
....
|
||||
$ hello-flake
|
||||
....
|
||||
|
||||
That worked before; why isn't it working now? Earlier we used
|
||||
`nix shell` to enter a _runtime_ environment where `hello-flake` was
|
||||
available and on the `$PATH`. This time we entered a _development_
|
||||
environment using the `nix develop` command. Since the flake hasn't been
|
||||
built yet, the executable won't be on the `$PATH`. We can, however, run
|
||||
it by specifying the path to the script.
|
||||
|
||||
....
|
||||
$ ./hello-flake
|
||||
....
|
||||
|
||||
We can also build the flake using the `nix build` command, which places
|
||||
the build outputs in a directory called `result`.
|
||||
|
||||
....
|
||||
$ nix build
|
||||
$ result/bin/hello-flake
|
||||
....
|
||||
|
||||
Rather than typing the full path to the executable, it's more convenient
|
||||
to use `nix run`.
|
||||
|
||||
....
|
||||
$ nix run
|
||||
....
|
||||
|
||||
Here's a summary of the more common Nix commands.
|
||||
|
||||
[width="100%",cols="<17%,<83%",options="header",]
|
||||
|===
|
||||
|command |Action
|
||||
|`nix develop` |Enters a _development_ shell with all the required
|
||||
development tools (e.g. compilers and linkers) available (as specified
|
||||
by `flake.nix`).
|
||||
|
||||
|`nix shell` |Enters a _runtime_ shell where the flake's executables are
|
||||
available on the `$PATH`.
|
||||
|
||||
|`nix build` |Builds the flake and puts the output in a directory called
|
||||
`result`.
|
||||
|
||||
|`nix run` |Runs the flake's default executable, rebuilding the package
|
||||
first if needed. Specifically, it runs the version in the Nix store, not
|
||||
the version in `result`.
|
||||
|===
|
||||
|
||||
== Introducing a dependency
|
||||
|
||||
Now we're ready to make the flake a little more interesting.
|
||||
Instead of using the `echo` command in the script, we can use the Linux `cowsay`
|
||||
command.
|
||||
Here's the modified `hello-flake` file.
|
||||
|
||||
////
|
||||
$ sed -i 's/echo/cowsay/' hello-flake
|
||||
////
|
||||
|
||||
[source,nix,linenums,highlight=3]
|
||||
.hello-flake
|
||||
....
|
||||
$# cat hello-flake
|
||||
....
|
||||
|
||||
Let's test the modified script.
|
||||
|
||||
....
|
||||
$ ./hello-flake # Fails
|
||||
....
|
||||
|
||||
What went wrong? Remember that we are in a _development_ shell. Since
|
||||
`flake.nix` didn't define the `devShells` variable, the development
|
||||
shell only includes the Nix standard environment. In particular, the
|
||||
`cowsay` command is not available.
|
||||
|
||||
[#hello-flake-dependency]
|
||||
To fix the problem, we can modify `flake.nix`.
|
||||
We don't need to add `cowsay` to the `inputs` section because it's included in `nixpkgs`,
|
||||
which is already an input.
|
||||
However, we also want it to be available in a development shell.
|
||||
The highlighted modifications below will accomplish that.
|
||||
|
||||
////
|
||||
$ cp ../flake.nix.new flake.nix
|
||||
////
|
||||
|
||||
[source,nix,linenums,highlight=15..19]
|
||||
.flake.nix
|
||||
....
|
||||
$# cat flake.nix
|
||||
....
|
||||
|
||||
Now we restart the development shell and see that the `cowsay` command is available.
|
||||
Because we've updated source files but haven't ``git commit``ed the new version,
|
||||
we get a warning message about it being "`dirty`".
|
||||
It's just a warning, though; the script runs correctly.
|
||||
|
||||
....
|
||||
$# echo '$ nix develop'
|
||||
$# nix develop --command sh
|
||||
$ which cowsay # is it available now?
|
||||
$ ./hello-flake
|
||||
$ exit
|
||||
....
|
||||
|
||||
Let's try `nix run`.
|
||||
|
||||
....
|
||||
$ nix run # Fails
|
||||
....
|
||||
|
||||
What went wrong?
|
||||
Recall that we only added `cowsay` to the development environment;
|
||||
we didn't add it to the runtime environment.
|
||||
The modified flake below will fix that.
|
||||
|
||||
////
|
||||
$ cp ../flake.nix.new.2 flake.nix
|
||||
////
|
||||
|
||||
[source,nix,linenums,highlight='37..39,42']
|
||||
.flake.nix
|
||||
....
|
||||
$# cat flake.nix
|
||||
....
|
||||
|
||||
Line 42 adds `cowsay` as a `buildInput` for the package.
|
||||
That does make it available at build and runtime, but it doesn’t put it on the path,
|
||||
so our hello-flake script wouldn’t be able to find it.
|
||||
There are various ways to deal with this problem.
|
||||
In this case we simply edited the script (lines 37-39) as we install it,
|
||||
specifying the full path to cowsay.
|
||||
We'll see another way of handling this in <<writeShellApplication>>.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
When you're packaging a program written in a more powerful language such as
|
||||
Haskell, Python, Java, C, C#, or Rust,
|
||||
the language build system will usually do all that is required
|
||||
to make the dependencies visible to the program at runtime.
|
||||
In that case, adding the dependency to `buildInputs` is sufficient.
|
||||
====
|
||||
|
||||
This time `nix run` works.
|
||||
|
||||
....
|
||||
$ nix run
|
||||
....
|
||||
|
||||
Note, however, that `nix run` rebuilt the package in the Nix store and
|
||||
ran _that_. It did not alter the copy in the `result` directory, as
|
||||
we'll see next.
|
||||
|
||||
....
|
||||
$ cat result/bin/hello-flake
|
||||
....
|
||||
|
||||
If we want to update the version in `result`, we need `nix build` again.
|
||||
|
||||
....
|
||||
$ nix build
|
||||
$ cat result/bin/hello-flake
|
||||
....
|
||||
|
||||
Let's `git commit` the changes and verify that the warning goes away. We
|
||||
don't need to `git push` the changes until we're ready to share them.
|
||||
|
||||
....
|
||||
$ git commit hello-flake flake.nix -m 'added bovine feature'
|
||||
$ nix run
|
||||
....
|
||||
|
||||
== Development workflows
|
||||
|
||||
If you're getting confused about when to use the different commands,
|
||||
it's because there's more than one way to use Nix. I tend to think of it
|
||||
as two different development workflows.
|
||||
|
||||
My usual, _high-level workflow_ is quite simple.
|
||||
|
||||
[arabic]
|
||||
. `nix run` to re-build (if necessary) and run the executable.
|
||||
. Fix any problems in `flake.nix` or the source code.
|
||||
. Repeat until the package works properly.
|
||||
|
||||
In the high-level workflow, I don't use a development shell because I
|
||||
don't need to directly invoke development tools such as compilers and
|
||||
linkers. Nix invokes them for me according to the output definition in
|
||||
`flake.nix`.
|
||||
|
||||
Occasionally I want to work at a lower level, and invoke compiler,
|
||||
linkers, etc. directly. Perhaps want to work on one component without
|
||||
rebuilding the entire package. Or perhaps I'm confused by some error
|
||||
message, so I want to temporarily bypass Nix and work directly with
|
||||
the compiler. In this case I temporarily switch to a _low-level
|
||||
workflow_.
|
||||
|
||||
[arabic]
|
||||
. `nix develop` to enter a development shell with any development tools
|
||||
I need (e.g. compilers, linkers, documentation generators).
|
||||
. Directly invoke tools such as compilers.
|
||||
. Fix any problems in `flake.nix` or the source code.
|
||||
. Directly invoke the executable. Note that the location of the
|
||||
executable depends on the development tools – It probably isn't
|
||||
`result`!
|
||||
. Repeat until the package works properly.
|
||||
|
||||
I generally only use `nix build` if I just want to build the package but
|
||||
not execute anything (perhaps it's just a library).
|
||||
|
||||
== This all seems like a hassle!
|
||||
|
||||
It is a bit annoying to modify `flake.nix` and ether rebuild or reload
|
||||
the development environment every time you need another tool. However,
|
||||
this Nix way of doing things ensures that all of your dependencies, down
|
||||
to the exact versions, are captured in `flake.lock`, and that anyone
|
||||
else will be able to reproduce the development environment.
|
||||
|
||||
////
|
||||
Good adoc0 scripts clean up after themselves.
|
||||
$ cd .. ; rm -rf hello-flake # clean up
|
||||
////
|
||||
|
|
@ -261,7 +261,28 @@ system:
|
|||
}
|
||||
....
|
||||
|
||||
So `lib.genAttrs [ "x86_64-linux" "aarch64-linux" ]`
|
||||
followed by the first function will give us the development shell definitions for both systems,
|
||||
and followed by the second function will give us the package definitions for both systems.
|
||||
We can make the flake more readable with the following definitions.
|
||||
|
||||
[source,nix]
|
||||
....
|
||||
supportedSystems = [ "x86_64-linux" "aarch64-linux" ];
|
||||
|
||||
forAllSupportedSystems = nixpkgs.lib.genAttrs supportedSystems;
|
||||
....
|
||||
|
||||
Now let's examine the definition of `nixpkgsFor.${system}`.
|
||||
|
||||
[source,nix]
|
||||
....
|
||||
nixpkgsFor = forAllSupportedSystems (system: import nixpkgs { inherit system; });
|
||||
....
|
||||
|
||||
Putting everything together, we have a shiny new flake.
|
||||
You may want to compare it carefully to the original version,
|
||||
in order to reassure yourself that the definitions are equivalent.
|
||||
|
||||
////
|
||||
$ cp ../flake-4.nix flake.nix
|
||||
|
|
@ -276,12 +297,13 @@ $# cat flake.nix
|
|||
Let's verify that it runs on our system.
|
||||
|
||||
....
|
||||
$ git commit -am "refactored the flake"
|
||||
$ nix run
|
||||
....
|
||||
|
||||
You may want to compare the latest `flake.nix` carefully to the original version,
|
||||
in order to reassure yourself that the definitions are equivalent.
|
||||
// TODO In packages, add cow-hello and set default = cow-hello. Explain why.
|
||||
|
||||
// TODO Add an apps section and explain why.
|
||||
|
||||
////
|
||||
Good adoc0 scripts clean up after themselves.
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, pandoc-columns }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
customGhc = pkgs.haskellPackages.ghcWithPackages (p: with p; [ extra ]);
|
||||
in
|
||||
{
|
||||
devShells = rec {
|
||||
default = pkgs.mkShell {
|
||||
buildInputs = [ customGhc ];
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
77
source/recipes/devshell/nix-non-flake/tempwork/flake.lock
generated
Normal file
77
source/recipes/devshell/nix-non-flake/tempwork/flake.lock
generated
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hello-nix": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1757705465,
|
||||
"narHash": "sha256-sJCQ9+8Dy+QF9ISaupp42+mGbuXtFyqbX85tWzeNPOI=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "56044f61231c996e4ab795de1da89e5f79db3f4f",
|
||||
"revCount": 5,
|
||||
"type": "git",
|
||||
"url": "https://codeberg.org/mhwombat/hello-nix"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://codeberg.org/mhwombat/hello-nix"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1760301964,
|
||||
"narHash": "sha256-5oeX7NvYHNslymyCmX9mLEmLp07a8ai522G8J4VrDrs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1b5c1881789eb8c86c655caeff3c918fb76fbfe6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"hello-nix": "hello-nix",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
27
source/recipes/devshell/nix-non-flake/tempwork/flake.nix
Normal file
27
source/recipes/devshell/nix-non-flake/tempwork/flake.nix
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
hello-nix = {
|
||||
url = "git+https://codeberg.org/mhwombat/hello-nix";
|
||||
flake = false;
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, hello-nix }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
};
|
||||
helloNix = import hello-nix { inherit pkgs; };
|
||||
in
|
||||
{
|
||||
devShells = rec {
|
||||
default = pkgs.mkShell {
|
||||
packages = [ helloNix ];
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue