clan-vm-manager: Working pytest skeleton. clan-cli: Fixing devshell depending on itself
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
source_up
|
||||
# BUG: If this is enabled the devshell depends on clan_cli building successfully
|
||||
# source_up
|
||||
|
||||
watch_file flake-module.nix default.nix
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from typing import Any
|
||||
|
||||
from clan_cli.clan_uri import ClanURI, MachineData
|
||||
from clan_cli.dirs import vm_state_dir
|
||||
from qemu.qmp import QEMUMonitorProtocol
|
||||
from clan_cli.qemu.qmp import QEMUMonitorProtocol
|
||||
|
||||
from ..cmd import run
|
||||
from ..errors import ClanError
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
# Inputs for the package
|
||||
age,
|
||||
lib,
|
||||
argcomplete,
|
||||
@@ -10,14 +11,11 @@
|
||||
pytest-xdist,
|
||||
pytest-subprocess,
|
||||
pytest-timeout,
|
||||
remote-pdb,
|
||||
ipdb,
|
||||
python3,
|
||||
runCommand,
|
||||
setuptools,
|
||||
sops,
|
||||
stdenv,
|
||||
wheel,
|
||||
fakeroot,
|
||||
rsync,
|
||||
bash,
|
||||
@@ -30,33 +28,15 @@
|
||||
gnupg,
|
||||
e2fsprogs,
|
||||
mypy,
|
||||
rope,
|
||||
clan-core-path,
|
||||
}:
|
||||
let
|
||||
|
||||
dependencies = [
|
||||
argcomplete # optional dependency: if not enabled, shell completion will not work
|
||||
# Dependencies that are directly used in the project
|
||||
pythonDependencies = [
|
||||
argcomplete # Enables shell completion; without it, this feature won't work.
|
||||
];
|
||||
|
||||
pytestDependencies =
|
||||
runtimeDependencies
|
||||
++ dependencies
|
||||
++ [
|
||||
pytest
|
||||
pytest-cov
|
||||
pytest-subprocess
|
||||
pytest-xdist
|
||||
pytest-timeout
|
||||
remote-pdb
|
||||
ipdb
|
||||
openssh
|
||||
git
|
||||
gnupg
|
||||
stdenv.cc
|
||||
];
|
||||
|
||||
# Optional dependencies for clan cli, we re-expose them here to make sure they all build.
|
||||
# Runtime dependencies required by the application
|
||||
runtimeDependencies = [
|
||||
bash
|
||||
nix
|
||||
@@ -74,14 +54,31 @@ let
|
||||
e2fsprogs
|
||||
];
|
||||
|
||||
# Dependencies required for running tests
|
||||
testDependencies =
|
||||
runtimeDependencies
|
||||
++ [
|
||||
gnupg
|
||||
stdenv.cc # Compiler used for certain native extensions
|
||||
]
|
||||
++ pythonDependencies
|
||||
++ [
|
||||
pytest # Testing framework
|
||||
pytest-cov # Generate coverage reports
|
||||
pytest-subprocess # fake the real subprocess behavior to make your tests more independent.
|
||||
pytest-xdist # Run tests in parallel on multiple cores
|
||||
pytest-timeout # Add timeouts to your tests
|
||||
];
|
||||
|
||||
# Convert runtimeDependencies into an attribute set for easier access
|
||||
runtimeDependenciesAsSet = builtins.listToAttrs (
|
||||
builtins.map (p: lib.nameValuePair (lib.getName p.name) p) runtimeDependencies
|
||||
);
|
||||
|
||||
checkPython = python3.withPackages (_ps: pytestDependencies);
|
||||
# Setup Python environment with all dependencies for running tests
|
||||
pythonWithTestDeps = python3.withPackages (_ps: testDependencies);
|
||||
|
||||
# - vendor the jsonschema nix lib (copy instead of symlink).
|
||||
# Interesting fact: using nixpkgs from flakes instead of nixpkgs.path is reduces evaluation time by 5s.
|
||||
# Prepare the source code for the project, including copying over jsonschema and nixpkgs
|
||||
source = runCommand "clan-cli-source" { } ''
|
||||
cp -r ${./.} $out
|
||||
chmod -R +w $out
|
||||
@@ -89,6 +86,8 @@ let
|
||||
ln -s ${nixpkgs'} $out/clan_cli/nixpkgs
|
||||
cp -r ${../../lib/jsonschema} $out/clan_cli/config/jsonschema
|
||||
'';
|
||||
|
||||
# Create a custom nixpkgs for use within the project
|
||||
nixpkgs' = runCommand "nixpkgs" { nativeBuildInputs = [ nix ]; } ''
|
||||
mkdir $out
|
||||
cat > $out/flake.nix << EOF
|
||||
@@ -114,36 +113,36 @@ python3.pkgs.buildPythonApplication {
|
||||
src = source;
|
||||
format = "pyproject";
|
||||
|
||||
makeWrapperArgs = [
|
||||
# This prevents problems with mixed glibc versions that might occur when the
|
||||
# cli is called through a browser built against another glibc
|
||||
"--unset LD_LIBRARY_PATH"
|
||||
];
|
||||
# Arguments for the wrapper to unset LD_LIBRARY_PATH to avoid glibc version issues
|
||||
makeWrapperArgs = [ "--unset LD_LIBRARY_PATH" ];
|
||||
|
||||
# Build-time dependencies.
|
||||
nativeBuildInputs = [
|
||||
setuptools
|
||||
installShellFiles
|
||||
];
|
||||
propagatedBuildInputs = dependencies;
|
||||
|
||||
# also re-expose dependencies so we test them in CI
|
||||
propagatedBuildInputs = pythonDependencies;
|
||||
|
||||
# Define and expose the tests and checks to run in CI
|
||||
passthru.tests =
|
||||
(lib.mapAttrs' (n: lib.nameValuePair "clan-dep-${n}") runtimeDependenciesAsSet)
|
||||
// rec {
|
||||
clan-pytest-without-core =
|
||||
runCommand "clan-pytest-without-core" { nativeBuildInputs = [ checkPython ] ++ pytestDependencies; }
|
||||
runCommand "clan-pytest-without-core"
|
||||
{ nativeBuildInputs = [ pythonWithTestDeps ] ++ testDependencies; }
|
||||
''
|
||||
cp -r ${source} ./src
|
||||
chmod +w -R ./src
|
||||
cd ./src
|
||||
|
||||
export NIX_STATE_DIR=$TMPDIR/nix IN_NIX_SANDBOX=1
|
||||
${checkPython}/bin/python -m pytest -m "not impure and not with_core" ./tests
|
||||
${pythonWithTestDeps}/bin/python -m pytest -m "not impure and not with_core" ./tests
|
||||
touch $out
|
||||
'';
|
||||
# separate the tests that can never be cached
|
||||
clan-pytest-with-core =
|
||||
runCommand "clan-pytest-with-core" { nativeBuildInputs = [ checkPython ] ++ pytestDependencies; }
|
||||
runCommand "clan-pytest-with-core"
|
||||
{ nativeBuildInputs = [ pythonWithTestDeps ] ++ testDependencies; }
|
||||
''
|
||||
cp -r ${source} ./src
|
||||
chmod +w -R ./src
|
||||
@@ -151,15 +150,11 @@ python3.pkgs.buildPythonApplication {
|
||||
|
||||
export CLAN_CORE=${clan-core-path}
|
||||
export NIX_STATE_DIR=$TMPDIR/nix IN_NIX_SANDBOX=1
|
||||
${checkPython}/bin/python -m pytest -m "not impure and with_core" ./tests
|
||||
${pythonWithTestDeps}/bin/python -m pytest -m "not impure and with_core" ./tests
|
||||
touch $out
|
||||
'';
|
||||
|
||||
clan-pytest = runCommand "clan-pytest" { } ''
|
||||
echo ${clan-pytest-without-core}
|
||||
echo ${clan-pytest-with-core}
|
||||
touch $out
|
||||
'';
|
||||
# Utility to check for leftover debugging breakpoints in the codebase
|
||||
check-for-breakpoints = runCommand "breakpoints" { } ''
|
||||
if grep --include \*.py -Rq "breakpoint()" ${source}; then
|
||||
echo "breakpoint() found in ${source}:"
|
||||
@@ -170,18 +165,13 @@ python3.pkgs.buildPythonApplication {
|
||||
'';
|
||||
};
|
||||
|
||||
# Additional pass-through attributes
|
||||
passthru.nixpkgs = nixpkgs';
|
||||
passthru.checkPython = checkPython;
|
||||
|
||||
passthru.devDependencies = [
|
||||
rope
|
||||
setuptools
|
||||
wheel
|
||||
] ++ pytestDependencies;
|
||||
|
||||
passthru.pytestDependencies = pytestDependencies;
|
||||
passthru.testDependencies = testDependencies;
|
||||
passthru.pythonWithTestDeps = pythonWithTestDeps;
|
||||
passthru.runtimeDependencies = runtimeDependencies;
|
||||
|
||||
# Install shell completions for bash and fish using the argcomplete package
|
||||
postInstall = ''
|
||||
cp -r ${nixpkgs'} $out/${python3.sitePackages}/clan_cli/nixpkgs
|
||||
installShellCompletion --bash --name clan \
|
||||
@@ -189,13 +179,17 @@ python3.pkgs.buildPythonApplication {
|
||||
installShellCompletion --fish --name clan.fish \
|
||||
<(${argcomplete}/bin/register-python-argcomplete --shell fish clan)
|
||||
'';
|
||||
# Don't leak python packages into a devshell.
|
||||
# It can be very confusing if you `nix run` then load the cli from the devshell instead.
|
||||
|
||||
# Clean up after the package to avoid leaking python packages into a devshell
|
||||
postFixup = ''
|
||||
rm $out/nix-support/propagated-build-inputs
|
||||
'';
|
||||
|
||||
# Run a basic check to ensure the application is executable
|
||||
checkPhase = ''
|
||||
PYTHONPATH= $out/bin/clan --help
|
||||
'';
|
||||
|
||||
# Specify the main program for this package
|
||||
meta.mainProgram = "clan";
|
||||
}
|
||||
|
||||
@@ -1,59 +1,29 @@
|
||||
{
|
||||
nix-unit,
|
||||
clan-cli,
|
||||
system,
|
||||
mkShell,
|
||||
writeScriptBin,
|
||||
openssh,
|
||||
ruff,
|
||||
python3,
|
||||
}:
|
||||
let
|
||||
checkScript = writeScriptBin "check" ''
|
||||
nix build .#checks.${system}.{treefmt,clan-pytest} -L "$@"
|
||||
'';
|
||||
|
||||
pythonWithDeps = python3.withPackages (
|
||||
ps: clan-cli.propagatedBuildInputs ++ clan-cli.devDependencies ++ [ ps.pip ]
|
||||
);
|
||||
devshellTestDeps =
|
||||
clan-cli.passthru.testDependencies
|
||||
++ (with python3.pkgs; [
|
||||
rope
|
||||
setuptools
|
||||
wheel
|
||||
pip
|
||||
]);
|
||||
in
|
||||
mkShell {
|
||||
packages = [
|
||||
buildInputs = [
|
||||
nix-unit
|
||||
openssh
|
||||
ruff
|
||||
clan-cli.checkPython
|
||||
];
|
||||
] ++ devshellTestDeps;
|
||||
|
||||
shellHook = ''
|
||||
tmp_path=$(realpath ./.direnv)
|
||||
|
||||
repo_root=$(realpath .)
|
||||
mkdir -p "$tmp_path/python/${pythonWithDeps.sitePackages}"
|
||||
|
||||
# Install the package in editable mode
|
||||
# This allows executing `clan` from within the dev-shell using the current
|
||||
# version of the code and its dependencies.
|
||||
${pythonWithDeps.interpreter} -m pip install \
|
||||
--quiet \
|
||||
--disable-pip-version-check \
|
||||
--no-index \
|
||||
--no-build-isolation \
|
||||
--prefix "$tmp_path/python" \
|
||||
--editable $repo_root
|
||||
export PATH=$(pwd)/bin:$PATH
|
||||
|
||||
ln -sfT ${clan-cli.nixpkgs} clan_cli/nixpkgs
|
||||
|
||||
export PATH="$tmp_path/python/bin:${checkScript}/bin:$PATH"
|
||||
export PYTHONPATH="$repo_root:$tmp_path/python/${pythonWithDeps.sitePackages}:"
|
||||
|
||||
export XDG_DATA_DIRS="$tmp_path/share''${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}"
|
||||
export fish_complete_path="$tmp_path/share/fish/vendor_completions.d''${fish_complete_path:+:$fish_complete_path}"
|
||||
mkdir -p \
|
||||
$tmp_path/share/fish/vendor_completions.d \
|
||||
$tmp_path/share/bash-completion/completions \
|
||||
$tmp_path/share/zsh/site-functions
|
||||
register-python-argcomplete --shell fish clan > $tmp_path/share/fish/vendor_completions.d/clan.fish
|
||||
register-python-argcomplete --shell bash clan > $tmp_path/share/bash-completion/completions/clan
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), "helpers"))
|
||||
sys.path.append(str(Path(__file__).parent.parent)) # Also add clan_cli to PYTHONPATH
|
||||
|
||||
|
||||
from clan_cli.custom_logger import setup_logging
|
||||
from clan_cli.nix import nix_shell
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), "helpers"))
|
||||
|
||||
pytest_plugins = [
|
||||
"temporary_dir",
|
||||
"root",
|
||||
|
||||
@@ -12,8 +12,8 @@ from fixtures_flakes import FlakeForTest, generate_flake
|
||||
from root import CLAN_CORE
|
||||
|
||||
from clan_cli.dirs import vm_state_dir
|
||||
from qemu.qga import QgaSession
|
||||
from qemu.qmp import QEMUMonitorProtocol
|
||||
from clan_cli.qemu.qga import QgaSession
|
||||
from clan_cli.qemu.qmp import QEMUMonitorProtocol
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from age_keys import KeyPair
|
||||
|
||||
Reference in New Issue
Block a user