Как записать воспроизводимый профиль в nix (особенно из nix-env)?

Итак, наконец-то я начал получать стабильную среду nix, в которой я могу заниматься практически всеми своими разработками. Ура!

Теперь я хочу сделать его воспроизводимым, как в yarn.lock (для тех, кто знаком с npm / yarn в javascript land) или Pipfile.lock (очень похоже на Python).

По сути, идея заключается в том, чтобы у меня был способ генерировать аналогичный файл блокировки всякий раз, когда я запускаю nix-env -if my-env.nix или после выполнения этой команды, если это так. Из этого файла блокировки я мог затем точно восстановить свой профиль nix, вплоть до точных версий зависимостей и суб-зависимостей установленного профиля. Это может быть проверено в git или в любом другом месте после тестирования новых улучшений, и поэтому будет поддерживаться запись среды.

Мне кажется, что это будет один из наиболее очевидных вариантов использования Nix и одно из основных преимуществ по сравнению с простым использованием Docker (хотя оба они не являются взаимоисключающими), поэтому я прошу прощения, если пропустил какую-то соответствующую документацию.

2 ответа

Решение

То, что вы, вероятно, ищете shell.nix файл как это:

let
  pkgs = import (fetchTarball {
    url = "https://github.com/NixOS/nixpkgs/archive/696c6bed4e8e2d9fd9b956dea7e5d49531e9d13f.tar.gz";
    sha256 = "1v3yrpj542niyxp0h3kffsdjwlrkvj0mg4ljb85d142gyn3sdzd4";
  }) {};
in pkgs.mkShell {
  buildInputs = with pkgs; [
    git
    hello
  ];
}

По вызову nix-shell (который по умолчанию использует shell.nix файл в текущем каталоге), вы будете в среде с git а также hello из конкретной данной ревизии nixpkgs. Это может быть воспроизведено среди всех пользователей nix (хорошо, почти *). Я действительно могу рекомендовать использовать shell.nix файлы для всей разработки.

Кроме того, есть и менее известные -r флаг для nix-env, в котором говорится, что

--remove-all, -r

Сначала удалите все ранее установленные пакеты. Это эквивалентно запуску nix-env -e '.*' В первую очередь, за исключением того, что все происходит в одной транзакции.

Вы можете эффективно использовать его для замены состояний ~/.nix-profile/manifest.nix, Создать файл env.nix содержащий:

let
  pkgs = import <nixpkgs> {};
in {
  inherit (pkgs) git hello;
}

Сейчас работает nix-env -ir env.nix установит точно git а также hello и удалите все остальное, чтобы вы могли воспроизвести ваши установки nix-env с этим единственным файлом. Чтобы установить дополнительные вещи: добавьте его в файл и снова введите команду. Вы также можете прикрепить nixpkgs к определенной версии, как в приведенном выше файле, чтобы не заботиться о вашей nix-channel установка (которая также с состоянием).

Изменить: Также возможно получить некоторые пакеты из вашего канала и некоторые из конкретных ревизий nixpkgs:

let
  pkgs = import <nixpkgs> {};
  fixed = import (fetchTarball {
    url = "https://github.com/NixOS/nixpkgs/archive/696c6bed4e8e2d9fd9b956dea7e5d49531e9d13f.tar.gz";
    sha256 = "1v3yrpj542niyxp0h3kffsdjwlrkvj0mg4ljb85d142gyn3sdzd4";
  }) {};
in {
  inherit (pkgs) git;
  inherit (fixed) hello;
}

*: Конфигурация nix, оверлеи и ваша система (Linux/Mac) могут по-прежнему влиять на это. Это хорошая идея для использования import <nixpkgs> { config = {}; overlays = []; } для развития, чтобы избежать этого.

После множества предложений от пользователей IRC я ​​смог собрать следующий скрипт, который принимает выражение nix в качестве единственного аргумента, копирует файл деривации и записывает версии nixpkgs локально при установке указанной среды:

#!/bin/bash

if [ -z "$1" ] || [ "${1: -4}" != ".nix" ] || [ ! -f "$1" ]
  then
      echo "No .nix file supplied"
      exit -1
fi

ENV_DRV=$(nix-instantiate "$1")
cp "$ENV_DRV" ./env_backup.drv
chmod u+rw ./env_backup.drv
nix-env --set "$ENV_DRV"


NIXPKGS_VERSION=$(nix-instantiate --eval '<nixpkgs/lib>' -A version)
NIXOS_VERSION=$(nix-instantiate --eval '<nixos/lib>' -A version)

printf "nixpkgs: %s\\nnixos: %s" "$NIXPKGS_VERSION" "${NIXOS_VERSION}" > .nix_versions

Предостережение: ваше выражение nix должно иметь nix пакет в нем, так как мы используем nix-env --set,

Я еще не пробовал использовать скопированный файл.drv, но его нужно каким-то образом восстановить в хранилище nix; Я в основном включил это в качестве крайней меры и для отладки. Выход в .nix_versions должно быть более полезным, так как они содержат хиты git commit (после последнего "."), которые могут использоваться для использования правильной ревизии nixpkgs (благодаря infinisil на IRC):

pkgs = import "${(import <nixpkgs> {}).fetchFromGitHub { owner = "NixOS"; repo = "nixpkgs"; rev = "<your revision hash>"; sha256 = "<the hash of the output>"; }}" {}

Чтобы заполнить хеш, либо предоставьте неверный хеш, чтобы получить правильный хеш, либо просто используйте следующее: nix-prefetch-url --unpack github.com/nixos/nixpkgs/archive/<revision>.tar.gz,

Или, если вы вручную проверяете nixpkgs, вы можете просто сделать, например:

with import ((builtins.getEnv "HOME") + "/workspace/nixpkgs") { }; # or:
with import "../nixpkgs" { }; # or similar

Я не проверял такого рода вещи с nix-shell пока, но надеюсь сделать это в ближайшее время.

Другие вопросы по тегам