Files
project-templates/rust/default.nix
T

237 lines
8.1 KiB
Nix

{
flake-parts-lib,
inputs,
...
}: {
flake = {
templates = {
rust = {
path = ./template;
description = "A rust flake with crane and templates for command args and configs";
};
};
flakeModules.rust = {
imports = [
inputs.treefmt-nix.flakeModule
];
options.perSystem = flake-parts-lib.mkPerSystemOption ({
lib,
config,
pkgs,
self',
...
}: let
cfg = config.krantz.rust;
src = cfg.srcFiltered;
manifest = (lib.importTOML "${src}/Cargo.toml").package;
craneLib =
if cfg.srcToolchain != null && builtins.pathExists cfg.srcToolchain
then
(inputs.crane.mkLib (pkgs.extend inputs.rust-overlay.overlays.default)).overrideToolchain (
p: p.rust-bin.fromRustupToolchainFile cfg.srcToolchain
)
else inputs.crane.mkLib pkgs;
buildInputs = cfg.runtimeDeps;
# build dependencies
nativeBuildInputs = cfg.buildDeps;
# Build *just* the cargo dependencies, so we can reuse
# all of that work (e.g. via cachix) when running in CI
cargoArtifacts = craneLib.buildDepsOnly ({
inherit src buildInputs nativeBuildInputs;
}
// cfg.cargoArtifacts.extraAttrs);
in {
options.krantz.rust = {
enable = lib.mkEnableOption "building a cargo project with crane";
src = lib.mkOption {
description = "The path to the root of the crate.";
type = lib.types.nullOr lib.types.path;
default = null;
example = lib.literalExpression "./.";
};
srcFiltered = lib.mkOption {
description = "A path to the filtered directory of the root of the crate.";
type = lib.types.path;
default = craneLib.cleanCargoSource cfg.src;
defaultText = lib.literalExpression "config.krantz.rust.craneLib.cleanCargoSource cfg.src";
example = lib.literalExpression "./.";
};
srcToolchain = lib.mkOption {
description = "A path to the rust-toolchain(.toml) file for the repo. Will use the toolchain from nixpkgs if the file does not exist.";
type = lib.types.nullOr lib.types.path;
default =
if cfg.src != null
then cfg.src + "/rust-toolchain.toml"
else null;
defaultText =
lib.literalExpression
/*
nix
*/
''
if cfg.src != null
then cfg.src + "/rust-toolchain.toml"
else null;
'';
example = lib.literalExpression "./rust-toolchain";
};
runtimeDeps = lib.mkOption {
description = "Packages needed for the app to run.";
type = lib.types.listOf lib.types.package;
default = [];
example = with pkgs; [
openssl
];
};
buildDeps = lib.mkOption {
description = "Packages needed for the app to build.";
type = lib.types.listOf lib.types.package;
default = [];
example = with pkgs; [
pkg-config
rustPlatform.bindgenHook
];
};
devDeps = lib.mkOption {
description = "Packages to include only in the devShell.";
type = lib.types.listOf lib.types.package;
default = with pkgs; [
rust-analyzer
];
};
cargoArtifacts = {
extraAttrs = lib.mkOption {
description = "Extra attributes to merge into buildDepsOnly. See https://crane.dev/API.html#cranelibbuilddepsonly";
type = lib.types.attrs;
default = {};
example = {
doCheck = false;
};
};
};
devShell = {
enable = lib.mkEnableOption "a rust development environment" // {default = true;};
name = lib.mkOption {
description = "The name of the attribute in devShells to configure";
type = lib.types.str;
default = "default";
example = "rust";
};
extraAttrs = lib.mkOption {
description = "Extra attributes to merge into the devshell. See https://crane.dev/API.html#cranelibdevshell";
type = lib.types.attrs;
default = {};
example = {
shellHook = ''
export DEBUG=1
'';
};
};
};
package = {
enable = lib.mkEnableOption "the compiled cargo project" // {default = true;};
name = lib.mkOption {
description = "The name of the attribute in packages to configure";
type = lib.types.str;
default = "default";
example = "lib";
};
extraAttrs = lib.mkOption {
description = "Extra attributes to merge into the package. See https://crane.dev/API.html#cranelibbuildpackage";
type = lib.types.attrs;
default = {};
example = {
doCheck = false;
};
};
};
formatter = {
enable = lib.mkEnableOption "treefmt for formatting multiple types of files" // {default = true;};
nix = lib.mkEnableOption "formatting for nix files" // {default = true;};
rust = lib.mkEnableOption "formatting for rust files" // {default = true;};
toml = lib.mkEnableOption "formatting for toml files" // {default = true;};
markdown = lib.mkEnableOption "formatting for toml files" // {default = true;};
};
checks = {
enable = lib.mkEnableOption "checks for rust" // {default = true;};
linter = lib.mkEnableOption "lints for rust" // {default = true;};
};
craneLib = lib.mkOption {
description = "The crane lib instance this module is using. Useful for overriding options";
default = craneLib;
defaultText = lib.literalExpression "crane.mkLib pkgs";
readOnly = true;
};
};
config = lib.mkIf cfg.enable {
# Dev Shell that lets you enter an environment with all the necessary utilites
# Available through 'nix develop'
# Also can be activated automatically if direnv is installed on the system with 'direnv allow'
devShells = lib.mkIf cfg.devShell.enable {
${cfg.devShell.name} =
craneLib.devShell {
inherit (self') checks;
# extra tooling dependencies
packages = cfg.devDeps;
inputsFrom = [self'.packages.${cfg.package.name}];
}
// cfg.devShell.extraAttrs;
};
# Your custom packages
# Accessible through 'nix build', 'nix shell', 'nix run', etc
packages = lib.mkIf cfg.package.enable {
${cfg.package.name} = craneLib.buildPackage ({
inherit src buildInputs nativeBuildInputs cargoArtifacts;
}
// cfg.package.extraAttrs);
};
# Formatter for nix files, available through 'nix fmt'
treefmt.programs = lib.mkIf cfg.formatter.enable {
alejandra.enable = lib.mkIf cfg.formatter.nix true;
rustfmt = lib.mkIf cfg.formatter.rust {
enable = true;
edition = manifest.edition;
};
taplo.enable = lib.mkIf cfg.formatter.toml true;
rumdl-check.enable = lib.mkIf cfg.formatter.markdown true;
rumdl-format.enable = lib.mkIf cfg.formatter.markdown true;
};
checks = lib.mkIf cfg.checks.enable {
clippy = lib.mkIf cfg.checks.linter (craneLib.cargoClippy {
inherit src buildInputs nativeBuildInputs cargoArtifacts;
cargoClippyExtraArgs = "-- --deny warnings";
});
};
};
});
};
};
}