Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
213 changes: 11 additions & 202 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";

hooks = {
url = "github:cachix/git-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
Expand Down Expand Up @@ -32,217 +33,25 @@
outputs = {
uv,
self,
hooks,
nixpkgs,
pyproject,
build-systems,
...
}: let
inherit (nixpkgs) lib;

getPythonVersion = let
val = builtins.getEnv "PYTHON_VERSION";
result =
if val == ""
then "3.13"
else val;
in
builtins.replaceStrings ["."] [""] result;
inherit (import ./nix/helpers.nix {inherit self nixpkgs overlay;}) forAllSystems;

workspace = uv.lib.workspace.loadWorkspace {workspaceRoot = ./.;};
overlay = workspace.mkPyprojectOverlay {sourcePreference = "wheel";};

forAllSystems = f:
lib.genAttrs [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
] (system:
f rec {
inherit system;

pkgs = nixpkgs.legacyPackages.${system};
python = pkgs."python${getPythonVersion}";

pythonSet =
(pkgs.callPackage pyproject.build.packages {inherit python;}).overrideScope (
lib.composeManyExtensions [
build-systems.overlays.default
overlay
]
);
importWithAttrs = path:
forAllSystems (attrs:
import path {
inherit workspace self lib;
inherit (attrs) pkgs system python pythonSet;
});
in {
devShells =
forAllSystems ({
pkgs,
system,
python,
pythonSet,
...
}: let
check = self.checks.${system}.pre-commit;
in {
default = let
editableOverlay =
workspace.mkEditablePyprojectOverlay {
root = "$REPO_ROOT";
};

editablePythonSet =
pythonSet.overrideScope (
lib.composeManyExtensions [
editableOverlay

(final: prev: {
proselint =
prev.proselint.overrideAttrs (old: {
nativeBuildInputs =
old.nativeBuildInputs
++ final.resolveBuildSystem {
editables = [];
};
});
})

(final: prev: {
google-re2 =
prev.google-re2.overrideAttrs (old: {
nativeBuildInputs =
(old.nativeBuildInputs or [])
++ (with final; [setuptools pybind11])
++ (with pkgs; [re2 abseil-cpp]);
});
})
]
);

virtualenv = editablePythonSet.mkVirtualEnv "proselint-env" {proselint = ["test" "dev" "web"];};
in
pkgs.mkShell {
buildInputs = check.enabledPackages;

packages = [
virtualenv
pkgs.git-cliff
pkgs.typos
pkgs.uv
];

env = {
UV_NO_SYNC = "1";
UV_PYTHON = python.interpreter;
UV_PYTHON_DOWNLOADS = "never";
LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib";
};

shellHook =
''
export REPO_ROOT=$(git rev-parse --show-toplevel)
unset PYTHONPATH
''
+ check.shellHook;
};
});

packages =
forAllSystems ({
pythonSet,
pkgs,
...
}: {
default = pythonSet.mkVirtualEnv "proselint-env" workspace.deps.default;

wheel =
pythonSet.proselint.override {
pyprojectHook = pythonSet.pyprojectDistHook;
};

sdist =
(pythonSet.proselint.override {
pyprojectHook = pythonSet.pyprojectDistHook;
}).overrideAttrs (old: {
env.uvBuildType = "sdist";
});

api = let
env =
pythonSet.mkVirtualEnv "proselint-api-env" {
proselint = ["web"];
};
in
pkgs.stdenv.mkDerivation {
name = "proselint-api";
src = ./.;

dontBuild = true;
dontConfigure = true;

installPhase = ''
mkdir -p $out/bin $out/share/proselint-api

cp $src/app.py $out/share/proselint-api

cat > $out/bin/proselint-api-run <<-EOF
#!${pkgs.bash}/bin/bash
cd $out/share/proselint-api
exec ${env}/bin/uvicorn app:app "\$@"
EOF

chmod +x $out/bin/proselint-api-run
'';
};
});

apps =
forAllSystems ({system, ...}: {
default = {
type = "app";
program = "${self.packages.${system}.default}/bin/proselint";
};

api = {
type = "app";
program = "${self.packages.${system}.api}/bin/proselint-api-run";
};
});

checks =
forAllSystems ({
system,
pkgs,
...
}: {
pre-commit =
hooks.lib.${system}.run {
src = ./.;
package = pkgs.prek;

hooks = {
trim-trailing-whitespace.enable = true;
end-of-file-fixer.enable = true;
mixed-line-endings.enable = true;
markdownlint.enable = true;

ruff.enable = true;
pyright = let
pyright = pkgs.basedpyright;
in {
enable = true;
package = pyright;
entry = "${pyright}/bin/basedpyright";
};

convco.enable = true;

alejandra.enable = true;
statix = {
enable = true;
settings.ignore = ["/.direnv"];
};
};
};
});
devShells = importWithAttrs ./nix/dev-shells.nix;
packages = importWithAttrs ./nix/packages.nix;
checks = importWithAttrs ./nix/checks.nix;
apps = importWithAttrs ./nix/apps.nix;
};
}
16 changes: 16 additions & 0 deletions nix/apps.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
lib,
self,
system,
...
}: {
default = {
type = "app";
program = lib.getExe' self.packages.${system}.default "proselint";
};

api = {
type = "app";
program = lib.getExe' self.packages.${system}.api "proselint-api-run";
};
}
34 changes: 34 additions & 0 deletions nix/checks.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
lib,
self,
pkgs,
system,
...
}: {
pre-commit =
self.inputs.hooks.lib.${system}.run {
src = ./.;
package = pkgs.prek;

hooks = {
trim-trailing-whitespace.enable = true;
end-of-file-fixer.enable = true;
mixed-line-endings.enable = true;
markdownlint.enable = true;
alejandra.enable = true;
convco.enable = true;
ruff.enable = true;

statix = {
enable = true;
settings.ignore = ["/.direnv"];
};

pyright = {
enable = true;
package = pkgs.basedpyright;
entry = lib.getExe pkgs.basedpyright;
};
};
};
}
66 changes: 66 additions & 0 deletions nix/dev-shells.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
workspace,
self,
lib,
system,
pkgs,
python,
pythonSet,
}: let
check = self.checks.${system}.pre-commit;

