Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite disko in Python #902

Draft
wants to merge 37 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b102aeb
disko2: Set up dev environment for python
iFreilicht Oct 28, 2024
b752b83
disko2: Set up basic argument parsing
iFreilicht Oct 28, 2024
8cf1486
dev: Add mypy type checker
iFreilicht Oct 29, 2024
db29851
dev: Add vscode launch config for disko2
iFreilicht Oct 29, 2024
ffa1b89
disko2: Add basic logging setup
iFreilicht Oct 29, 2024
d4a944c
disko2: Add --verbose,-v flag
iFreilicht Oct 29, 2024
88a8541
disko2: Make Result generic over the value it contains
iFreilicht Oct 29, 2024
ed50604
dev: Add autoflake to remove unused imports automatically
iFreilicht Oct 29, 2024
8acd249
disko2: Add evaluation for configs and flakes
iFreilicht Oct 29, 2024
e825c64
disko2: Implement rudimentary generate mode
iFreilicht Oct 30, 2024
5da5781
disko2: Add dev subcommand
iFreilicht Oct 30, 2024
389235b
disko2: Create package
iFreilicht Oct 30, 2024
737e045
tests: Move example tests to dedicated folder
iFreilicht Oct 31, 2024
fb5e63a
dev: Add vscode settings for nixd and cSpell
iFreilicht Oct 31, 2024
0cd9490
disko2: Add test for generate_config
iFreilicht Oct 31, 2024
4db452e
disko2: Fix entrypoints
iFreilicht Nov 3, 2024
a6944c6
disko2: Make messages type-safe and modular
iFreilicht Nov 3, 2024
c5da562
dev: Move colors to constants
iFreilicht Nov 3, 2024
fa44467
disko2: Refactor dev mode, add disko dev eval
iFreilicht Nov 3, 2024
0d54c7a
disko2: Make generate write output to nix file
iFreilicht Nov 4, 2024
da8a997
dev: Switch to ruff for python linting & formatting
iFreilicht Nov 7, 2024
963b49d
lib: Add dict_diff
iFreilicht Nov 8, 2024
6b360a2
tests: Add simple tests for eval_config.py
iFreilicht Nov 8, 2024
c5d1a42
tests: Put tests with snapshots into directories
iFreilicht Nov 8, 2024
b30e5ce
disko2 dev: Print better error message
iFreilicht Nov 8, 2024
4f16850
lib: Detect and show new keys in dict_diff
iFreilicht Nov 10, 2024
70efb0a
lib: Evaluate partition's _index parameter
iFreilicht Nov 10, 2024
2bd9c4f
dev,docs: Improve and document DX with Python
iFreilicht Nov 10, 2024
a5c646b
lib: Fix jsonTypes evaluation
iFreilicht Nov 12, 2024
d382a3c
tests: Make mypy a lot stricter
iFreilicht Nov 15, 2024
08ec11a
lib: Fix jsonTypes evaluation
iFreilicht Nov 12, 2024
a0e8f7f
disko2: Add code generator for disko config type
iFreilicht Nov 14, 2024
ae7891e
disko2: Fix all mypy type checking errors
iFreilicht Nov 17, 2024
6651792
disko2: Validate config for type-safety in python
iFreilicht Nov 17, 2024
cfcc518
disko2: Add rudimentary plan generation
iFreilicht Nov 25, 2024
db57281
disko2: Fix dedenting bug
iFreilicht Nov 27, 2024
59edac4
disko2: Add jupyter notebook for experiments and debugging
iFreilicht Nov 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use flake
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
result

disko-config.nix

.direnv

__pycache__/

