如何在不抛出“不能将字符串强制转换为字符串”的情况下覆盖Nix派生词?

时间:2016-09-19 19:54:02

标签: nixos

或者,目标:如何以声明方式从Nix中获取单个包?

我是NixOS的新用户,目前正在尝试安装较新版本的Consul而不是我的NixOS版本的默认0.5.2(最新稳定版)。我试图通过覆盖/etc/nix/configuration.nix中的衍生物来尝试这一点。

我想保持稳定运行,但我发现不稳定的Consul版本我已经想要(0.7.0),所以我决定使用这个包的属性作为覆盖{{的起点3}}

我将其大部分复制到我的configuration.nix,以下是相关部分:

nixpkgs.config.packageOverrides = pkgs: rec {
  consul = pkgs.lib.overrideDerivation pkgs.consul (attrs: rec {
    version = "0.7.0";
    name = "consul-${version}";
    rev = "v${version}";

    goPackagePath = "github.com/hashicorp/consul";

    src = pkgs.fetchFromGitHub {
      owner = "hashicorp";
      repo = "consul";
      inherit rev;
      sha256 = "04h5y5vixjh9np9lsrk02ypbqwcq855h7l1jlnl1vmfq3sfqjds7";
    };

    # Keep consul.ui for backward compatability
    passthru.ui = pkgs.consul-ui;
  });
};

environment.systemPackages = with pkgs; [
  vim
  which
  telnet
  consul-ui
  consul-alerts
  consul-template
  consul
];

我正在运行nix-build (Nix) 1.11.2投掷:

$ nixos-rebuild switch
building Nix...
building the system configuration...
error: cannot coerce a set to a string, at /etc/nixos/configuration.nix:19:7
(use ‘--show-trace’ to show detailed location information)

当我查看第19行时,name设置为"consul-${version}"

为什么会出现类型强制?任何提示将不胜感激!

我也想知道是否有更好的方法可以在不稳定的情况下运行单个包,但是从configuration.nix以声明方式执行,而不是强制执行?

2 个答案:

答案 0 :(得分:4)

添加Rok所说的内容:

  

哪个应该指出错误实际发生在passthru,line。如果你评论它可能会建立。我假设有一些递归调用在这里发挥作用,当它试图评估consul / consul-ui包时会发生错误。

如果你刚刚开始,你可以放心地忽略下面的内容,如果你对这个细节很好奇,可能会回过头来。

这里的问题是overrideDerivation是一种覆盖事物的低级方法。在stdenv.mkDerivation后面,我们有一个更小的原始函数,叫做derivationderivation函数需要一些属性,(或多或少 - 请参阅文档以获取更精细的细节)在构建期间将这些属性作为环境变量传递。另一方面,stdenv.mkDerivation函数在顶部分层设置了一大堆智能,在将它们传递到derivation之前按摩给它的属性 - 在某些情况下,如同passthru,它根本不会将该属性传递给derivation

返回overrideDerivation:它需要stdenv.mkDerivation传递给derivation的最终调整属性,在此之前,它允许您使用您提供的函数覆盖这些属性它(例如,这意味着,此时passthru已被删除)。当您的函数添加passthru时,它会进入derivation,然后它会将passthru的值强制转换为字符串,以便它可以使passthru成为一个环境变量在建设期间;但是,因为passthru现在指向属性集,并且不支持这样的强制,Nix然后抱怨。

所以这种情况让我们处于一种奇怪的境地。为了说明,我将在这里复制领事包的来源:

{ stdenv, lib, buildGoPackage, consul-ui, fetchFromGitHub }:

buildGoPackage rec {
  name = "consul-${version}";
  version = "0.6.4";
  rev = "v${version}";

  goPackagePath = "github.com/hashicorp/consul";

  src = fetchFromGitHub {
    owner = "hashicorp";
    repo = "consul";
    inherit rev;
    sha256 = "0p6m2rl0d30w418n4fzc4vymqs3vzfa468czmy4znkjmxdl5vp5a";
  };

  # Keep consul.ui for backward compatability
  passthru.ui = consul-ui;
}

(请注意buildGoPackagestdenv.mkDerivation的包装。)

你可能熟悉例如consul.override,它允许您提供不同的输入(例如,可能是consul-uibuildGoPackage的不同版本),但它不允许您覆盖 aren'的内容t 输入(例如srcpassthru等)。同时,overrideDerivation允许您修改授予derivation的attrs,但赋予stdenv.mkDerivation的attrs。理想情况下,介于两者之间会有一些东西可以操纵给予stdenv.mkDerivation的attrs,而恰好有一个PR可以解决这个问题:

https://github.com/NixOS/nixpkgs/pull/18660

答案 1 :(得分:3)

欢迎来到Nix / NixOS:)

每当您需要了解有关错误的更多信息时,您可以使用--show-trace,这会给您更详细的错误。在你的情况下,你会看到类似

的东西
error: while evaluating the attribute ‘passthru’ of the derivation ‘consul-0.7.0’ at /home/rok/tmp/consul.nix:6:3:
cannot coerce a set to a string, at /home/rok/tmp/consul.nix:6:3

哪个应该指出错误实际发生在passthru,line。如果你评论它可能会建立。我假设有一些递归调用在这里发挥作用,当它试图评估consul / consul-ui包时会发生错误。

至于覆盖不稳定频道的一个包,需要这样的东西

let
  unstable_pkgs = import ./path/to/unstabe/nixpkgs {};
  # or
  # unstable_pkgs = import (pkgs.fetchFromGitHub {...}) {};
in {
  ...
  nixpkgs.config.packageOverrides = pkgs: rec {
    consul = unstable_pkgs.consul;
  };
  ...
}

我没有尝试过上述内容,但我认为它会起作用。