This commit is contained in:
Amy de Buitléir 2025-09-02 16:56:18 +01:00
parent 97a04e49ea
commit 90b9c96dc5
13 changed files with 288 additions and 73826 deletions

View file

@ -8,7 +8,7 @@
version="1.1"
id="svg5913"
xml:space="preserve"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="wombat.svg"
inkscape:export-filename="wombat.png"
inkscape:export-xdpi="96"
@ -27,14 +27,14 @@
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="2.4607825"
inkscape:cx="474.84896"
inkscape:cy="168.84873"
inkscape:window-width="2556"
inkscape:zoom="2.8284271"
inkscape:cx="455.9071"
inkscape:cy="180.66578"
inkscape:window-width="3436"
inkscape:window-height="1383"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" /><defs
id="defs5910" /><g
inkscape:label="Layer 1"
@ -73,15 +73,13 @@
sodipodi:nodetypes="cc" /><path
style="fill:#ba9c6a;fill-opacity:1;stroke:#000000;stroke-width:0.6;stroke-linecap:round;stroke-dasharray:none;stop-color:#000000"
d="m 94.548277,130.43371 c 0,0 -6.90332,-5.91092 -9.37557,-3.55446 -2.47226,2.35646 0.10844,10.24541 0.10844,10.24541 l -3.06306,-2.69648 2.34121,4.77336 -2.57053,-2.28643 3.49402,5.16987"
id="path6412" /><g
id="g2485"
transform="translate(4.3585838,0.17055041)"><path
id="path6368-4"
style="fill:#e3dedb;stroke:#000000;stroke-width:0.4;stroke-dasharray:none;stop-color:#000000"
d="m 110.09801,132.36663 a 2.2434674,1.9215461 0 0 1 -2.24346,1.92155 2.2434674,1.9215461 0 0 1 -2.24346,-1.92155 2.2434674,1.9215461 0 0 1 2.24346,-1.92154 2.2434674,1.9215461 0 0 1 2.24346,1.92154 z" /><path
id="path11906"
style="fill:#000000;stroke:none;stroke-width:0.900003;stop-color:#000000"
d="m 108.52917,132.54659 a 0.73756917,1.260413 5.7418555 0 1 -0.86001,1.18029 0.73756917,1.260413 5.7418555 0 1 -0.60776,-1.32787 0.73756917,1.260413 5.7418555 0 1 0.86001,-1.18028 0.73756917,1.260413 5.7418555 0 1 0.60778,1.32787 z" /></g><path
id="path6412" /><path
id="path6368-4"
style="fill:#e3dedb;stroke:#000000;stroke-width:0.4;stroke-dasharray:none;stop-color:#000000"
d="m 114.26024,131.61933 a 1.9215461,2.2434674 65.850277 0 1 -1.26096,2.67123 1.9215461,2.2434674 65.850277 0 1 -2.83326,-0.83553 1.9215461,2.2434674 65.850277 0 1 1.26096,-2.67122 1.9215461,2.2434674 65.850277 0 1 2.83326,0.83552 z" /><path
id="path11906"
style="fill:#000000;stroke:none;stroke-width:0.900003;stop-color:#000000"
d="m 113.92504,132.07651 a 1.260413,0.73756917 60.207704 0 1 -0.0139,1.46031 1.260413,0.73756917 60.207704 0 1 -1.26632,-0.72736 1.260413,0.73756917 60.207704 0 1 0.0139,-1.4603 1.260413,0.73756917 60.207704 0 1 1.26633,0.72734 z" /><path
id="path12434"
style="fill:#000000;fill-opacity:1;stroke-width:0.900004;stop-color:#000000"
d="m 158.72308,200.87103 c -2.39891,-0.60203 -3.49657,3.28976 -5.13291,1.0768 -1.35531,-1.83291 3.89675,-2.86693 5.13291,-1.0768 z"

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Before After
Before After

4454
index.html

File diff suppressed because it is too large Load diff

View file

@ -84,7 +84,7 @@ the version in `result`.
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 `hello-flake` file, with the modified line highlighted.
Here's the modified `hello-flake` file.
////
$ sed -i 's/echo/cowsay/' hello-flake
@ -107,6 +107,7 @@ What went wrong? Remember that we are in a _development_ shell. Since
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.

View file

@ -0,0 +1,7 @@
import Network.HostName
main :: IO ()
main = do
putStrLn "Hello from Haskell inside a Nix flake!"
h <- getHostName
putStrLn $ "Your hostname is: " ++ h

View file