# Created by the NixOS interactive test driver
.nixos-test-history
11 changes: 11 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"recommendations": [
"mkhl.direnv",
"jnoortheen.nix-ide",
"ms-python.python",
"ms-python.debugpy",
"ms-python.mypy-type-checker",
"charliermarsh.ruff",
"ms-toolsai.jupyter"
]
}
65 changes: 65 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "disko2 mount disko_file",
"type": "debugpy",
"request": "launch",
"module": "disko",
"env": {
"PYTHONPATH": "${workspaceFolder}/src"
},
"console": "integratedTerminal",
"args": [
"mount",
"example/simple-efi.nix"
]
},
{
"name": "disko2 mount flake",
"type": "debugpy",
"request": "launch",
"module": "disko",
"env": {
"PYTHONPATH": "${workspaceFolder}/src"
},
"console": "integratedTerminal",
"args": [
"mount",
"--flake",
".#testmachine"
]
},
{
"name": "disko2 generate",
"type": "debugpy",
"request": "launch",
"module": "disko",
"env": {
"PYTHONPATH": "${workspaceFolder}/src"
},
"console": "integratedTerminal",
"args": [
"generate"
]
},
{
"name": "disko2 destroy,format,mount dry-run",
"type": "debugpy",
"request": "launch",
"module": "disko",
"env": {
"PYTHONPATH": "${workspaceFolder}/src"
},
"console": "integratedTerminal",
"args": [
"destroy,format,mount",
"--dry-run",
"disko-config.nix"
]
}
]
}
27 changes: 27 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"nix.serverSettings": {
"nixd": {
"formatting": {
"command": [
"nixpkgs-fmt",
"--"
]
}
}
},
"cSpell.enabled": true,
"cSpell.words": [
"Disko",
"nixos",
"nixpkgs"
],
"python.analysis.extraPaths": [
"./src"
],
"mypy-type-checker.importStrategy": "fromEnvironment",
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
3 changes: 3 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ way to help us fix issues quickly. Check out
For more information on how to run and debug tests, check out
[Running and debugging tests](./docs/testing.md).

Also refer to [Setting up your development environment](./dev-setup.md) to get
the best possible development experience.

## How to find issues to work on

