Unable to reference locally installed golang flake executable like "{$pkgs.todocalmenu}/bin/todocalmenu"

Summary: In my home-manager sway configuration, I can’t refer to “${pkgs.todocalmenu}/bin/todocalmenu” for a keybinding when I have another locally installed flake ‘keepmenu’ that can use that same reference successfully “${pkgs.keepmenu}/bin/keepmenu”. They are (near as I can tell) being built and installed the exact same way other than keepmenu is python and todocalmenu is a golang app.

Here’s my abbreviated config:

/flake.nix

{
  description = "System configurations";

  inputs = {
    nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05";

    home-manager.url = "github:nix-community/home-manager/release-24.05";
    home-manager.inputs.nixpkgs.follows = "nixpkgs";

    keepmenu.url = "github:firecat53/keepmenu";
    keepmenu.inputs.nixpkgs.follows = "nixpkgs";

    todocalmenu.url = "github:firecat53/todocalmenu";
    todocalmenu.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = inputs@{
    self,
    nixpkgs,
    nixpkgs-unstable,
    home-manager,
    ...
  }: let
    inherit (self) outputs;
    system = "x86_64-linux";
  in {
    nixosConfigurations = {
      laptop = nixpkgs.lib.nixosSystem {
        specialArgs = {
          inherit inputs outputs;
        };
      };
    }; 
}

/hosts/laptop/configuration.nix

{
  inputs,
  ...
}:{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
      ../../home-manager/home-manager.nix
      inputs.home-manager.nixosModules.home-manager
    ];

  home-manager.users.firecat53 = {
    imports = [
       ../../home-manager/laptop.nix
    ];
  };
....

/home-manager/home-manager.nix

{
  inputs,
  outputs,
  pkgs,
  ...
}:{
  # Home-manager configuration
  home-manager = {
    extraSpecialArgs = { 
      inherit inputs outputs pkgs ;
    };
  };
}

/home-manager/laptop.nix

{
  config,
  inputs,
  sops-nix,
  ...
{
  imports = [
    ./sway
  ];
  programs.home-manager.enable = true;
  home.stateVersion = "23.05";
}

/home-manager/sway/sway.nix

{
  config,
  lib,
  pkgs,
  ...
}: let
  mod = "Mod4";
  mod1 = "Mod1";
in {
....
      keybindings = let
          todocalmenu = "todocalmenu -cmd bemenu -todo /home/firecat53/.local/share/calendars/todo";
          keepmenu = "${pkgs.keepmenu}/bin/keepmenu";
        in lib.mkOptionDefault {
          "${mod}+${mod1}+k" = "exec ${keepmenu}";
          "${mod}+${mod1}+t" = "exec ${todocalmenu}";
....

If I use nix repl and then :lf ., I can’t seem to find todocalmenu anywhere. If I change the above sway config to “${pkgs.todocalmenu}/bin/todocalmenu” I get the following error:

error:
       … while calling the 'head' builtin

         at /nix/store/mvz96grv31nxq69ldw5a5pn2qh1s6ca6-source/lib/attrsets.nix:1575:11:

         1574|         || pred here (elemAt values 1) (head values) then
         1575|           head values
             |           ^
         1576|         else

       … while evaluating the attribute 'value'

         at /nix/store/mvz96grv31nxq69ldw5a5pn2qh1s6ca6-source/lib/modules.nix:809:9:

          808|     in warnDeprecation opt //
          809|       { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
             |         ^
          810|         inherit (res.defsFinal') highestPrio;

       (stack trace truncated; use '--show-trace' to show the full trace)

       error: attribute 'todocalmenu' missing

       at /nix/store/3panizqjpn8dw3l364k9wi6lwrgblsim-source/home-manager/sway/sway.nix:152:28:

          151|           tmux = "${pkgs.tmux}/bin/tmux";
          152|           todocalmenu = "${pkgs.todocalmenu}/bin/todocalmenu -cmd bemenu -todo /home/firecat53/.local/share/calendars/todo";
             |                            ^
          153|           vim = "${pkgs.vim}/bin/vim";

Any ideas??? Thanks!

todocalmenu is not packaged on nixpkgs, so you need to package it.

Just having the flake input doesn’t automatically put the package in pkgs.

You can use inputs.todocalmenu.packages.${pkgs.system}.default instead. Either directly, or put it in a let…in binding.

If you prefer, you can put it in pkgs.todocalmenu through an overlay, like so:

{ inputs, ... }: {
  nixpkgs.overlays = [(final: prev: {
    todocalmenu = inputs.todocalmenu.packages.${final.system}.default;
  })];
}

@waffle8946 - both projects are built and installed using the flake.nix from the project pages.

That did it, thanks!!

So, a more complicated question, why does keepmenu work with just ${pkgs.keepmenu} when it is installed via flake the same way as todocalmenu (see above config files)?

If you look at the flake.nix (keepmenu and todocalmenu) for both projects, they are almost identical except that keepmenu uses buildPythonApplication and todocalmenu uses buildGoModule. Could that be the cause?

No, the module arg pkgs refers to the nixpkgs instance within the module system, so you are using keepmenu from nixpkgs, not the keepmenu flake. So actually the keepmenu flake input is currently dead code, if you want to use that flake you need to use the same method of inputs.keepmenu.packages.${pkgs.stdenv.hostPlatform.system}.default (replace default with whatever output the flake uses, which you can verify with nix flake show github:firecat53/keepmenu on the command line).

I would strongly recommend against this, as this is essentially creating a broken overlay, where if you try overlay some packages which happen to be dependencies of todocalmenu, it will not actually overlay those dependencies, due to todocalmenu using a different nixpkgs instance. Ideally the todocalmenu flake should expose its own overlay where it uses final.callPackage, and consumers of that overlay would in turn be able to incorporate the package into their current nixpkgs instance more effectively.

Hmmm…I think I forgot to include part of my config (abbreviated):

/home-manager/common/packages.nix

{
  inputs,
  pkgs,
  ...
}: let
  my-python-packages = ps:
    with ps; [
      ansible
      ansible-core
      grip
      ipython
      ipdb
      pip
      podman
      python-lsp-ruff
    ];
in {
  home.packages = with pkgs; [
    # Terminal tools
    autossh
    bottom
    fd
    ripgrep
    stow
    udiskie
    unzip
    home-manager
    ranger
    sshfs
    todoman
    highlight
    (python312.withPackages my-python-packages)
    pipx
    # Gui applications
    alacritty
    dmenu
    firefox
    inputs.keepmenu.packages.${pkgs.system}.default
    inputs.todocalmenu.packages.${pkgs.system}.default
  ];
}

Does that change anything? They are both available in ~/.nix-profile/bin/ along with other packages installed via home-manager. Sorry for the incomplete info!

No, you still need to use inputs.keepmenu… etc. not pkgs.keepmenu when referring to keepmenu.
The way you wrote this config, you are now putting two different keepmenu packages into the closure, which may or may not cause other issues if the versions are incompatible.

1 Like

Thanks so much!! Obvious in hindsight, but I hadn’t ever thought about it that way before. A year and a half and still learning…