составление локальных пакетов nix

Я хочу запустить nix-shell со следующими установленными пакетами:

  • заклинание
  • aspellDicts.en
  • Привет

Я не могу просто сделать: nix-shell -p aspell aspellDicts.en hello --pure, так как это не приведет к правильной установке словарей aspell. Nix предоставляет aspellWithDict функцию, которую можно использовать для построения aspell со словарями:

nix-build -E 'with import <nixpkgs> {}; aspellWithDicts (d: [d.en])'

Я хочу использовать результат этой сборки как зависимость в другом локальном пакете (foo). Вот как я в настоящее время добиваюсь этого:

./pkgs/aspell-with-dicts/default.nix:

with import <nixpkgs> {};

aspellWithDicts (d: [d.en])

./pkgs/foo/default.nix:

{stdenv, aspellWithDicts, hello}:

stdenv.mkDerivation rec {
    name = "foo";
    buildInputs = [ aspellWithDicts hello ];
}

./custom-packages.nix:

{ system ? builtins.currentSystem }:

let
  pkgs = import <nixpkgs> { inherit system; };

in

rec {
  aspellWithDicts = import ./pkgs/aspell-with-dicts;

  foo = import ./pkgs/foo {
    aspellWithDicts = aspellWithDicts;
    hello = pkgs.hello;
    stdenv = pkgs.stdenv;
  };
}

Оболочка работает нормально: nix-shell ./custom-packages.nix -A foo --pure

Итак, мое решение работает, но можно ли достичь этого результата более лаконичным идиоматическим способом?


person b73    schedule 01.12.2017    source источник
comment
Куда вы хотите отправить свой foo пакет? Вы хотите разместить это в репозитории NixPkgs? Или это пакет, который вы хотите установить только локально? Может быть, вы хотите использовать его в своей компании?   -  person Robert Hensing    schedule 01.12.2017
comment
В этом случае foo - это то, что я просто хочу использовать локально.   -  person b73    schedule 01.12.2017


Ответы (2)


Чтобы сделать этот код более идиоматичным, у меня есть следующие предложения:

callPackage

Используйте функцию pkgs.callPackage. Он позаботится о передаче аргументов, которые нужны вашему производному. Вот почему многие файлы в NixPkgs выглядят как { dependency, ...}: something. Первый аргумент - это функция, в которую вы хотите внедрить зависимости, а второй аргумент - это набор атрибутов, который вы можете использовать для передачи некоторых зависимостей вручную.

При использовании callPackage вам не нужно import <nixpkgs> {}, поэтому ваш код будет проще использовать в новых контекстах, <nixpkgs> не может быть использован, и он будет оцениваться немного быстрее, потому что он должен оценивать фиксированную точку NixPkgs только один раз.

(Конечно, вам нужно import <nixpkgs> один раз, чтобы начать работу, но после этого в этом не должно быть необходимости.)

with

В pkgs/aspell-with-dicts/default.nix вы используете ключевое слово with, что нормально, но в данном случае оно не добавляет ценности. Я предпочитаю ссылаться на переменные явно, поэтому предпочитаю читать pkgs.something, если он используется один или два раза, или inherit (pkgs) something, если он используется чаще. Таким образом, читатель может легко определить, откуда взялась переменная.

Я использую его, когда экспериментирую с незнакомыми пакетами или функциями, потому что тогда обслуживание не является проблемой.

pkgs/aspell-with-dicts/default.nix

Если вы не ожидаете, что ваш экземпляр aspell будет чем-то, что вы хотите повторно использовать, вероятно, проще просто создать его там, где вы его используете.

Если вы действительно планируете повторно использовать определенную конфигурацию пакета, вы можете захотеть сделать его пакетом первого класса, построив его в наложении.


Вот и все. Я думаю, что самый важный момент - избегать <nixpkgs>, а в остальном это уже довольно идиоматично.

Я не знаю, что это за загадочный foo, но если это открытый исходный код, пожалуйста, подумайте о его апстриме в NixPkgs. По моему опыту, у Nix очень приветливое сообщество.

person Robert Hensing    schedule 02.12.2017
comment
Спасибо за ваши предложения, Роберт, которые очень помогли мне в обучении. - person b73; 03.12.2017

Вам нужно построить foo? Что в foo будешь использовать?

Предположим, вы хотите использовать оболочку только через nix-shell и не хотите создавать / устанавливать что-либо с помощью nix-build или nix-env -i, это должно сработать.

Следующие shell.nix

with import <nixpkgs> {};
with pkgs;

let
  myAspell = aspellWithDicts (d: [d.en]);
in
  stdenv.mkDerivation {
    name = "myShell";

    buildInputs = [myAspell hello];

    shellHooks = ''
      echo Im in $name.
      echo aspell is locate at ${myAspell}
      echo hello is locate at ${hello}
    '';
  }

даст вам оболочку с aspell и hello

$ nix-shell
Im in myShell.
aspell is locate at /nix/store/zcclppbibcg4nfkis6zqml8cnrlnx00b-aspell-env
hello is locate at /nix/store/gas2p68jqbzgb7zr96y5nc8j7nk61kkk-hello-2.10

Если это так, foo есть код для сборки и установки.

mkDerivation в foo/default.nix должно иметь поле src, которое может быть src = ./.; или что-то вроде fetchurl или fetchFromGithub (см. документ для примеров).

Затем вы можете использовать callPackages или import (зависит от того, как было написано выражение nix) с foo/default.nix в качестве аргумента, чтобы указать, что foo предоставлено для использования в этой оболочке.

Если вы попытаетесь построить этот shell.nix (или foo/default.nix), он потерпит неудачу из-за отсутствия src

$ nix-build shell.nix 
these derivations will be built:
  /nix/store/20h8cva19irq8vn39i72j8iz40ivijhr-myShell.drv
building path(s) ‘/nix/store/r1f6qpxz91h5jkj7hzrmaymmzi9h1yml-myShell’
unpacking sources
variable $src or $srcs should point to the source
builder for ‘/nix/store/20h8cva19irq8vn39i72j8iz40ivijhr-myShell.drv’ failed with exit code 1
error: build of ‘/nix/store/20h8cva19irq8vn39i72j8iz40ivijhr-myShell.drv’ failed
person wizzup    schedule 02.12.2017
comment
Спасибо, wizzup, поправьте меня, если я ошибаюсь, но я думаю, что buildInputs в вашем примере действительно должно быть [myAspell hello]. Если я внесу эту поправку, ваш пример будет работать должным образом. - person b73; 02.12.2017
comment
Если у shell.nix есть требование построить какое-то здание, нельзя ли его просто вызвать с помощью nix-build? Ваш shell.nix не определяет функцию верхнего уровня и, следовательно, не требует передачи зависимостей в качестве аргументов. Так что я не понимаю, зачем было бы использовать callPackage или import, если shell.nix что-то построил? Оцените ваш совет. - person b73; 02.12.2017
comment
Я имею в виду, что foo, похоже, не дает никаких результатов, потому что src отсутствует, поэтому я просто пропускаю его. Запуск nix-build foo/default.nix в любом случае не удастся. - person wizzup; 03.12.2017
comment
спасибо за информацию, особенно полезную, чтобы увидеть использование shellHooks. - person b73; 03.12.2017