{ flake-parts-lib, inputs, ... }: { flake = { templates = { rust = { path = ./rust; 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, ... }: let cfg = config.krantz.rust; craneLib = inputs.crane.mkLib pkgs; src = cfg.srcFiltered; manifest = (lib.importTOML "${src}/Cargo.toml").package; 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; }; 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.path; 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 cfg.src"; example = lib.literalExpression "./."; }; 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 ]; }; 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; }; }; }; 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 rec { # 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.${cfg.devShell.name} = lib.mkIf cfg.devShell.enable (craneLib.devShell { inherit checks; # extra tooling dependencies packages = cfg.devDeps; inputsFrom = [packages.default]; } // cfg.devShell.extraAttrs); # Formatter for nix files, available through 'nix fmt' treefmt = { programs.alejandra.enable = lib.mkDefault true; programs.rustfmt = { enable = true; edition = manifest.edition; }; }; # Your custom packages # Accessible through 'nix build', 'nix shell', 'nix run', etc packages.${cfg.package.name} = lib.mkIf cfg.package.enable (craneLib.buildPackage { inherit src buildInputs nativeBuildInputs cargoArtifacts; } // cfg.package.extraAttrs); checks = { clippy = craneLib.cargoClippy { inherit src buildInputs nativeBuildInputs cargoArtifacts; cargoClippyExtraArgs = "-- --deny warnings"; }; }; }; }); }; }; }