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

Using extraPackages for cargo plugins #443

Closed
DavSanchez opened this issue May 12, 2024 · 7 comments
Closed

Using extraPackages for cargo plugins #443

DavSanchez opened this issue May 12, 2024 · 7 comments
Labels
question Further information is requested

Comments

@DavSanchez
Copy link

DavSanchez commented May 12, 2024

Hi! Apologies if this should be obvious, but I'm having trouble getting extraPackages (#430) to work on a certain setup. Suppose that I have a custom hook defined like this:

# ...
custom-hook = {
  enable = true;
  name = "tests";
  entry = "${pkgs.gnumake}/bin/make -C somedir some-make-target";
  language = "rust";
  pass_filenames = false;
  extraPackages = with pkgs; [
    rustToolchain # Created with fenix, working for building the package
    cargo-deny
    git
  ] ++ lib.optionals stdenv.isDarwin [
    libiconv
  ];
};
# ...

And the make target runs cargo deny then cargo run and then git. I am having trouble for cargo to detect that it has the cargo-deny plugin, as if for example I try to run cargo run -- <CARGO_DENY_OUTPUT> the contents of CARGO_DENY_OUTPUT are actually 'error: no such command: "deny" Did you mean "bench"? View all installed commands with "cargo --list" Find a package to install "deny" with "cargo search cargo-deny" '.

What could be missing? Do you have any way to help me troubleshoot this?

Thanks a lot!

@sandydoo sandydoo added the question Further information is requested label May 13, 2024
@sandydoo
Copy link
Member

@DavSanchez, could you post the full pre-commit config, including the part where you create the devShell? Thanks

@DavSanchez
Copy link
Author

DavSanchez commented May 13, 2024

Hi @sandydoo , I'll redact some segments as they are related to work, but should represent my problem enough:

flake.nix
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    git-hooks = {
      url = "github:cachix/git-hooks.nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    flake-utils.url = "github:numtide/flake-utils";
    flake-compat.url = "github:edolstra/flake-compat";

    # Rust toolchains
    fenix = {
      url = "github:nix-community/fenix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    # Compiling Rust projects in cacheable/composable way
    crane = {
      url = "github:ipetkov/crane";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = inputs @ {
    self,
    nixpkgs,
    git-hooks,
    flake-utils,
    fenix,
    crane,
    ...
  }:
    flake-utils.lib.eachDefaultSystem (system: let
      pkgs = nixpkgs.legacyPackages.${system};

      rustToolchain = with fenix.packages.${system};
        combine [
          stable.toolchain

          targets.x86_64-unknown-linux-musl.stable.rust-std
          targets.aarch64-unknown-linux-musl.stable.rust-std

          targets.aarch64-apple-darwin.stable.rust-std
          targets.x86_64-apple-darwin.stable.rust-std
        ];

      craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain;

      cargoArtifacts = craneLib.buildDepsOnly (commonArgs
        // {
          pname = "project-dependencies";
          version = "0.1.0";
        });

      commonArgs = {
        src = pkgs.lib.cleanSourceWith {
          src = craneLib.path ./.; # The original, unfiltered source
          # There are some shell scripts in the tests directory, should not be filtered out
          filter = path: type:
            (builtins.match ".*sh$" path != null) || (craneLib.filterCargoSources path type);
        };
        strictDeps = true;
        # Platform-agnostic dependencies, required for protobuf compilation
        depsBuildBuild = with pkgs; [
          git
          protobuf
        ];
        # Compilation inputs
        buildInputs = with pkgs;
          lib.optionals stdenv.isDarwin [
            libiconv
            darwin.apple_sdk.frameworks.SystemConfiguration
          ];
      };

      build-project-package = targetPkgs: features: args:
        craneLib.buildPackage (
          commonArgs
          // craneLib.crateNameFromCargoToml {cargoToml = ./some-workspace-dir/Cargo.toml;}
          // {
            inherit cargoArtifacts;

            # Only running test when not cross-compiling
            doCheck = with targetPkgs; stdenv.buildPlatform.canExecute stdenv.hostPlatform;

            cargoExtraArgs = "--features=${features}";
            cargoTestExtraArgs = "--features=${features} -- --skip as_root";

            CARGO_BUILD_TARGET = targetPkgs.hostPlatform.config;
            # We go static when using the musl target
            CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUSTFLAGS = "-C target-feature=+crt-static";
            CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_RUSTFLAGS = "-C target-feature=+crt-static";

            # Linker setups for cross-compilation
            CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER = with pkgs.pkgsCross.musl64.stdenv; "${cc}/bin/${cc.targetPrefix}cc";
            CC_x86_64_unknown_linux_musl = with pkgs.pkgsCross.musl64.stdenv; "${cc}/bin/${cc.targetPrefix}cc";
            CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER = with pkgs.pkgsCross.aarch64-multiplatform-musl.stdenv; "${cc}/bin/${cc.targetPrefix}cc";
            CC_aarch64_unknown_linux_musl = with pkgs.pkgsCross.aarch64-multiplatform-musl.stdenv; "${cc}/bin/${cc.targetPrefix}cc";
          }
          // pkgs.lib.optionalAttrs (! builtins.isNull args) args
        );
    in {
      checks = {
        git-hooks-check = git-hooks.lib.${system}.run {
          src = ./.;
          hooks = {
            actionlint.enable = true;
            alejandra.enable = true;
            ansible-lint.enable = false;
            convco.enable = true;
            markdownlint.enable = false;
            rustfmt.enable = true;
            taplo.enable = true;
            # Below is a custom hook.
            third-party-notices = {
              enable = true;
              name = "third-party-notices";
              entry = "${pkgs.gnumake}/bin/make -C license third-party-notices";
              language = "rust";
              pass_filenames = false;
              extraPackages = with pkgs; [
                rustToolchain
                cargo-deny
                git
              ] ++ lib.optionals stdenv.isDarwin [
                libiconv
              ] ;
            };
            cargo-check-somefeature = {
              enable = true;
              name = "cargo-check-somefeature";
              entry = "${rustToolchain}/bin/cargo check --features some feature";
              language = "rust";
              pass_filenames = false;
            };
            clippy-somefeature = {
              enable = true;
              name = "cippy-somefeature";
              entry = "${rustToolchain}/bin/cargo clippy --features some feature";
              language = "rust";
              pass_filenames = false;
            };
          };
          tools = {
            cargo = rustToolchain;
            rustfmt = rustToolchain;
            clippy = rustToolchain;
          };
        };
      };

      devShells = {
        default = pkgs.mkShell {
          inherit (self.checks.${system}.git-hooks-check) shellHook;
          buildInputs = with pkgs;
            [
              rustToolchain
              protobuf
              # goreleaser
              # gnumake
            ]
            ++ lib.optionals stdenv.isDarwin [
              libiconv
              darwin.apple_sdk.frameworks.SystemConfiguration
            ];
        };
      };

      packages = {
        # default build, generates outputs native to the host
        default = build-project-package pkgs "somefeature" { };

        with-some-feature = build-project-package pkgs "somefeature" null;
        with-some-other-feature = build-project-package pkgs "someotherfeature" null;

        # cross x86_64 builds
        x86_64-linux-musl-somefeature = build-project-package pkgs.pkgsCross.musl64 "somefeature" null;
        x86_64-linux-musl-someotherfeature = build-project-package pkgs.pkgsCross.musl64 "someotherfeature" null;
        # cross aarch64 builds
        aarch64-linux-musl-somefeature = build-project-package pkgs.pkgsCross.aarch64-multiplatform-musl "somefeature" null;
        aarch64-linux-musl-someotherfeature = build-project-package pkgs.pkgsCross.aarch64-multiplatform-musl "someotherfeature" null;
      };
    });
}

