The main branch is not going to get extended beyond it's current capabilities.
New functionality is going to be available in the /v2
branch.
There are slight non-backward compatible differences between main and v2,
feel free to check the
examples to learn more about
how to use nixDir.
nixDir is a library that transforms a convention oriented directory structure
into a nix flake.
With nixDir, you don't run into large flake.nix files, and don't have to
implement the "import wiring" of multiple nix files. nixDir will use
Convention over
Configuration and
lets you get back to your business.
The nixDir library traverses a configured nix directory to build the flakes
outputs dynamically.
The behavior is easier to explain with an example; assume you have a myproj
directory with the following flake.nix:
{
description = "myproj is here to make the world a better place";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
nixDir = {
url = "github:roman/nixDir";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {nixDir, ...} @ inputs: nixDir.lib.buildFlake {
systems = [ "x86_64-linux" "aarch64-darwin" ];
root = ./.;
dirName = "nix"; # (default)
inputs = inputs;
};
}With this setup, if there is no nix subdirectory in the myproj, our flake
will have no outputs.
$ nix flake show
git+file:///home/myuser/tmp/myproj?ref=refs%2fheads%2fmaster&rev=b9748c5fcb913af50bedaa8e75757b7120a6a0baIf we want to introduce a new package hello to our project, we can add a new
file in the myproj/nix/packages/hello.nix file.
Once we version this new file into the repository, the nix flake show output
will have the new package available:
$ nix flake show
git+file:///home/roman/myproj?ref=refs%2fheads%2fmaster&rev=<sha>
└───packages
├───aarch64-darwin
│ └───hello: package 'hello'
└───x86_64-linux
└───hello: package 'hello'nixDir adds the package automatically, and it does it with the systems that
we specified in the nixDir invocation in the flake.nix file.
Following are the various conventions that you can use with nixDir
ℹ️ The examples bellow assume the configured
nixDiris callednix
To add new packages, add an entry in your nix/packages directory. The entry
may be a nix file, or a directory with a default.nix. The name of the
file/directory will be the name of the exported package. For example:
# nix/packages/hello.nix
# packages receive the system, the flake inputs, and an attribute set with
# required nixpkgs packages.
system: inputs: { hello, writeShellScriptBin, makeWrapper, symlinkJoin }:
# We are going to do an essential wrapping of the hello package, following steps
# from: https://nixos.wiki/wiki/Nix_Cookbook#Wrapping_packages
symlinkJoin {
name = "hello";
paths = [ hello ];
buildInputs = [ makeWrapper ];
postBuild = ''
wrapProgram $out/bin/hello --add-flags "-t"
'';
}Your package file must receive three arguments. The first argument is the
current system platform, the second argument are the flake's inputs, and the
third argument is an attribute set with all the required dependencies for the
package (e.g. callPackage
convention).
⚠️ Packages could either be a nix file or a directory, nixDir will fail if it finds both a directory and a file with the same name.
In some situations, you may not be able to build a package for a certain
platform. nixDir will help you remove a package for a specific system
platform if the package metadata's platforms
attribute indicates the package
is not supported by such system.
If a package doesn't configure the platform's metadata, nixDir will include
the package in every specified system platform by default.
To add a lib export to your flake, include a nix/lib.nix inside your.For
example:
# nix/lib.nix
inputs: {
sayHello = str: builtins.trace "sayHello says: ${str}" null;
}The lib.nix file must export a function that receives the flake inputs as
parameters.
ℹ️ Given that library functions should be system agnostic, the
nix/lib.nixfile does not receive thesystemargument.
To create overlays, nixDir looks for the nix/overlays.nix file. This file
must receive the flake inputs as a parameter and return an attribute set with
every named overlay. Following is an example:
# nix/overlays.nix
{
self,
nixpkgs,
my-flake-dependency1,
my-flake-dependency2,
...
}:
let
default = final: prev:
self.packages.${prev.system};
develop =
nixpkgs.lib.composeManyExtensions [
my-flake-dependency1.overlays.default
my-flake-dependency2.overlays.default
];
in
{
inherit default develop;
}In the example above, we are creating two overlays, the one named default
includes all the packages this flake exports into the nixpkgs import. The one
named develop includes the overlays of some of our flake inputs.
There is an optional functionality to inject your flake overlays and use custom packages across your flake. Following is an example:
{
# inputs = {};
outputs = { nixDir, ... } @ inputs:
nixDir.lib.buildFlake {
inherit inputs;
systems = ["x86_64-linux"];
root = ./.;
# We want the packages injected by the develop overlay
# available in our flake code.
injectOverlays = ["develop"];
};
}In the example above, the develop overlay (which was defined on your
nix/overlays.nix file and includes the overlays of some of your flake inputs)
will be included in every nixpkgs import used within your flake exports.
ℹ️ Given that flake overlays should be system agnostic, the
nix/overlays.nixfile does not receive thesystemargument.
TODO
TODO
nixDir can run devenv profiles (using nix flakes porcelain) automatically.
To add a new devenv, add an entry in the nix/devenvs/ folder. Following is
an example, of a very basic devenv profile.
# nix/devenvs/my-devenv.nix
system: inputs: { config, pkgs, ... }:
{
languages.go.enable = true;
packages = [ inputs.self.packages.${system}.my-dance-music ];
enterShell = ''
echo "everybody dance now!"
'';
}In the same way we have it with other nixDir components, your devenv profile
must add two extra parameters, the first one being the current system and the
second one being all the inputs of your nix flake.
If you invoke nix flake show, you'll notice there is a new entry in the
devShells outputs called my-devenv (the name of the file containing the
devenv profile)
To run your devenv profile, run the nix develop command using the name of
the devenv profile.
nix develop .#my-devenv
⚠️ devenvmodules anddevShellswork on the devShells namespace, nixDir will fail if there is an entry on bothdevenvsanddevShellsdirectories with the same name.
As it stands today, the devenv project requires many uncached dependencies
that will take some time to build. To skip long build times, we recommend
adding their cachix setup, or to include
it on your flake:
{
description = "myproj is here to make the world a better place";
nixConfig = {
extra-trusted-public-keys = "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw=";
extra-substituters = "https://devenv.cachix.org";
};
# inputs = {};
# outputs = {};
}We do not recommend overriding devenv flake dependencies to skip cache misses.
nixDir is able to integrate a single pre-commit-hooks.nix to devShells
entries. This is an optional functionality; to enable it, you must have a
nix/pre-commit.nix file and enable the injectPreCommit option (defaults to
true) in the nixDir.lib.buildFlake call. Following is an example of a pre-commit configuration.
# nix/pre-commit.nix
system: inputs: pkgs:
{
# root of the project
src = ../.;
hooks = {
nixfmt.enable = true;
};
}The file must receive three arguments, the current system platform, the flake
inputs and an attribute-set with the nixpkgs pkgs.
ℹ️ As opposed to other
nixDircomponents, thenix/pre-commit.nixreceives all packages rather than relying on thecallPackageconvention
Another side-effect that occurs when using the nix/pre-commit.nix is that
nixDir appends a preCommitRunHook attribute to the flake's lib. This
attribute contains the pre-commit script, and it may be used as a value in other
places (like a docker image). Following is an example on how to add the script
in a docker image package:
# nix/packages/devenv-img.nix
system: {self, ...}: {
lib,
dockerTools,
buildEnv,
bashInteractive
}: let
dockerTools.buildImage {
tag = "latest";
name = "devenv-img";
copyToRoot = buildEnv {
name = "devenv-img";
paths = [
bashInteractive
];
pathsToLink = ["/bin"];
};
config = {
WorkingDir = "/tmp";
Env = [
# Inject pre-commit script to your container environment
"PRE_COMMIT_HOOK=${self.lib.preCommitRunHook.${system}}"
];
};
}If you are maintaining a project with nix flakes that has a big flake.nix file
(>500 LOC) or that involves several nix files, you may benefit from this
library.