editablePythonSet =
pythonSet.overrideScope (
lib.composeManyExtensions [
(workspace.mkEditablePyprojectOverlay {root = "$REPO_ROOT";})

(final: prev: {
proselint =
prev.proselint.overrideAttrs (old: {
nativeBuildInputs =
old.nativeBuildInputs
++ final.resolveBuildSystem {
editables = [];
};
});
})

(final: prev: {
google-re2 =
prev.google-re2.overrideAttrs (old: {
nativeBuildInputs =
(old.nativeBuildInputs or [])
++ (with final; [setuptools pybind11])
++ (with pkgs; [re2 abseil-cpp]);
});
})
]
);
in {
default =
pkgs.mkShell {
buildInputs = check.enabledPackages;

packages = [
(editablePythonSet.mkVirtualEnv "proselint-env" {proselint = ["test" "dev" "web"];})

pkgs.git-cliff
pkgs.typos
pkgs.uv
];

env = {
UV_NO_SYNC = "1";
UV_PYTHON = python.interpreter;
UV_PYTHON_DOWNLOADS = "never";
LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib";
};

shellHook =
''
export REPO_ROOT=$(git rev-parse --show-toplevel)
unset PYTHONPATH
''
+ check.shellHook;
};
}
36 changes: 36 additions & 0 deletions nix/helpers.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
self,
nixpkgs,
overlay,
}: let
getPythonVersion = let
val = builtins.getEnv "PYTHON_VERSION";

result =
if val == ""
then "3.13"
else val;
in
builtins.replaceStrings ["."] [""] result;
in {
forAllSystems = f:
nixpkgs.lib.genAttrs [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
] (system:
f rec {
inherit system;

pkgs = nixpkgs.legacyPackages.${system};
python = pkgs."python${getPythonVersion}";
pythonSet =
(pkgs.callPackage self.inputs.pyproject.build.packages {inherit python;}).overrideScope (
nixpkgs.lib.composeManyExtensions [
self.inputs.build-systems.overlays.default
overlay
]
);
});
}
Loading