If you're looking for a low-hanging fruit, check out
Expand Down
42 changes: 3 additions & 39 deletions default.nix
Original file line number Diff line number Diff line change
@@ -1,44 +1,8 @@
{ lib ? import <nixpkgs/lib>
, rootMountPoint ? "/mnt"
, checked ? false
, diskoLib ? import ./lib { inherit lib rootMountPoint; }
, diskoLib ? import ./src/disko_lib { inherit lib rootMountPoint; }
}:
let
eval = cfg: lib.evalModules {
modules = lib.singleton {
# _file = toString input;
imports = lib.singleton { disko.devices = cfg.disko.devices; };
options = {
disko.devices = lib.mkOption {
type = diskoLib.toplevel;
};
};
};
};
in
{
lib = lib.warn "the .lib.lib output is deprecated" diskoLib;

# legacy alias
create = cfg: builtins.trace "the create output is deprecated, use format instead" (eval cfg).config.disko.devices._create;
createScript = cfg: pkgs: builtins.trace "the create output is deprecated, use format instead" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript;
createScriptNoDeps = cfg: pkgs: builtins.trace "the create output is deprecated, use format instead" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps;

format = cfg: (eval cfg).config.disko.devices._create;
formatScript = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript;
formatScriptNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps;

mount = cfg: (eval cfg).config.disko.devices._mount;
mountScript = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScript;
mountScriptNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScriptNoDeps;

disko = cfg: (eval cfg).config.disko.devices._disko;
diskoScript = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScript;
diskoScriptNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps;

# we keep this old output for backwards compatibility
diskoNoDeps = cfg: pkgs: builtins.trace "the diskoNoDeps output is deprecated, please use disko instead" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps;

config = cfg: (eval cfg).config.disko.devices._config;
packages = cfg: (eval cfg).config.disko.devices._packages;
diskoLib.outputs {
inherit lib checked rootMountPoint;
}
2 changes: 1 addition & 1 deletion disko
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ else
fi

# The "--impure" is still pure, as the path is within the nix store.
script=$(nixBuild "${libexec_dir}"/cli.nix \
script=$(nixBuild "${libexec_dir}"/src/cli.nix \
--no-out-link \
--impure \
--argstr mode "$mode" \
Expand Down
2 changes: 1 addition & 1 deletion disko-install
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ main() {
# shellcheck disable=SC2064
trap "cleanupMountPoint ${escapeMountPoint}" EXIT

outputs=$(nixBuild "${libexec_dir}"/install-cli.nix \
outputs=$(nixBuild "${libexec_dir}"/src/install-cli.nix \
"${nix_args[@]}" \
--no-out-link \
--impure \
Expand Down
7 changes: 7 additions & 0 deletions disko2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
# This script only exists so you can run `./disko2` directly
# It should not be be installed as part of the package!
# Check src/disko/cli.py for the actual entrypoint

set -euo pipefail
PYTHONPATH="$(dirname "$(realpath "$0")")"/src python3 -m disko "$@"
2 changes: 1 addition & 1 deletion doc.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{ lib, nixosOptionsDoc, runCommand, fetchurl, pandoc }:

let
diskoLib = import ./lib {
diskoLib = import ./src/disko_lib {
inherit lib;
rootMountPoint = "/mnt";
};
Expand Down
1 change: 1 addition & 0 deletions docs/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@

### For contributors

- [Setting up your development environment](./dev-setup.md)
- [Running and debugging tests](./testing.md)
75 changes: 75 additions & 0 deletions docs/dev-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Setting up your development environment

**This guide assumes you have flakes enabled.**

disko uses Nix flake's `devShells` output and [direnv](https://direnv.net/) to
set up the development environment in two ways.

The quickest way to get started is to run:

```
nix develop
```

However, if you use a shell other than bash, working inside `nix develop` might
get annoying quickly. An alternative is to use direnv, which sets up the
environment in your current shell session:

```console
# nix shell nixpkgs#direnv
direnv: error /home/felix/repos-new/temp/disko/.envrc is blocked. Run `direnv allow` to approve its content
# direnv allow
direnv: loading ~/repos-new/temp/disko/.envrc
direnv: using flake
direnv: export +AR +AS +CC +CONFIG_SHELL +CXX +HOST_PATH +IN_NIX_SHELL +LD +NIX_BINTOOLS +NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_BUILD_CORES +NIX_BUILD_TOP +NIX_CC +NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_CFLAGS_COMPILE +NIX_ENFORCE_NO_NATIVE +NIX_HARDENING_ENABLE +NIX_LDFLAGS +NIX_STORE +NM +OBJCOPY +OBJDUMP +RANLIB +READELF +SIZE +SOURCE_DATE_EPOCH +STRINGS +STRIP +TEMP +TEMPDIR +TMP +TMPDIR +__structuredAttrs +buildInputs +buildPhase +builder +cmakeFlags +configureFlags +depsBuildBuild +depsBuildBuildPropagated +depsBuildTarget +depsBuildTargetPropagated +depsHostHost +depsHostHostPropagated +depsTargetTarget +depsTargetTargetPropagated +doCheck +doInstallCheck +dontAddDisableDepTrack +mesonFlags +name +nativeBuildInputs +out +outputs +patches +phases +preferLocalBuild +propagatedBuildInputs +propagatedNativeBuildInputs +shell +shellHook +stdenv +strictDeps +system ~PATH ~XDG_DATA_DIRS
```

You can now run `./disko2 dev --help` or `pytest` to confirm everything is working.

If you're working exclusively in the terminal, you're all set.

## IDE Integration

### VSCode

If you're using VSCode or any of its forks, you should install the recommended
extensions. You can find them in .vscode/extensions.json, searching for
`@recommended` in the Extensions Panel, or by opening the
command pallette and searching "Show Recommended Extensions".

You can then install all extensions in one click:

![VSCode button "Install workspace recommended extensions](./img/vscode-recommended-ext.png)

When you do this (and every time you open the repository again), the
[direnv extension](https://marketplace.visualstudio.com/items?itemName=mkhl.direnv)
will prompt you in the bottom right corner to restart all extensions once it
has loaded the development environment:

![Direnv extension asking "Environment updated. Restart extensions?"](./img/vscode-direnv-prompt.png)

Click "Restart" to make all dependencies available to VSCode.

Afterwards, open the command pallette, search "Python: Select Interpreter" and
press Enter. The "Select Interpreter" dialog will open:

![VSCode Python "Select Interpreter" dialog](./img/vscode-select-python.png)

Do not select the interpreters tagged "Recommended" or "Global"! These will be
the ones installed on your system or currently selected in the extension.
Instead, pick one of the ones below them, this will be the latest available
package that includes the python packages specified in the `devShell`!

Now you're all set! You might want to also enable the "Format on Save" settings
and run the "Format Document" command once to select a formatter for each file
type.

Remember to go through these steps again whenever updating the flake.

### Other IDEs

These are just notes. Feel free to submit a PR that adds support and
documentation for other IDEs!

[Jetbrains Marketplace has two direnv extensions available](https://plugins.jetbrains.com/search?excludeTags=internal&search=direnv)

Binary file added docs/img/vscode-direnv-prompt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/vscode-recommended-ext.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/vscode-select-python.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

We are currently having issues being able to generate proper module option
documentation for our recursive disko types. However you can read the available
options [here](https://github.com/nix-community/disko/tree/master/lib/types).
options [here](https://github.com/nix-community/disko/tree/master/src/disko_lib/types).
Combined with the
[examples](https://github.com/nix-community/disko/tree/master/example) this
hopefully gives you an overview.
Expand Down
25 changes: 20 additions & 5 deletions docs/testing.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
# Running and debugging tests

This assumes you've already set up your development environment!

See [Setting up your development environment](./dev-setup.md)

## Python tests

Big parts of disko are written in Python. You can test all Python
functionality by simply running

```
pytest
```

## VM tests

Disko makes extensive use of VM tests. All examples you can find in
[the example directory](../example) have a respective test suite that verifies
the example is working in [the tests directory](../tests/). They utilize the
[NixOS test functionality](https://nixos.org/manual/nixos/stable/#sec-nixos-tests).

We use a wrapper around this called `makeDiskoTest`. There is currently (as of
2024-10-16) no documentation for all its arguments, but you can have a look at
[its current code](https://github.com/nix-community/disko/blob/master/lib/tests.nix#L44C5-L58C10),
[its current code](https://github.com/nix-community/disko/blob/master/src/disko_lib/tests.nix#L44C5-L58C10),
that should already be helpful.

However, you don't need to know about all of the inner workings to interact with
the tests effectively. For some of the most common operations, see the sections
below.

## Run just one of the tests
### Run just one of the tests

```sh
nix build --no-link .#checks.x86_64-linux.simple-efi
Expand All @@ -27,7 +42,7 @@ virtual devices, run disko to format them, reboot, verify the VM boots properly,
and then run the code specified in `extraTestScript` to validate that the
partitions have been created and were mounted as expected.

### How `extraTestScript` works
#### How `extraTestScript` works

This is written in Python. The most common lines you'll see look something like
this:
Expand All @@ -45,7 +60,7 @@ Disko currently (as of 2024-10-16) doesn't have any tests that utilize multiple
VMs at once, so the only machine available in these scripts is always just the
default `machine`.

## Debugging tests
### Debugging tests

If you make changes to disko, you might break a test, or you may want to modify
a test to prevent regressions. In these cases, running the full test with
Expand Down Expand Up @@ -131,7 +146,7 @@ vdb 253:16 0 4G 0 disk
You can find some additional details in
[the NixOS manual's section on interactive testing](https://nixos.org/manual/nixos/stable/#sec-running-nixos-tests-interactively).

## Running all tests at once
### Running all tests at once

If you have a bit of experience, you might be inclined to run `nix flake check`
to run all tests at once. However, we instead recommend using
Expand Down
Loading