@ -13,7 +13,7 @@ $ git init
Next, we'll create a simple Haskell program.
////
$ curl https://codeberg.org/mhwombat/hello-flake-haskell/raw/branch/main/Main.hs --silent --output Main.hs
$ cp ../Main.hs .
////
[source,haskell,linenums]
@ -22,10 +22,22 @@ $ curl https://codeberg.org/mhwombat/hello-flake-haskell/raw/branch/main/Main.hs
$# cat Main.hs
....
== (Optional) Testing before packaging
== Running the program manually (optional)
[NOTE]
====
In this section you will learn how to do some development tasks manually, the "hard" way.
This can help you understand the distinction between Nix's role and
the Haskell build system you've chosen.
Also, if you have a build problem but you're not sure if the fault is in
your flake definition or some other configuration file,
these commands can help you narrow it down.
But you may wish to skip to the <<_the_cabal_file,next section>>
and come back here later.
====
Before we package the program, let's verify that it runs. We're going to
need a Haskell compiler. By now you've probably figured out that we can write a
need Haskell. By now you've probably figured out that we can write a
`flake.nix` and define a development shell that includes Haskell. We'll
do that shortly, but first I want to show you a handy shortcut. We can
launch a _temporary_ shell with any Nix packages we want. This is
@ -36,21 +48,11 @@ packages you need), and you want to experiment a bit first.
The command to enter a temporary shell is
`nix-shell -p __packages__`
`nix shell -p __installables__`
If there are multiple packages, they should be separated by spaces.
[IMPORTANT]
====
The command used here is `nix-shell` with a hyphen, not `nix shell`
with a space; those are two different commands. In fact there are
hyphenated and non-hyphenated versions of many Nix commands, and yes,
it's confusing. The non-hyphenated commands were introduced when support
for flakes was added to Nix. I predict that eventually all hyphenated
commands will be replaced with non-hyphenated versions. Until then, a
useful rule of thumb is that non-hyphenated commands are for working
directly with flakes; hyphenated commands are for everything else.
====
Where __installables__ are flakes and other types of packages that you need.
(You can learn more about these in the
https://nix.dev/manual/nix/stable/command-ref/new-cli/nix#installables[Nix manual].)
=== Some unsuitable shells
@ -66,8 +68,8 @@ You can come back to this section later to learn more.
Let's enter a shell with the Glasgow Haskell Compiler ("ghc") and try to run the program.
....
$# echo '$ nix-shell -p ghc'
$# nix-shell -p ghc --command sh
$# echo '$ nix shell nixpkgs#ghc'
$# nix shell nixpkgs#ghc --command sh
$ runghc Main.hs
....
@ -77,8 +79,8 @@ Let's exit that shell and try again, this time adding the `hostname` package.
....
$# echo '$ exit'
$# echo '$ nix-shell -p "[ghc hostname]"'
$# nix-shell -p "[ghc hostname]" --command sh
$# echo '$ nix shell nixpkgs#ghc nixpkgs#hostname'
$# nix shell nixpkgs#ghc nixpkgs#hostname --command sh
$ runghc Main.hs
....
@ -91,39 +93,29 @@ Let's try that again, with the correct package.
....
$# echo '$ exit'
$# echo '$ nix-shell -p "[ghc haskellPackages.hostname]"'
$# nix-shell -p "[ghc haskellPackages.hostname]" --command sh
$# echo '$ nix shell nixpkgs#ghc nixpkgs#haskellPackages.hostname'
$# nix shell nixpkgs#ghc nixpkgs#haskellPackages.hostname --command sh
$ runghc Main.hs
....
Now what's wrong?
The syntax we used in the `nix-shell` command above is fine, but it doesn't make the package _available to GHC_!
The syntax we used in the `nix shell` command above is fine,
but it doesn't make the package _available to GHC_!
=== A suitable shell for a quick test
Consider the Haskell "pandoc" package, which provides both an executable (the Nix package `pandoc`)
and a library (the Nix package `haskellPackages.pandoc`).
There are several different shells we could create involving both Pandoc and GHC,
and it's important to understand the differences between them.
[cols="1,1"]
|===
|`nix-shell -p "[ghc pandoc]"`
|Makes the Pandoc _executable_ available at the command line, but the _library_ won't be visible to GHC.
|`nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ pandoc ])"`
|Makes the Pandoc _library_ visible to GHC, but we won't be able to run the _executable_.
|`nix-shell -p "[pandoc (haskellPackages.ghcWithPackages (pkgs: with pkgs; [ pandoc ]))]"`
|Makes the Pandoc _executable_ available at the command line, and the _library_ visible to GHC.
|===
Now we can create a shell that can run the program.
Now we will create a shell that can run the program.
When you need support for both a language and some of
its packages, it's best to use one of the Nix functions that are
specific to the programming language and build system.
For Haskell, we can use the `ghcWithPackages` function.
The command below is rather complex,
and a complete explanation would be rather lengthy.
[#haskell-nix-shell]
....
$# echo '$ nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ hostname ])"'
$# nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ hostname ])" --command sh
$# echo '$ nix shell --impure --expr '"'"'with import <nixpkgs> {}; haskellPackages.ghcWithPackages (p: [ p.hostname ])'"'"
$# nix shell --impure --expr 'with import <nixpkgs> {}; haskellPackages.ghcWithPackages (p: [ p.hostname ])' --command sh
$ runghc Main.hs
....
@ -133,14 +125,13 @@ Success! Now we know the program works.
$# echo '$ exit'
....
== The cabal file
It's time to write a Cabal file for this program.
This is just an ordinary Cabal file; we don't need to do anything special for Nix.
////
$ curl https://codeberg.org/mhwombat/hello-flake-haskell/raw/branch/main/hello-flake-haskell.cabal --silent --output hello-flake-haskell.cabal
$ cp ../hello-flake-haskell.cabal .
////
[source,cabal,linenums]
@ -149,55 +140,77 @@ $ curl https://codeberg.org/mhwombat/hello-flake-haskell/raw/branch/main/hello-f
$# cat hello-flake-haskell.cabal
....
== Building the program manually (optional)
== (Optional) Building and running with cabal-install
At this point, I would normally write `flake.nix` and use Nix to build the program.
I'll cover that in the next section.
However, it's useful to know how to build the package manually in a Nix environment,
without using a Nix flake.
When you're new to Nix, this can help you differentiate between problems in your flake definition
and problems in your Cabal file.
[NOTE]
====
In this section you will learn how to do some development tasks manually, the "hard" way.
This can help you understand the distinction between Nix's role and
the Haskell build system you've chosen.
Also, if you have a build problem but you're not sure if the fault is in
your flake definition or some other configuration file,
these commands can help you narrow it down.
But you may wish to skip to the <<haskell-flake,next section>>
and come back here later.
====
We won't write `flake.nix` just yet.
First we'll try building the package manually.
(If you didn't run the `nix shell` command from <<haskell-nix-shell,earlier>>, do so now.)
....
$ cabal build
....
Aha! We need `cabal-install` in our shell.
Rather than launch another shell-within-a-shell, let's exit create a new one.
The `cabal` command is provided by the `cabal-install` package.
The error happens because we don't have `cabal-install` available
in the temporary shell.
We can correct that.
....
$# echo '$ exit'
$# echo '$ nix-shell -p "[ cabal-install (haskellPackages.ghcWithPackages (pkgs: with pkgs; [ hostname ]))]"'
$# nix-shell -p "[ cabal-install (haskellPackages.ghcWithPackages (pkgs: with pkgs; [ hostname ]))]" --command sh
$ cabal build
$ cabal run
$# echo '$ exit'
$# echo '$ nix shell --impure --expr '"'"'with import <nixpkgs> {}; haskellPackages.ghcWithPackages (p: [ p.hostname p.cabal-install ])'"'"
$# nix shell --impure --expr 'with import <nixpkgs> {}; haskellPackages.ghcWithPackages (p: [ p.hostname p.cabal-install ])' --command sh
....
After some output messages, the build succeeds and the program runs.
Note that we're now inside a temporary shell inside the previous
temporary shell! To get back to the original shell, we have to `exit`
twice.
Alternatively, we could have done `exit` followed by the
second `nix-shell` command.
....
$# echo '$ cabal build'
$# echo ". . ."
$# cabal build |& tail -n 4
....
After a lot of output messages, the build succeeds.
[#haskell-flake]
== The Nix flake
Now we should write `flake.nix`. We already know how to write most of
the flake from the examples we did earlier. The two parts that would be
different are the development shell and the package builder.
Now we should write `flake.nix`.
We already know how to write most of the flake from the examples we did earlier.
The two parts that will be different are the development shell and the package builder.
However, there's a simpler way, using `haskell-flake`.
However, there's a _much_ simpler way, using `haskell-flake`.
The following command will create `flake.nix` based on their template.
////
$ curl https://codeberg.org/mhwombat/hello-flake-haskell/raw/branch/main/flake.nix --silent --output flake.nix
////
....
$ nix flake init -t github:srid/haskell-flake
....
[source,nix,linenums]
Examining the flake,
you'll notice that it is well-commented.
The only thing we need to change for now is the name in `packages.default`;
I've highlighted the change below.
[source,nix,linenums,highlight=55]
.flake.nix
....
$# sed -i 's/example/hello-flake-haskell/' flake.nix
$# cat flake.nix
....
The above definition will work for most of your haskell projects;
simply change the `description` and the package name in `packages.default`.
We also need a `LICENSE` file.
For now, this can be empty.
@ -205,25 +218,37 @@ For now, this can be empty.
$ touch LICENSE
....
== Building the program
Let's try out the new flake.
....
$ nix run
....
Why can't it find `flake.nix`? Nix flakes only "`see`" files that are
Nix flakes only "`see`" files that are
part of the repository. We need to add all of the important files to the
repo before building or running the flake.
....
$ git add flake.nix hello-flake-haskell.cabal LICENSE Main.hs
$ nix build
....
We'll deal with those warnings later.
The important thing for now is that the build succeeded.
== Running the program
Now we can run the program.
....
$ nix run
....
By the way, we didn't need to do `nix build` earlier.
The `nix run` command will first build the program for us if needed.
We'd like to share this package with others, but first we should do some
cleanup. When the package was built (automatically by the `nix run`
command), it created a `flake.lock` file. We need to add this to the
repo, and commit all important files.
cleanup.
It's time to deal with those warnings.
When the package was built, Nix created a `flake.lock` file.
We need to add this to the repo, and commit all important files.
....
$ git add flake.lock

View file

@ -22,6 +22,20 @@ $ curl https://codeberg.org/mhwombat/hello-flake-python/raw/branch/main/hello.py
$# cat hello.py
....
== Running the program manually (optional)
[NOTE]
====
In this section you will learn how to do some development tasks manually, the "hard" way.
This can help you understand the distinction between Nix's role and
the Python build system you've chosen.
Also, if you have a build problem but you're not sure if the fault is in
your flake definition or some other configuration file,
these commands can help you narrow it down.
But you may wish to skip to the <<_configuring_setuptools,next section>>
and come back here later.
====
Before we package the program, let's verify that it runs. We're going to
need Python. By now you've probably figured out that we can write a
`flake.nix` and define a development shell that includes Python. We'll
@ -34,31 +48,22 @@ packages you need), and you want to experiment a bit first.
The command to enter a temporary shell is
`nix-shell -p __packages__`
`nix shell -p __installables__`
If there are multiple packages, they should be separated by spaces.
[NOTE]
====
The command used here is `nix-shell` with a hyphen, not `nix shell`
with a space; those are two different commands. In fact there are
hyphenated and non-hyphenated versions of many Nix commands, and yes,
it's confusing. The non-hyphenated commands were introduced when support
for flakes was added to Nix. I predict that eventually all hyphenated
commands will be replaced with non-hyphenated versions. Until then, a
useful rule of thumb is that non-hyphenated commands are for for working
directly with flakes; hyphenated commands are for everything else.
====
Where __installables__ are flakes and other types of packages that you need.
(You can learn more about these in the
https://nix.dev/manual/nix/stable/command-ref/new-cli/nix#installables[Nix manual].)
Let's enter a shell with Python so we can test the program.
[#python-nix-shell]
....
$# echo '$ nix-shell -p python3'
$# nix-shell -p python3 --command sh
$# echo '$ nix shell nixpkgs#python3'
$# nix shell nixpkgs#python3 --command sh
$ python hello.py
....
== A Python builder
== Configuring setuptools
Next, create a Python script to build the package. We'll use Python's
setuptools, but you can use other build tools. For more information on
@ -78,9 +83,23 @@ $ curl https://codeberg.org/mhwombat/hello-flake-python/raw/branch/main/setup.py
$# cat setup.py
....
We won't write `flake.nix` just yet. First we'll try building the
package manually.
== Building the program manually (optional)
[NOTE]
====
In this section you will learn how to do some development tasks manually, the "hard" way.
This can help you understand the distinction between Nix's role and
the Python build system you've chosen.
Also, if you have a build problem but you're not sure if the fault is in
your flake definition or some other configuration file,
these commands can help you narrow it down.
But you may wish to skip to the <<python-flake,next section>>
and come back here later.
====
We won't write `flake.nix` just yet.
First we'll try building the package manually.
(If you didn't run the `nix shell` command from <<python-nix-shell,earlier>>, do so now.)
....
$ python -m build
....
@ -99,8 +118,9 @@ $# nix-shell -p "python3.withPackages (ps: with ps; [ build ])" --command sh
Note that we're now inside a temporary shell inside the previous
temporary shell! To get back to the original shell, we have to `exit`
twice. Alternatively, we could have done `exit` followed by the
`nix-shell` command.
twice.
Alternatively, we could have done `exit` followed by the
second `nix-shell` command.
....
$# echo '$ python -m build'
@ -109,11 +129,12 @@ $# python -m build > /dev/null 2>&1
After a lot of output messages, the build succeeds.
[#python-flake]
== The Nix flake
Now we should write `flake.nix`. We already know how to write most of
the flake from the examples we did earlier. The two parts that will be
different are the development shell and the package builder.
Now we should write `flake.nix`.
We already know how to write most of the flake from the examples we did earlier.
The two parts that will be different are the development shell and the package builder.
Let's start with the development shell. It seems logical to write
something like the following.
@ -172,10 +193,12 @@ $ curl https://codeberg.org/mhwombat/hello-flake-python/raw/branch/main/flake.ni
$# cat flake.nix
....
== Building the program
Let's try out the new flake.
....
$ nix run
$ nix build
....
Why can't it find `flake.nix`? Nix flakes only "`see`" files that are
@ -184,13 +207,28 @@ repo before building or running the flake.
....
$ git add flake.nix setup.py hello.py
$ nix build
....
We'll deal with those warnings later.
The important thing for now is that the build succeeded.
== Running the program
Now we can run the program.
....
$ nix run
....
By the way, we didn't need to do `nix build` earlier.
The `nix run` command will first build the program for us if needed.
We'd like to share this package with others, but first we should do some
cleanup. When the package was built (automatically by the `nix run`
command), it created a `flake.lock` file. We need to add this to the
repo, and commit all important files.
cleanup.
It's time to deal with those warnings.
When the package was built, Nix created a `flake.lock` file.
We need to add this to the repo, and commit all important files.
....
$ git add flake.lock

View file

@ -1,4 +1,14 @@
= From the command line
= From the command line (flake style)
....
$# echo '$ nix shell nixpkgs#hello nixpkgs#cowsay --command bash'
$# nix shell nixpkgs#hello nixpkgs#cowsay --command bash <<EOL
$ hello
$ cowsay "moo"
$# EOL
....
= From the command line (non-flake style)
....
$# echo '$ nix-shell -p "[hello cowsay]"'

View file

@ -1,4 +1,17 @@
= In a Bash script
= In a Bash script (flake style)
[source,bash,linenums]
.Script
....
include::my-flake-script.sh[]
....
.Output
....
$# ./my-flake-script.sh
....
= In a Bash script (non-flake style)
[source,bash,linenums]
.Script

View file

@ -1,3 +1,10 @@
= In `flake.nix`
See the example in <<_introducing_a_dependency>>
where defined a development shell in <<hello-flake-dependency,flake.nix>>
with a dependency on `cowsay` ,
and tested the shell.
= In `shell.nix`
[source,nix,linenums]

View file

@ -0,0 +1,54 @@
{
# See https://github.com/mhwombat/nix-for-numbskulls/blob/main/flakes.md
# for a brief overview of what each section in a flake should or can contain.
description = "a sample flake";
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; };
in
{
devShells = rec {
default = pkgs.mkShell {
packages = [ hello-nix ];
};
};
packages = rec {
hello = pkgs.stdenv.mkDerivation rec {
name = "hello-again";
src = ./.;
unpackPhase = "true";
buildPhase = ":";
installPhase =
''
mkdir -p $out/bin
cp $src/hello-again $out/bin/hello-again
chmod +x $out/bin/hello-again
'';
};
default = hello;
};
apps = rec {
hello = flake-utils.lib.mkApp { drv = self.packages.${system}.hello; };
default = hello;
};
}
);
}

View file

@ -0,0 +1,4 @@
#!/usr/bin/env sh
echo "I'm a flake, but I'm running a command defined in a non-flake package."
hello-nix

View file

@ -1,6 +1,6 @@
= Access to a package defined in a remote git repo
Ex: Access a package called `hello-nix`,
Ex: Access a package (not a flake) called `hello-nix`,
which is defined in a remote git repo on codeberg.
To use a package from GitHub, GitLab, or any other public platform,
modify the URL.

File diff suppressed because it is too large Load diff