How to install a specific version of a package from my configuration.nix

Since amuled 2.3.3 is currently broken, I want to install 2.3.2 on my system, but I can’t find anything that explains how to do that.

There’s Nix Package Versions which has nice instructions for what to write, but not where to put it.

There’s also FAQ/Pinning Nixpkgs - NixOS Wiki which also has instructions for what to write, but not where to put it.

I’ve tried just stuffing it in my inner container’s config, but it doesn’t like that:

container-amuled.nix:

{ config, pkgs, ... }:

let
  hostDataPath = "/home/data/mule";
  guestDataPath = "/amule";
  macaddr = "12:4b:53:00:00:24";
in {
  systemd.tmpfiles.rules = [
  "d ${hostDataPath} 755 karl users -"
  ];

  containers.mule = {
    autoStart = true;
    ephemeral = true;

    # Use a specific bridge instead of the host's networking
    privateNetwork = true;
    hostBridge = "br0";

    bindMounts = {
      "${guestDataPath}" = {
        hostPath = "${hostDataPath}";
        isReadOnly = false;
      };
    };

    config = { config, pkgs, ... }: {
      boot.isContainer = true;

      ##### This doesn't work ######
      import (builtins.fetchGit {
        name = "old-amule";
        url = "https://github.com/nixos/nixpkgs/";
        ref = "refs/heads/nixos-unstable";
        rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
      }) {}

      networking.interfaces.eth0.useDHCP = true;

      # Hack: Change the MAC address before dhcpcd runs
      systemd.services.setmacaddr = {
        script = ''
          /run/current-system/sw/bin/ip link set dev eth0 address ${macaddr}
          /run/current-system/sw/bin/systemctl stop dhcpcd.service
          /run/current-system/sw/bin/ip addr flush eth0
          /run/current-system/sw/bin/systemctl start dhcpcd.service
        '';
        wantedBy = [ "basic.target" ];
        after = [ "dhcpcd.service" ];
      };

      # Make sure txuser exists (uid 1000)
      users.users.txuser.isNormalUser = true;

      # Make sure guest path exists
      systemd.tmpfiles.rules = [
      "d ${guestDataPath} 700 txuser users -"
      ];

      services.amule = {
        # Run "amuled --ec-config" to configure the service for the first time. 
        enable = true;
        dataDir = "${guestDataPath}";
        user = "txuser";
      };
    };
  };
}

1 Like

Looking at the NixOS options shows the source for services.amule to be https://github.com/NixOS/nixpkgs/blob/47cd6702934434dd02bc53a67dbce3e5493e33a2/nixos/modules/services/networking/amuled.nix
I was hoping for an option to set the pkgs.amuleDaemon package. Rather, the trouble is we want the expression ${pkgs.amuleDaemon}/bin/amuled to evaluate to amuled 2.3.2.

I’m not sure how to build a nixos config with different nixpkgs versions. The FAQ page you links to suggests one option we have is the nixpkgs.config.packageOverrides.

Probably it’s enough to then use that like:

nixpkgs.config.packageOverrides = pkgs: {
  amuleDaemon =
    let
      pkgs-with-old-amule = import (builtins.fetchGit {
        name = "old-amule";
        url = "https://github.com/nixos/nixpkgs/";
        ref = "refs/heads/nixos-unstable";
        rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
      }) {};
    in
    pkgs-with-old-amule.amuleDaemon;
};
2 Likes

There are some caveats to doing it like that though, and that is that this will import a totally different version of nixpkgs, with all kinds of outdated and duplicate libraries, while also doubly evaluating nixpkgs. This is slow, burns a ton of disk space and is a potential source of security issues in the future (when you inevitably forget about this, or never get around to unpinning this).

I think better practice is just to change the source version with overrideAttrs, but that’s difficult in this case because the build script changed quite a bit: amule: unbreak (except daemon), unstable-20201006 -> 2.3.3, use cmake · NixOS/nixpkgs@1a8cf34 · GitHub

You could also just copy the old derivation, and callPackge it by hand. I always wonder if there is a nice way to do that with nix when I run into this.

Maybe in this case the best practice is just to try and get the package updated in nixpkgs proper.

1 Like

At this point I’m well past my depth. I tried the above solution but then some random thing broke (I really hate spooky action at a distance):

error: attribute 'currentSystem' missing

       at /nix/store/176g3d0sly5d602qf8wcljc15584zngz-old-amule/pkgs/top-level/impure.nix:90:39:

           89|                 else (if args ? localSystem then {}
           90|                       else { system = builtins.currentSystem; }) // localSystem;
             |                                       ^
           91| })

This happens after putting the new blob into the container config:

...
    config = { config, pkgs, ... }: {
      boot.isContainer = true;

      nixpkgs.config.packageOverrides = pkgs: {
        amuleDaemon =
          let
            pkgs-with-old-amule = import (builtins.fetchGit {
              name = "old-amule";
              url = "https://github.com/nixos/nixpkgs/";
              ref = "refs/heads/nixos-unstable";
              rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
            }) {};
          in
          pkgs-with-old-amule.amuleDaemon;
      };

      networking.interfaces.eth0.useDHCP = true;
...

I haven’t checked anything for amuled, but here’s what i do for other packages:

let
    nixosRecentCommitTarball =
    builtins.fetchTarball {
      url = "https://github.com/NixOS/nixpkgs/archive/0e575a459e4c3a96264e7a10373ed738ec1d708f.tar.gz"; # 2021-09-18
      # to find this, click on "commits" at https://github.com/NixOS/nixpkgs and then follow nose to get e.g. https://github.com/NixOS/nixpkgs/commit/0e575a459e4c3a96264e7a10373ed738ec1d708f, and then change "commit" to "archive" and add ".tar.gz"
    };
in
{
  imports =
    [
      ./hardware-configuration.nix
    ];

    nixpkgs.config = {
      packageOverrides = pkgs: {
        nixosRecentCommit = import nixosRecentCommitTarball {
          config = config.nixpkgs.config;
        };
      };
    };

and then:

environment.systemPackages = with pkgs; [

nixosRecentCommit.whatever-package
1 Like

(disclaimer that I haven’t tried this; & sorry about my earlier snippet not working)

Baking in @Mapybara 's suggestion to the snippet I suggested might look like:

      nixpkgs.config.packageOverrides = pkgs: {
        amuleDaemon =
          let
            pkgs-with-old-amule = import (builtins.fetchGit {
              name = "old-amule";
              url = "https://github.com/nixos/nixpkgs/";
              ref = "refs/heads/nixos-unstable";
              rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
            }) {
              config = config.nixpkgs.config;
            };
          in
          pkgs-with-old-amule.amuleDaemon;
      };

(what might be hard to tell is that the import ... is a builtin function).

And @TLATER 's suggestion might look like:

nixpkgs.config.packageOverrides = pkgs: {
  amuleDaemon = pkgs.amuleDaemon.overrideAttrs (oldAttrs: {
    src = pkgs.fetchFromGitHub {
      owner = "amule-project";
      repo = "amule";
      rev = "2.3.2";
      sha256 = "010wxm6g9f92x6fympj501zbnjka32rzbx0sk3a2y4zpih5d2nsn";
    };
  });
};

or the “copy paste the old derivation” would involve something like copying the old default.nix file in amule to /etc/nixos/pkgs/amuleDaemon/default.nix, and:

nixpkgs.config.packageOverrides = pkgs: {
  amuleDaemon = pkgs.callPackage ./pkgs/amuleDaemon {};
};

Inheriting the config from the system config is good, but you’ll also need to set the system arg to get around the error @ksten is seeing - I guess a second evaluation of nixpkgs needs to define that before it can be used:

      nixpkgs.config.packageOverrides = pkgs: {
        amuleDaemon =
          let
            pkgs-with-old-amule = import (builtins.fetchGit {
              name = "old-amule";
              url = "https://github.com/nixos/nixpkgs/";
              ref = "refs/heads/nixos-unstable";
              rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
            }) {
              config = config.nixpkgs.config;
              system = builtins.currentSystem; # Or you can set "x86_64" explicitly
              # Maybe this being a container is what makes `builtins.currentSystem` undefined?
            };
          in
          pkgs-with-old-amule.amuleDaemon;
      };
1 Like

Hey guys, I appreciate the help and have tried all of the suggestions. Unfortunately nothing is working, and it’s really worrying that such a simple task is so complicated and error prone on nixos :confused:

The config:

      nixpkgs.config.packageOverrides = pkgs: {
        amuleDaemon =
          let
            pkgs-with-old-amule = import (builtins.fetchGit {
              name = "old-amule";
              url = "https://github.com/nixos/nixpkgs/";
              ref = "refs/heads/nixos-unstable";
              rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
            }) {
              config = config.nixpkgs.config;
            };
          in
          pkgs-with-old-amule.amuleDaemon;
      };

Fails with:

error: attribute 'currentSystem' missing

       at /nix/store/176g3d0sly5d602qf8wcljc15584zngz-old-amule/pkgs/top-level/impure.nix:90:39:

           89|                 else (if args ? localSystem then {}
           90|                       else { system = builtins.currentSystem; }) // localSystem;
             |                                       ^
           91| })

The config:

      nixpkgs.config.packageOverrides = pkgs: {
        amuleDaemon = pkgs.amuleDaemon.overrideAttrs (oldAttrs: {
          src = pkgs.fetchFromGitHub {
            owner = "amule-project";
            repo = "amule";
            rev = "2.3.2";
            sha256 = "010wxm6g9f92x6fympj501zbnjka32rzbx0sk3a2y4zpih5d2nsn";
          };
        });
      };

Ignores the directive and tries to get the default amule 2.3.3 instead of 2.3.2 (which is even worse than erroring out because now you have silent failure):

error: Package ‘amule-2.3.3’ in /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/pkgs/tools/networking/p2p/amule/default.nix:55 is marked as broken, refusing to evaluate.

The config:

      nixpkgs.config.packageOverrides = pkgs: {
        amuleDaemon =
          let
            pkgs-with-old-amule = import (builtins.fetchGit {
              name = "old-amule";
              url = "https://github.com/nixos/nixpkgs/";
              ref = "refs/heads/nixos-unstable";
              rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
            }) {
              config = config.nixpkgs.config;
              system = builtins.currentSystem; # Or you can set "x86_64" explicitly
              # Maybe this being a container is what makes `builtins.currentSystem` undefined?
            };
          in
          pkgs-with-old-amule.amuleDaemon;
      };

Fails with:

error: attribute 'currentSystem' missing

       at /nix/store/adppy720xyjlcbgmqzlbl2h75ypyb90a-source/container-mule.nix:40:24:

           39|               config = config.nixpkgs.config;
           40|               system = builtins.currentSystem; # Or you can set "x86_64" explicitly
             |                        ^
           41|               # Maybe this being a container is what makes `builtins.currentSystem` undefined?
(use '--show-trace' to show detailed location information)

Switching builtins.currentSystem to "x86_64":

      nixpkgs.config.packageOverrides = pkgs: {
        amuleDaemon =
          let
            pkgs-with-old-amule = import (builtins.fetchGit {
              name = "old-amule";
              url = "https://github.com/nixos/nixpkgs/";
              ref = "refs/heads/nixos-unstable";
              rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
            }) {
              config = config.nixpkgs.config;
              system = "x86_64"; # Or you can set "x86_64" explicitly
              # Maybe this being a container is what makes `builtins.currentSystem` undefined?
            };
          in
          pkgs-with-old-amule.amuleDaemon;
      };

Fails with:

error: Target specification with 1 components is ambiguous
(use '--show-trace' to show detailed location information)

Adding --show-trace gives a 1400 line trace (cut short because of the 32000 character message limit):

[root@nas:/etc/nixos]# nixos-rebuild switch --show-trace --flake .
warning: Git tree '/etc/nixos' is dirty
building the system configuration...
warning: Git tree '/etc/nixos' is dirty
error: Target specification with 1 components is ambiguous

       … while evaluating the attribute '"1"'

       at /nix/store/176g3d0sly5d602qf8wcljc15584zngz-old-amule/lib/systems/parse.nix:370:5:

          369|   mkSkeletonFromList = l: {
          370|     "1" = if elemAt l 0 == "avr"
             |     ^
          371|       then { cpu = elemAt l 0; kernel = "none"; abi = "unknown"; }

       … while evaluating 'mkSkeletonFromList'

       at /nix/store/176g3d0sly5d602qf8wcljc15584zngz-old-amule/lib/systems/parse.nix:369:24:

          368|
          369|   mkSkeletonFromList = l: {
             |                        ^
          370|     "1" = if elemAt l 0 == "avr"

       … from call site

       at /nix/store/176g3d0sly5d602qf8wcljc15584zngz-old-amule/lib/systems/parse.nix:446:49:

          445|
          446|   mkSystemFromString = s: mkSystemFromSkeleton (mkSkeletonFromList (lib.splitString "-" s));
             |                                                 ^
          447|

       … while evaluating 'mkSystemFromString'

       at /nix/store/176g3d0sly5d602qf8wcljc15584zngz-old-amule/lib/systems/parse.nix:446:24:

          445|
          446|   mkSystemFromString = s: mkSystemFromSkeleton (mkSkeletonFromList (lib.splitString "-" s));
             |                        ^
          447|

       … from call site

       at /nix/store/176g3d0sly5d602qf8wcljc15584zngz-old-amule/lib/systems/default.nix:23:16:

           22|       # Prefer to parse `config` as it is strictly more informative.
           23|       parsed = parse.mkSystemFromString (if args ? config then args.config else args.system);
             |                ^
           24|       # Either of these can be losslessly-extracted from `parsed` iff parsing succeeds.

       … while evaluating the attribute 'parsed.abi.assertions'

       at /nix/store/176g3d0sly5d602qf8wcljc15584zngz-old-amule/lib/systems/default.nix:23:7:

           22|       # Prefer to parse `config` as it is strictly more informative.
           23|       parsed = parse.mkSystemFromString (if args ? config then args.config else args.system);
             |       ^
           24|       # Either of these can be losslessly-extracted from `parsed` iff parsing succeeds.

       … while evaluating 'foldl''

       at /nix/store/176g3d0sly5d602qf8wcljc15584zngz-old-amule/lib/lists.nix:82:16:

           81|     let
           82|       foldl' = n:
             |                ^
           83|         if n == -1

       … from call site

       at /nix/store/176g3d0sly5d602qf8wcljc15584zngz-old-amule/lib/lists.nix:86:8:

           85|         else op (foldl' (n - 1)) (elemAt list n);
           86|     in foldl' (length list - 1);
             |        ^
           87|

SNIP

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/attrsets.nix:301:19:

          300|           g =
          301|             name: value:
             |                   ^
          302|             if isAttrs value && cond value

       … from call site

       … while evaluating 'escapeShellArg'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/strings.nix:318:20:

          317|   */
          318|   escapeShellArg = arg: "'${replaceStrings ["'"] ["'\\''"] (toString arg)}'";
             |                    ^
          319|

       … from call site

       … while evaluating 'concatMapStringsSep'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/strings.nix:110:5:

          109|     # List of input strings
          110|     list: concatStringsSep sep (map f list);
             |     ^
          111|

       … from call site

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/nixos/modules/system/etc/etc.nix:54:43:

           53|     mkdir -p "$out/etc"
           54|     ${concatMapStringsSep "\n" (etcEntry: escapeShellArgs [
             |                                           ^
           55|       "makeEtcEntry"

       … while evaluating anonymous lambda

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/nixos/modules/system/etc/etc.nix:54:33:

           53|     mkdir -p "$out/etc"
           54|     ${concatMapStringsSep "\n" (etcEntry: escapeShellArgs [
             |                                 ^
           55|       "makeEtcEntry"

       … from call site

       … while evaluating 'concatMapStringsSep'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/strings.nix:110:5:

          109|     # List of input strings
          110|     list: concatStringsSep sep (map f list);
             |     ^
          111|

       … from call site

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/nixos/modules/system/etc/etc.nix:54:7:

           53|     mkdir -p "$out/etc"
           54|     ${concatMapStringsSep "\n" (etcEntry: escapeShellArgs [
             |       ^
           55|       "makeEtcEntry"

       … while evaluating the attribute 'buildCommand' of the derivation 'etc'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/pkgs/stdenv/generic/make-derivation.nix:205:7:

          204|     // (lib.optionalAttrs (attrs ? name || (attrs ? pname && attrs ? version)) {
          205|       name =
             |       ^
          206|         let

       … while evaluating the attribute 'value'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/modules.nix:452:44:

          451|       defnsByName' = byName "config" (module: value:
          452|           [{ inherit (module) file; inherit value; }]
             |                                            ^
          453|         ) configs;

       … while evaluating 'dischargeProperties'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/modules.nix:669:25:

          668|   */
          669|   dischargeProperties = def:
             |                         ^
          670|     if def._type or "" == "merge" then

       … from call site

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/modules.nix:598:137:

          597|         defs' = concatMap (m:
          598|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
             |                                                                                                                                         ^
          599|         ) defs;

       … while evaluating definitions from `/nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/nixos/modules/system/etc/etc.nix':

       … while evaluating anonymous lambda

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/modules.nix:597:28:

          596|         # Process mkMerge and mkIf properties.
          597|         defs' = concatMap (m:
             |                            ^
          598|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))

       … from call site

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/modules.nix:597:17:

          596|         # Process mkMerge and mkIf properties.
          597|         defs' = concatMap (m:
             |                 ^
          598|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))

       … while evaluating the attribute 'values'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/modules.nix:710:7:

          709|     in {
          710|       values = concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
             |       ^
          711|       inherit highestPrio;

       … while evaluating the attribute 'values'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/modules.nix:611:9:

          610|       in {
          611|         values = defs''';
             |         ^
          612|         inherit (defs'') highestPrio;

       … while evaluating the attribute 'mergedValue'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/modules.nix:617:5:

          616|     # Type-check the remaining definitions, and merge them. Or throw if no definitions.
          617|     mergedValue =
             |     ^
          618|       if isDefined then

       … while evaluating the option `system.activationScripts.etc.text':

       … while evaluating the attribute 'value'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/modules.nix:585:9:

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

       … while evaluating anonymous lambda

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/modules.nix:171:72:

          170|           # For definitions that have an associated option
          171|           declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options;
             |                                                                        ^
          172|

       … from call site

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/attrsets.nix:304:20:

          303|               then recurse (path ++ [name]) value
          304|               else f (path ++ [name]) value;
             |                    ^
          305|         in mapAttrs g set;

       … while evaluating 'g'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/attrsets.nix:301:19:

          300|           g =
          301|             name: value:
             |                   ^
          302|             if isAttrs value && cond value

       … from call site

       … while evaluating the attribute 'text'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/nixos/modules/system/activation/activation-script.nix:9:5:

            8|   addAttributeName = mapAttrs (a: v: v // {
            9|     text = ''
             |     ^
           10|       #### Activation script snippet ${a}:

       … while evaluating 'id'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/trivial.nix:14:5:

           13|     # The value to return
           14|     x: x;
             |     ^
           15|

       … from call site

       … while evaluating 'textClosureMap'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/lib/strings-with-deps.nix:75:35:

           74|
           75|   textClosureMap = f: predefined: names:
             |                                   ^
           76|     concatStringsSep "\n" (map f (textClosureList predefined names));

       … from call site

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/nixos/modules/system/activation/activation-script.nix:49:9:

           48|
           49|       ${textClosureMap id (withDrySnippets) (attrNames withDrySnippets)}
             |         ^
           50|

       … while evaluating 'systemActivationScript'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/nixos/modules/system/activation/activation-script.nix:20:33:

           19|
           20|   systemActivationScript = set: onlyDry: let
             |                                 ^
           21|     set' = mapAttrs (_: v: if isString v then (noDepEntry v) // { supportsDryActivation = false; } else v) set;

       … from call site

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/nixos/modules/system/activation/activation-script.nix:136:18:

          135|       apply = set: set // {
          136|         script = systemActivationScript set false;
             |                  ^
          137|       };

       … while evaluating the attribute 'system.activationScripts.script'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/nixos/modules/system/activation/activation-script.nix:136:9:

          135|       apply = set: set // {
          136|         script = systemActivationScript set false;
             |         ^
          137|       };

       … while evaluating the attribute 'activationScript' of the derivation 'nixos-system-nas-21.11.20211218.2627c4b'

       at /nix/store/idcl4krkhgqha859fdr1fgqgd4pda787-source/pkgs/stdenv/generic/make-derivation.nix:205:7:

          204|     // (lib.optionalAttrs (attrs ? name || (attrs ? pname && attrs ? version)) {
          205|       name =
             |       ^
          206|         let

I don’t know if I would call this nice, but doing the following in an overlay is one approach to that:

    amule = let
      amulepkgs = fetchFromGitHub {
        owner = "nixos";
        repo = "nixpkgs";
        rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
        sha256 = "sha256-5s9kWXCG+7eHoPG59yoxUOR+i26+oV4QWuvSTIKXZyI=";
      };
      libupnp = callPackage "${amulepkgs}/pkgs/development/libraries/pupnp/default.nix" {
        stdenv = final.stdenv // { inherit lib; };
      };
    in
    callPackage "${amulepkgs}/pkgs/tools/networking/p2p/amule/default.nix" {
      inherit libupnp;
      cryptopp = final.cryptopp.dev;
    };

A note on libupnp: amule (as defined in 2c162d4) doesn’t build with the currently packaged version of libupnp, and the old libupnp references stdenv.lib, which no longer exists.

Result:

$ ./result/sw/bin/amule --version
aMule 2.3.2 compiled with wxGTK2 v2.8.12 (OS: Linux)
1 Like

The version you see in that error message is the version string as defined on this line here: https://github.com/NixOS/nixpkgs/blob/3c54f634f0eec10efc4ac657185d244596b4893c/pkgs/tools/networking/p2p/amule/default.nix#L30, and strictly speaking (now with your override in place) doesn’t really mean anything. If you want to also update the version number as reported by nix simply add: version = "2.3.2"; along side the src definition.

In fairness, this is not a simple task. It’s actively impossible to do on any other Linux distro, specifically because of the things you’re running into (i.e., no guarantee of backwards compatibility between distro versions).

You can always download a binary version of the package and patchelf it, if that is the “simple” you’re looking for.

Unfortunately, I think in this case what you’re trying to achieve is very difficult without a downstream package, or some active upstream maintenance - it isn’t always, but packages that don’t build easily or change frequently are subject to issues like this.

Maybe I’ll have a half hour or so to put together a derivation for 2.3.2 for you this evening.

As @gravndal mentions, this is purely cosmetic. I doubt that will work though, because the build script changed a lot.

Hrm. The only thing I haven’t done before here is doing this in a container. Could you move that block into the real system config, just to keep me from suspecting container strangeness?

error: Target specification with 1 components is ambiguous

I think this is complaining that "x86_64" isn’t enough info to define a system. ("x86_64-linux" or "x86_64-darwin" would be target specifications with the arch and kernel components).

1 Like

As it seems you’re more interested in the daemon @ksten, given how amuleDaemon/amule-daemon [1] is defined, the above code snippet also works for that:

$ ./result/sw/bin/amuled --version
aMuleD 2.3.2 compiled with wxBase(GTK2) v2.8.12 (OS: Linux)

[1] It was recently renamed, though I don’t know whether that’s relevant to whatever channel you’re on.

1 Like

That is unfortunate.

In general, I’d say that with Nix/NixOS, it’s 95% wonderful and 5% complete pain in the butt. It’s partly because whenever something with Nix doesn’t work, there’s always something you’ll have to understand; and prior Linux/Unix understanding is bothe required, but also not necessarily helpful.

Maybe rolling the nix channel back to one which had amule 2.3.2 would be a quick+dirty workaround while waiting for amule 2.3.3 to work.

The solutions being discussed in this thread are more sophisticated than that. (Arguably more “right way to do it”, too). The Nix stuff shared in this thread is all various ways of “replace the amule package with an older version”… though, :wink: unfortunately apparently not quite the right code for “import a separate nixpkgs when defining a NixOS container”.

It’s worth pointing out separately that this clearly should just work™, sorry for triggering all the other noise @gravndal :slight_smile: I missed that because the reply seems to suggest it doesn’t, referring to missing references and whatnot.

Alright, next round:

      amule = let
        amulepkgs = fetchFromGitHub {
          owner = "nixos";
          repo = "nixpkgs";
          rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
          sha256 = "sha256-5s9kWXCG+7eHoPG59yoxUOR+i26+oV4QWuvSTIKXZyI=";
        };
        libupnp = callPackage "${amulepkgs}/pkgs/development/libraries/pupnp/default.nix" {
          stdenv = final.stdenv // { inherit lib; };
        };
      in
      callPackage "${amulepkgs}/pkgs/tools/networking/p2p/amule/default.nix" {
        inherit libupnp;
        cryptopp = final.cryptopp.dev;
      };

This one fails with:

error: undefined variable 'fetchFromGitHub'

       at /nix/store/c275ci05scg2qpcc2iypsvkh90xxjia6-source/container-mule.nix:31:21:

           30|       amule = let
           31|         amulepkgs = fetchFromGitHub {
             |                     ^
           32|           owner = "nixos";

This also didn’t work:

[root@nas:/etc/nixos]# ./result/sw/bin/amuled --version
bash: ./result/sw/bin/amuled: No such file or directory

Next up, I tried system = "x86_64-linux"

      nixpkgs.config.packageOverrides = pkgs: {
        amuleDaemon =
          let
            pkgs-with-old-amule = import (builtins.fetchGit {
              name = "old-amule";
              url = "https://github.com/nixos/nixpkgs/";
              ref = "refs/heads/nixos-unstable";
              rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
            }) {
              config = config.nixpkgs.config;
              system = "x86_64-linux"; # Or you can set "x86_64" explicitly
              # Maybe this being a container is what makes `builtins.currentSystem` undefined?
            };
          in
          pkgs-with-old-amule.amuleDaemon;
      };

When I do a rebuild, it grinds away for 2-3 minutes and then all higher networking stops working (except for ICMP; it responds fine to pings). SSH, HTTP, even a nc session are all frozen on the host. ACPI shutdown doesn’t work either, and probably a whole lot of other things but I can’t see it since it’s headless; I have to hold the power button for a hard shutoff.

I also tried putting the amule definition in the main flake.nix, but no matter where I put it, it just complains that it can’t find config.

error: undefined variable 'config'

       at /nix/store/zjdx5szayxll8ipcbv26fv5a05hrnl3g-source/flake.nix:28:32:

           27|                     }) {
           28|                       config = config.nixpkgs.config;
             |                                ^
           29|                     };

flake.nix:

{
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.11";
  outputs = { self, nixpkgs }:
    let
      hostName = "nas";
      # hostId is needed for zfs pools to identify their associated host
      hostId = "d8b1f65c";
      system = "x86_64-linux";
      # grubDevice is needed for BIOS booting
      grubDevice = "/dev/disk/by-id/usb-TS120GMT_S420S_20201013ABCD-0:0";
      ethernet = "enp1s0";
      macaddr = "12:4b:53:00:00:05";
      timezone = "Europe/Berlin";
    in {
      nixosConfigurations.${hostName} = nixpkgs.lib.nixosSystem {
        system = "${system}";
        modules =
          [ ({ pkgs, ... }: {
              nixpkgs.config.packageOverrides = pkgs: {
                amuleDaemon =
                  let
                    pkgs-with-old-amule = import (builtins.fetchGit {
                      name = "old-amule";
                      url = "https://github.com/nixos/nixpkgs/";
                      ref = "refs/heads/nixos-unstable";
                      rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
                    }) {
                      config = config.nixpkgs.config;
                    };
                  in
                  pkgs-with-old-amule.amuleDaemon;
              };

              # Let 'nixos-version --json' know about the git revision of this flake.
              system.configurationRevision = nixpkgs.lib.mkIf (self ? rev) self.rev;

              # Enable flakes experimental feature
              nix = {
                package = pkgs.nixFlakes;
                extraOptions = ''
                  experimental-features = nix-command flakes
                '';
                registry.nixpkgs.flake = nixpkgs;
              };

              boot = {
                kernelModules = [ "kvm-amd" "kvm-intel" ];
                extraModprobeConfig = "options kvm_intel nested=1";
                supportedFilesystems = [ "zfs" ];
                loader = {
                  systemd-boot.enable = true;
                  grub = {
                    enable = true;
                    version = 2;
                    device = "${grubDevice}";
                  };
                };
              };

              # Make sure /backup exists
              systemd.tmpfiles.rules = [
                "d /backup 744 root root -"
              ];

              time.timeZone = "${timezone}";

              networking = {
                hostName = "${hostName}";
                hostId = "${hostId}";
                bridges.br0.interfaces = [ "${ethernet}" ];
                useDHCP = false;
                interfaces = {
                  ${ethernet}.useDHCP = false;
                  br0 = {
                    useDHCP = true;
                    macAddress = "${macaddr}";
                  };
                };
                firewall.allowedTCPPorts = [ 22 5900 ];
              };

              users.users.root = {
                subUidRanges = [
                  {startUid=1000; count=1;}
                ];
                subGidRanges = [
                  {startGid=100; count=1;}
                ];
              };

              
              services.cron = {
                enable = true;
                systemCronJobs = [
                  "0 0 * * 3      root    /etc/nixos/scripts/backup.sh > /tmp/backup.log"
                ];
              };

              virtualisation.lxd.enable = true;

              virtualisation.libvirtd = {
                enable = true;
                allowedBridges = [ "br0" "virbr0" ];
              };

              services.openssh.enable = true;

              nixpkgs.config.allowUnfree = true;
              environment.systemPackages = with pkgs; [
                exif
                ffmpeg
                git
                gnupg
		            graphicsmagick
                htop
                libguestfs
                libosinfo
                p7zip
                python3
                telnet
                tree
                unrar
                unzip
                vim
                virt-manager
                wget
                zip
              ];

              imports = [
                ./hardware-configuration.nix
                ./user-karl.nix
                ./container-files.nix
                ./container-media.nix
                ./container-bt.nix
                ./container-kms.nix
                ./container-plex.nix
                #./container-mule.nix # this is the container I was working on
                ./container-fm.nix
              ];
            })
          ];
      };
    };
}

This slipped my mind when I wrote that, and so I apologise for not making that perfectly copy-pasteable for you: you’re missing some simple boilerplate in the form of a

let
    inherit (final) callPackage fetchFromGitHub;
in

block at the top of your overlay.

Or, if you don’t think you will be modifying other packages all that often, simply prepend the callPackage and fetchFromGitHub calls with final..

You haven’t built amuled yet, why would you expect that to do anything?

Edit: and for the error wrt a missing config, change:

          [ ({ pkgs, ... }: {

to

          [ ({ pkgs, config, ... }: {
1 Like

You haven’t built amuled yet, why would you expect that to do anything?

Probably because I’m well out of my depth at this point…

So I added that new let statement, but I’ve probably done it wrong since it’s now complaining about an unexpected let. Full container-mule.nix is:

{ config, pkgs, ... }:

let
  hostDataPath = "/home/data/mule";
  guestDataPath = "/amule";
  macaddr = "12:4b:53:00:00:24";
in {
  systemd.tmpfiles.rules = [
  "d ${hostDataPath} 755 karl users -"
  ];

  containers.mule = {
    autoStart = true;
    ephemeral = true;

    # Use a specific bridge instead of the host's networking
    privateNetwork = true;
    hostBridge = "br0";

    bindMounts = {
      "${guestDataPath}" = {
        hostPath = "${hostDataPath}";
        isReadOnly = false;
      };
    };

    config = { config, pkgs, ... }: {
      boot.isContainer = true;

      let
        inherit (final) callPackage fetchFromGitHub;
      in nixpkgs.config.packageOverrides = pkgs: {
        amuleDaemon =
          let
            pkgs-with-old-amule = import (builtins.fetchGit {
              name = "old-amule";
              url = "https://github.com/nixos/nixpkgs/";
              ref = "refs/heads/nixos-unstable";
              rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
            }) {
              config = config.nixpkgs.config;
              system = "x86_64-linux"; # Or you can set "x86_64" explicitly
              # Maybe this being a container is what makes `builtins.currentSystem` undefined?
            };
          in
          pkgs-with-old-amule.amuleDaemon;
      };

      networking.interfaces.eth0.useDHCP = true;

      # Hack: Change the MAC address before dhcpcd runs
      systemd.services.setmacaddr = {
        script = ''
          /run/current-system/sw/bin/ip link set dev eth0 address ${macaddr}
          /run/current-system/sw/bin/systemctl stop dhcpcd.service
          /run/current-system/sw/bin/ip addr flush eth0
          /run/current-system/sw/bin/systemctl start dhcpcd.service
        '';
        wantedBy = [ "basic.target" ];
        after = [ "dhcpcd.service" ];
      };

      # Make sure txuser exists (uid 1000)
      users.users.txuser.isNormalUser = true;

      # Make sure guest path exists
      systemd.tmpfiles.rules = [
      "d ${guestDataPath} 700 txuser users -"
      ];

      services.amule = {
        # Run "amuled --ec-config" to configure the service for the first time. 
        enable = true;
        dataDir = "${guestDataPath}";
        user = "txuser";
      };
    };
  };
}

Trying the config approach again… hang on.

Moving the amule stuff to the main flake.nix fails in the same way it did in the container:

[root@nas:/etc/nixos]# nixos-rebuild switch --flake .
warning: Git tree '/etc/nixos' is dirty
building the system configuration...
warning: Git tree '/etc/nixos' is dirty
error: attribute 'currentSystem' missing

       at /nix/store/176g3d0sly5d602qf8wcljc15584zngz-old-amule/pkgs/top-level/impure.nix:90:39:

           89|                 else (if args ? localSystem then {}
           90|                       else { system = builtins.currentSystem; }) // localSystem;
             |                                       ^
           91| })

flake.nix:

{
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.11";
  outputs = { self, nixpkgs }:
    let
      hostName = "nas";
      # hostId is needed for zfs pools to identify their associated host
      hostId = "d8b1f65c";
      system = "x86_64-linux";
      # grubDevice is needed for BIOS booting
      grubDevice = "/dev/disk/by-id/usb-TS120GMT_S420S_20201013ABCD-0:0";
      ethernet = "enp1s0";
      macaddr = "12:4b:53:00:00:05";
      timezone = "Europe/Berlin";
    in {
      nixosConfigurations.${hostName} = nixpkgs.lib.nixosSystem {
        system = "${system}";
        modules =
          [ ({ pkgs, config, ... }: {
              nixpkgs.config.packageOverrides = pkgs: {
                amuleDaemon =
                  let
                    pkgs-with-old-amule = import (builtins.fetchGit {
                      name = "old-amule";
                      url = "https://github.com/nixos/nixpkgs/";
                      ref = "refs/heads/nixos-unstable";
                      rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
                    }) {
                      config = config.nixpkgs.config;
                    };
                  in
                  pkgs-with-old-amule.amuleDaemon;
              };

              # Let 'nixos-version --json' know about the git revision of this flake.
              system.configurationRevision = nixpkgs.lib.mkIf (self ? rev) self.rev;

              # Enable flakes experimental feature
              nix = {
                package = pkgs.nixFlakes;
                extraOptions = ''
                  experimental-features = nix-command flakes
                '';
                registry.nixpkgs.flake = nixpkgs;
              };

              boot = {
                kernelModules = [ "kvm-amd" "kvm-intel" ];
                extraModprobeConfig = "options kvm_intel nested=1";
                supportedFilesystems = [ "zfs" ];
                loader = {
                  systemd-boot.enable = true;
                  grub = {
                    enable = true;
                    version = 2;
                    device = "${grubDevice}";
                  };
                };
              };

              # Make sure /backup exists
              systemd.tmpfiles.rules = [
                "d /backup 744 root root -"
              ];

              time.timeZone = "${timezone}";

              networking = {
                hostName = "${hostName}";
                hostId = "${hostId}";
                bridges.br0.interfaces = [ "${ethernet}" ];
                useDHCP = false;
                interfaces = {
                  ${ethernet}.useDHCP = false;
                  br0 = {
                    useDHCP = true;
                    macAddress = "${macaddr}";
                  };
                };
                firewall.allowedTCPPorts = [ 22 5900 ];
              };

              users.users.root = {
                subUidRanges = [
                  {startUid=1000; count=1;}
                ];
                subGidRanges = [
                  {startGid=100; count=1;}
                ];
              };

              
              services.cron = {
                enable = true;
                systemCronJobs = [
                  "0 0 * * 3      root    /etc/nixos/scripts/backup.sh > /tmp/backup.log"
                ];
              };

              virtualisation.lxd.enable = true;

              virtualisation.libvirtd = {
                enable = true;
                allowedBridges = [ "br0" "virbr0" ];
              };

              services.openssh.enable = true;

              nixpkgs.config.allowUnfree = true;
              environment.systemPackages = with pkgs; [
                exif
                ffmpeg
                git
                gnupg
                graphicsmagick
                htop
                libguestfs
                libosinfo
                p7zip
                python3
                telnet
                tree
                unrar
                unzip
                vim
                virt-manager
                wget
                zip
              ];

              services.amule = {
                # Run "amuled --ec-config" to configure the service for the first time. 
                enable = true;
                dataDir = "/tmp/amule";
                user = "karl";
              };

              imports = [
                ./hardware-configuration.nix
                ./user-karl.nix
                ./container-files.nix
                ./container-media.nix
                ./container-bt.nix
                ./container-kms.nix
                ./container-plex.nix
                #./container-mule.nix
                #./container-dev.nix
                ./container-fm.nix
              ];
            })
          ];
      };
    };
}

First, about builtins.currentSystem, this has nothing to do with it being a container or not, but rather with you using flakes (and thus being in a pure evaluation context): Some recommended reading: Nix Flakes, Part 1: An introduction and tutorial

Secondly, here’s my solution adapted to your config (which should work assuming I haven’t mistyped or overlooked something just now):

{ config, pkgs, ... }:

let
  hostDataPath = "/home/data/mule";
  guestDataPath = "/amule";
  macaddr = "12:4b:53:00:00:24";
in {
  systemd.tmpfiles.rules = [
  "d ${hostDataPath} 755 karl users -"
  ];

  containers.mule = {
    autoStart = true;
    ephemeral = true;

    # Use a specific bridge instead of the host's networking
    privateNetwork = true;
    hostBridge = "br0";

    bindMounts = {
      "${guestDataPath}" = {
        hostPath = "${hostDataPath}";
        isReadOnly = false;
      };
    };

    config = { config, pkgs, lib, ... }: {
      boot.isContainer = true;

      nixpkgs.overlays = [
        (final: prev: {
          amule = let
            amulepkgs = final.fetchFromGitHub {
              owner = "nixos";
              repo = "nixpkgs";
              rev = "2c162d49cd5b979eb66ff1653aecaeaa01690fcc";
              sha256 = "sha256-5s9kWXCG+7eHoPG59yoxUOR+i26+oV4QWuvSTIKXZyI=";
            };
            libupnp = final.callPackage "${amulepkgs}/pkgs/development/libraries/pupnp/default.nix" {
              stdenv = final.stdenv // { inherit lib; };
            };
          in
          final.callPackage "${amulepkgs}/pkgs/tools/networking/p2p/amule/default.nix" {
            inherit libupnp;
            cryptopp = final.cryptopp.dev;
          };
        })
      ];

      networking.interfaces.eth0.useDHCP = true;

      # Hack: Change the MAC address before dhcpcd runs
      systemd.services.setmacaddr = {
        script = ''
          /run/current-system/sw/bin/ip link set dev eth0 address ${macaddr}
          /run/current-system/sw/bin/systemctl stop dhcpcd.service
          /run/current-system/sw/bin/ip addr flush eth0
          /run/current-system/sw/bin/systemctl start dhcpcd.service
        '';
        wantedBy = [ "basic.target" ];
        after = [ "dhcpcd.service" ];
      };

      # Make sure txuser exists (uid 1000)
      users.users.txuser.isNormalUser = true;

      # Make sure guest path exists
      systemd.tmpfiles.rules = [
      "d ${guestDataPath} 700 txuser users -"
      ];

      services.amule = {
        # Run "amuled --ec-config" to configure the service for the first time. 
        enable = true;
        dataDir = "${guestDataPath}";
        user = "txuser";
      };
    };
  };
}

Also, to possibly pre-empt an issue you might hit if you’re on unstable, see: nixos/amuled: fix package reference in service definition by gravndal · Pull Request #163304 · NixOS/nixpkgs · GitHub

Edit: actually, to properly pre-empt that, a workaround until that gets merged is to add amuleDaemon = final.amule-daemon; to the overlay like so:

            cryptopp = final.cryptopp.dev;
          };
          amuleDaemon = final.amule-daemon;
        })
      ];
2 Likes