numtide / devshell

Per project developer environments
https://numtide.github.io/devshell/
MIT License
1.22k stars 87 forks source link

Expose `flakeModule` from flake for use with `flake-parts` #238

Closed srid closed 1 year ago

srid commented 1 year ago

Is there any interest in providing a flake-parts module? @roberth had a WIP solution here: https://github.com/numtide/devshell/compare/master...hercules-ci:devshell:flake-modules

I'm happy to resume/update this if there is any interest.

Matrix discussion

My intention is to use devshell's MOTD feature but without having to create devshell.toml and the like (ie., configure everything in flake.nix, and use with an existing language dev shell). To begin with, I'd use this to replace all the scripts in https://github.com/srid/haskell-template/tree/master/bin

zimbatm commented 1 year ago

I like it. Especially if it can get the same treatment as with treefmt-nix.

terlar commented 1 year ago

This would be really nice, now writing abstractions on top of shells using config from flake-parts is a bit tricky.

brianmcgee commented 1 year ago

This would be really nice, now writing abstractions on top of shells using config from flake-parts is a bit tricky.

In the meantime here's a simple way that been bringing in devshell, might be useful:

{
  inputs,
  lib,
  ...
}: let
  importDevshellModule = name: {
    perSystem = import (inputs.devshell + "/modules/${name}");
  };
in {
  imports = [
    (importDevshellModule "env.nix") # allows us to define env variables
    (importDevshellModule "commands.nix") # allows us to define shell commands
    (importDevshellModule "devshell.nix") # the glue that binds
  ];

  config.perSystem = {
    pkgs,
    config,
    ...
  }: let
    # capture the devshell config generated for us by the devshell modules
    cfg = config.devshell;
  in {
    config = {
      # we need to create the data dir as this is typically done with devshells mkShell which we aren't using
      devshell.startup.create-datadir.text = ''
        mkdir -p $PRJ_DATA_DIR
      '';

      # define some useful env variables
      env = [
        ...
      ];

      # add some common commands
      commands = [
        ...
      ];

      # set our devshell
      devShells.default = cfg.shell;
    };
  };
}

In the next week or so I'm going to port this to a proper flake module for devshell.

terlar commented 1 year ago

Thank you, won't this put the env.nix and commands.nix options in the top level namespace? I wanted a more isolated solution and had a look at the currently proposed devenv integration. Based on this and also having tested it could look like this:

{
  lib,
  flake-parts-lib,
  ...
}: let
  inherit (flake-parts-lib) mkPerSystemOption;
  inherit (lib) mkOption types;
in {
  options = {
    perSystem = mkPerSystemOption ({
      config,
      pkgs,
      ...
    }: let
      devshellType =
        (lib.evalModules {
          modules = import ./modules/modules.nix {
            inherit lib pkgs;
          };
        })
        .type;
    in {
      options.devshell.shells = mkOption {
        type = types.lazyAttrsOf devshellType;
        default = {};
      };
      config.devShells = lib.mapAttrs (_name: devshell: devshell.devshell.shell) config.devshell.shells;
    });
  };
}
brianmcgee commented 1 year ago

Yeah I didn't really mind about polluting the global namespace, just getting something working. I like the proposal above