The flake is a work in progress so it's nowhere near a "final form", but it works fine cross-compiling to all the targets defined, and the other custom hooks work. The only hook failing is the third-party-notices. Thanks a lot!

@sandydoo
Copy link
Member

sandydoo commented May 14, 2024

The extraPackages get appended to enabledPackages, which contains the packages for every enabled hook. You just need to add this package set to you dev shell:

{
  devShells = {
    default = let
      gitHooks = self.checks.${system}.git-hooks-check;
    in pkgs.mkShell {
      inherit (gitHooks) shellHook;
      buildInputs = with pkgs;
        [
          rustToolchain
          gitHooks.enabledPackages # <-- here (it's a list, so you can ++ it if you like)
          protobuf
          # goreleaser
          # gnumake
        ]
        ++ lib.optionals stdenv.isDarwin [
          libiconv
          darwin.apple_sdk.frameworks.SystemConfiguration
        ];
    };
  };
}

@DavSanchez
Copy link
Author

Hi, it worked! Thank you very much.

I thought the packages were already available to any checks done with the hooks. Looking now on README.md I see it's advised to add enabledPackages to the shell's buildInputs, I didn't find this info when I checked a while back. Good to know!

Best regards

@DavSanchez
Copy link
Author

DavSanchez commented May 15, 2024

Hi @sandydoo , don't want to reopen for this, but I wanted to know what would be the flake-parts equivalent to this setup? How could I add the shellHook and the enabledPackages to a devShell I define? If I try using the documented flake-parts options such as installationScript and settings.enabledPackages I usually find errors like this one:

error: evaluation aborted with the following error message: 'Function called without required argument "cljfmt" at /nix/store/4a7sam75nsslhm29mpqpswxhxavgccv5-source/nix/tools.nix:15, did you mean "cbfmt", "clfft" or "clifm"?'

Though I haven't anything to do with Clojure defined here. I try to reach the options of the flakeModule via the repl but cannot find them. This config seems to work though:

devShells.default = let
  gitHooks = inputs'.git-hooks.devShells.default;
in
pkgs.mkShell {
  inherit (gitHooks) shellHook nativeBuildInputs;
  # ...
};

But seems a bit off to me. Is this the way?

@sandydoo
Copy link
Member

sandydoo commented May 15, 2024

@DavSanchez, we ship a flake-parts module. Sample usage here: https://github.com/cachix/git-hooks.nix/blob/master/template/flake.nix

flake-parts.lib.mkFlake
  { inherit inputs; }
  {
    imports = [
      inputs.pre-commit-hooks-nix.flakeModule
    ];
    systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
    perSystem = { config, self', inputs', pkgs, system, ... }: {
      # Per-system attributes can be defined here. The self' and inputs'
      # module parameters provide easy access to attributes of the same
      # system.

      # Equivalent to  inputs'.nixpkgs.legacyPackages.hello;
      packages.hello = pkgs.hello;

      pre-commit.settings.hooks.nixpkgs-fmt.enable = true;

      # Already includes `enabledPackages`. Run `nix flake update` if it doesn't.
      devShells.default = config.pre-commit.devShell;

      # Custom shell
      devShells.custom = pkgs.mkShell {
        shellHook = ''
          ${config.pre-commit.installationScript}
          echo 1>&2 "Welcome to the development shell!"
        '';
        nativeBuildInputs = config.pre-commit.settings.enabledPackages;
      };
    };
    flake = {
      # The usual flake attributes can be defined here, including system-
      # agnostic ones like nixosModule and system-enumerating ones, although
      # those are more easily expressed in perSystem.

    };
  };

@DavSanchez
Copy link
Author

I was doing something very similar to your example but mine was failing, was probably badly set up because your example works again. Thank you very much!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants