Cannot access locally created package even though derivation seems to work

I have created the following derivation to load a shell script into the bin directory of the derivation with the idea being to add the package to my inputs for another derivation so that I can ‘source’ it in this new (and yet unwritten) one. The code is as follows

{ config, pkgs, ... }:

   bash-common-functions = pkgs.writeShellScriptBin "bash-common-functions"
       (builtins.readFile ./bash-common-functions);
  environment.systemPackages = [ bash-common-functions ];

Yet when I try nix

Sorry, hit the wrong button somewhere, will continue:

Yet, when I try

nix-shell -p bash-common-functions

the following error message occurs:

error: undefined variable ‘bash-common-functions’ at (string):1:94
(use ‘–show-trace’ to show detailed location information)

I have also tried

nix-shell -p pkgs.bash-common-functions

and the error is as follows:
error: attribute ‘bash-common-functions’ missing, at (string):1:94
(use ‘–show-trace’ to show detailed location information)

Ultimately I would like to add it as a package to but am at a loss as to what I am doing wrong.

I think there are a few little misunderstandings here (don’t worry–I’ve struggled with the same bit; it’s a little slippery).

  • When you run nix-shell -p <packagename>, it’s going to be coming from nixpkgs.
  • To be adding your own custom packages to nixpkgs, you’ll either be using an overlay, or using your own fork of nixpkgs (whether that’s on your local drive, or on github or something).
  • environment.systemPackages doesn’t have much to do directly with what’s available in a nix shell, and you probably won’t be using it in individual packages. At some point, when your package is ready to use, you might want to add it to your system environment by adding it to environment.systemPackages in your main system config.
  • If you just run a bare nix-shell, it’ll be building default.nix or shell.nix in the present directory. You can also use nix-shell <filename>.nix to target a specific file.

It’s a little hard from here to know for sure which direction you want/need to go right now. I’m guessing from the context that you’re trying to get it running in a nix-shell first just to play with it, in which case something like this (in a file named shell.nix) might get you going:

{ pkgs ? import <nixpkgs> {} }:
   bash-common-functions = pkgs.writeShellScriptBin "bash-common-functions"
       (builtins.readFile ./bash-common-functions);
pkgs.mkShell {
  buildInputs = [ bash-common-functions ];

Thank you for your prompt and helpful reply. After much effort and reading, I’ve managed to get all of my bash scripts as overlays and they work in nix-shell. I tried to add them to environment.systemPackages but it reports ‘unknown package’ when I do this. I also need to add build inputs for two of the bash scripts - some depend on others, but that fails as well. Does anybody have any helpful ideas or links to documentation that I can read ? I can post the files if required - please advise.

You can add simple things to environment.systemPackages like this:

environment.systemPackages = [
	( pkgs.writeShellScriptBin "bash-common-functions" (builtins.readFile ./bash-common-functions); )
] ;

pkgs.writeShellScriptBin is a derivation, just like stdenv.mkDerivation. That means that it builds something that resides in /nix/store.
You can add derivations directly to environment.systemPackages, everything else needs to be put into a derivation.
Basically your first post is pretty much the solution for using in configuration.nix, you only got thrown of the way by using nix-shell, which has some different requirements.
nix-shell has two functions. The first function throws you into the build environment of a package so you can debug the build process, the second function (-p) creates an environment containing some packages from nixpkgs and gives you a shell in it.
What @abathur’s snippet is doing is to give you a shell derivation that builds a shell with your package in the build environment. This is great for testing, but if you then want to add that package to environment.systemPackages, you need to unwrap that package again, before you can use it.

By the way, it’s up to you wether you use let or just paste the definition directly into environment.systemPackages. If the definition is short, I tend to paste it in directly, else I usually extract it into a different file, like this:
File: ./pkgs/opencrypt/default.nix

{ stdenv, cryptsetup, nfs-utils, which}:

stdenv.mkDerivation rec {
  name = "opencrypt";
  src = ./opencrypt ;


environment.systemPackages = [
  (pkgs.callPackage ./pkgs/opencrypt/default.nix {})

The nice thing about the extra file is that you can build and examine the result without having to enter any shell by running the following command:
nix-build -E 'with import <nixpkgs> { }; callPackage ./pkgs/opencrypt/default.nix { }'
This will create a symlink result in your current directory, which links to the built package. And you should be able to run any scripts or binaries through ./result/bin/myscript.
The ./pkgs/opencrypt/default.nix also has the exact same format that’s required for inclusion in nixpkgs.

1 Like

Many thanks for an informative reply. It has enabled me to get the scripts into system environment and start some testing which is to a NixOS beginner a great achievement. So thanks to both that replied. I’d like to click on solved to both of you as both were helpful but will have to give credit to the last reply as it was the one that got me going. Thanks again.