Hi! I’m trying to learn to make development flake (through the mkShell function). I am working on a luajit-luarocks flake, in which I’d like to initialize a bunch of stuff like git repo, luarocks virtualenv, direnv, etc…
I could not find any resource to run some script only when the flake is initialized (if I understand, shellHook runs every time I enter the developement environment, and I don’t want to git init every time I enter the project).
Here is what I have so far:
{
description = "A LuaJIT app development flake";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
inputs.systems.url = "github:nix-systems/default";
inputs.flake-utils = {
url = "github:numtide/flake-utils";
inputs.systems.follows = "systems";
};
outputs =
{ nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
project_name = ""; # Enter project name here
in
{
devShells.default = pkgs.mkShell {
inputsFrom = with pkgs; [
luajitPackages.luarocks
luajit
];
buildInputs = [
pkgs.stdenv.mkDerivation {
name = "prepare";
src = ./.;
installPhase = ''
project_name=${project_name}
if [ "$project_name" = "" ]; then
project_name="$(basename "$PWD")"
fi
# Note: this block must come before the luarocks init
# Luarocks will adapt the generated config from this
mv "$PWD/lua/project-name" "$PWD/lua/$project_name"
luarocks init --wrapper-dir="$PWD/bin" --lua-versions=5.1 --no-gitignore "$project_name"
cp "$PWD/bin/lua" "$PWD/bin/luajit"
git init
git add "$PWD/flake.nix"
direnv allow "$PWD"
'';
}
];
shellHook = ''
# Put the local bin in front to give it priority
export PATH="$PWD/bin:$PATH"
'';
};
}
);
}
The installPhase part isn’t ran. Same if I put it in mkShell’s top level or if I replace it with buildPhase. Any idea? Thanks in advance.
By initializing, I just mean nix flake new/init -t what#ever [target-directory]. I would like something to run at this moment (or the first time I call nix develop inside), not just everytime I enter the flake’s shell.
Sorry about that, I glossed too quickly over the thread. Yes, it would run each and every time.
You could utilize your prepare, though you’d have to call it. Adding a logic check for .git or other artifact presence could exit the prepare, on the assumption that the init is completed already. These changes might be helpful:
{
description = "A LuaJIT app development flake";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
inputs.systems.url = "github:nix-systems/default";
inputs.flake-utils = {
url = "github:numtide/flake-utils";
inputs.systems.follows = "systems";
};
outputs = {
nixpkgs,
flake-utils,
...
}:
flake-utils.lib.eachDefaultSystem (
system: let
pkgs = nixpkgs.legacyPackages.${system};
project_name = ""; # Enter project name here
in {
devShells.default = pkgs.mkShell {
inputsFrom = with pkgs; [
luajitPackages.luarocks
luajit
];
buildInputs = [
(pkgs.writeShellApplication
{
name = "prepare";
checkPhase = "";
runtimeInputs = [pkgs.git pkgs.direnv];
text = ''
# Init will not run if git already exists
if [ -d .git ]; then
exit 0
fi
project_name=${project_name}
if [ "$project_name" = "" ]; then
project_name="$(basename "$PWD")"
fi
# Note: this block must come before the luarocks init
# Luarocks will adapt the generated config from this
mv "$PWD/lua/project-name" "$PWD/lua/$project_name"
luarocks init --wrapper-dir="$PWD/bin" --lua-versions=5.1 --no-gitignore "$project_name"
cp "$PWD/bin/lua" "$PWD/bin/luajit"
git init
git add "$PWD/flake.nix"
direnv allow "$PWD"
'';
})
];
shellHook = ''
# Put the local bin in front to give it priority
export PATH="$PWD/bin:$PATH"
# Run the preparation script
prepare
'';
};
}
);
}
The install was converted to a shell application that is now called by the shell hook, it either inits your script or quits early if the git repo already existed.
Direnv note for other projects:
Lastly, I use layout from direnv to accomplish automatic handling of venv. The benefit is that it automatically handles and integrates that directly into the environment and caches it. However, I don’t believe there’s a custom implementation for arbitrary triggers. More info from direnv’s lib: DIRENV-STDLIB 1 “2019” direnv “User Manuals” | direnv
Thanks for the inputs. I actually tried that .git heuristic but it seems uncomfortable. So far, I feel like I’m better off with a wrapper bash script that also calls nix flake new.
That layout command looks great, but there is no support for Lua in there
This isn’t possible and I reckon security is one of the main reasons why. It would be an absolute nightmare security wise if a template could just run arbitrary shell code.
Templates expose an attribute called welcomeText that prints to the console when a template is first initialized. You could maybe have it print out the shell commands that you want to run, then copy paste them to your shell.
Alternatively, if you go down the direnv route, you can have it make a file that acts like a “lock”, preventing whatever one time changes from running again.