Добро пожаловать на третью Nix-пилюлю. Во второй пилюле мы установили Nix на свою систему.
Сейчас мы, наконец, можем с ним поэкспериментировать.
Статья будет полезной, даже если вы пользуетесь не просто Nix, а NixOS.

Начинаем погружение

Если вы используете NixOS, вы можете пропустить следующий раздел — Устанавливаем что-нибудь.

В предыдущей статье мы создали пользователя Nix. Давайте переключимся на него с помощью команды su - nix.
Если ваш ~/.profile уже создан, вам должны быть доступны команды наподобие nix-env и nix-store.

Если нет, запустите:

$ source ~/.nix-profile/etc/profile.d/nix.sh

В прошлой статье мы выяснили, что ~/.nix-profile/etc указывает на порождение nix-2.1.3.
В данный момент мы находимся в профиле пользователя Nix.

Устанавливаем что-нибудь

Наконец, практика!
Установка в окружение Nix — интересный процесс.
Начнём с hello — простой командной утилиты, которая печатает Hello world и часто используется для проверки компиляторов и пакетных менеджеров.

Итак, установка:

$ nix-env -i hello
installing 'hello-2.10'
[...]
building '/nix/store/0vqw0ssmh6y5zj48yg34gc6macr883xk-user-environment.drv'...
created 36 symlinks in user environment

Теперь можно запускать hello.
Прежде, чем двигаться дальше, зафиксируем несколько важных моментов:

  • Мы установили программу с правами пользователя Nix, и только для пользователя Nix.

  • Из-за этого появилось новое окружение пользователя (среда пользователя). Это — новое поколение профиля нашего пользователя Nix.

  • Утилита nix-env управляет окружениями, профилями и их поколениями.

  • Мы установили hello, используя только имя, без указания версии. Ещё раз: только имя порождения (без версии) для установки.

Мы можем вывести список поколений без блужданий по каталогу /nix:

$ nix-env --list-generations
   1   2014-07-24 09:23:30
   2   2014-07-25 08:45:01   (current)

Вывести установленные порождения:

$ nix-env -q
nix-2.1.3
hello-2.10

В какой каталог мы установили hello на самом деле? which hello даёт нам ~/.nix-profile/bin/hello, который указывает на хранилище.
Кроме того, мы можем вывести пути порождения с помощью команды nix-env -q --out-path.
Эти пути порождения называются выходом (out) сборки.

Слияние путей

Возможно, сейчас самое время запустить man чтобы получить кое-какую информацию.
Даже если у вас уже есть man в основной системе, вы можете установить её в окружение Nix с помощью команды nix-env -i man-db.

Взглянем на профиль:

$ ls -l ~/.nix-profile/
dr-xr-xr-x 2 nix nix 4096 Jan  1  1970 bin
lrwxrwxrwx 1 nix nix   55 Jan  1  1970 etc -> /nix/store/ig31y9gfpp8pf3szdd7d4sf29zr7igbr-nix-2.1.3/etc
[...]

Тут есть кое-что интересное.
Когда у было установлено только одно порождение nix-2.1.3, bin был симлинком на nix-2.1.3.
Теперь, когда мы дополнительно установили несколько программ (man, hello), он стал реальным каталогом, не симлинком.

$ ls -l ~/.nix-profile/bin/
[...]
man -> /nix/store/83cn9ing5sc6644h50dqzzfxcs07r2jn-man-1.6g/bin/man
[...]
nix-env -> /nix/store/ig31y9gfpp8pf3szdd7d4sf29zr7igbr-nix-2.1.3/bin/nix-env
[...]
hello -> /nix/store/58r35bqb4f3lxbnbabq718svq9i2pda3-hello-2.10/bin/hello
[...]

Так, кое-что проясняется. nix-env слил пути из установленных порождений.
which man указывает на профиль Nix, вместо того, чтобы указывать на системный man, потому что ~/.nix-profile/bin находится в начале $PATH (путь к системному man находится дальше в списке путей, а программа which выводит первый найденный — примечание переводчика).

Откат и переключение поколений

Последняя установленная команда — это man.
Сейчас мы должны находиться в поколении номер 3, если вы ничего не меняли на предыдущих шагах.
Попробуем откатиться к предыдущему поколению:

$ nix-env --rollback
switching from generation 3 to 2

Теперь nix-env -q не выводит man.
Команда ls -l `which man` должна вывести содержимое каталога основной системы.

Разобравшись с откатом, вернёмся в поколение 3:

$ nix-env -G 3
switching from generation 2 to 3

Самое время познакомиться со справкой на команду nix-env.
Для запуска nix-env нужно указывать операцию.
Можно добавлять опции.
Часть из них — общие, а часть — специфичные для отдельных операций.

Конечно, вы можете удалять и обновлять пакеты.

Запросы в хранилище

К текущему моменту мы научились исследовать и изменять окружение.
Поскольку все компоненты окружения указывают на хранилище, нам надо научиться работать и с хранилищем.

Для этого у нас есть команда nix-store.
Она предоставляет широкие возможности, но пока мы познакомимся только с несколькими видами запросов.

Выводим непосредственные зависимости программы hello:

$ nix-store -q --references `which hello`
/nix/store/fg4yq8i8wd08xg3fy58l6q73cjy8hjr2-glibc-2.27
/nix/store/58r35bqb4f3lxbnbabq718svq9i2pda3-hello-2.10

Аргумент nix-store может быть как файлом, так и каталогом, главное, чтобы он находился в хранилище Nix.
Утилита следует симлинкам.

Сейчас это может показаться неважным, но давайте просмотрим порождения, зависящие от hello:

$ nix-store -q --referrers `which hello`
/nix/store/58r35bqb4f3lxbnbabq718svq9i2pda3-hello-2.10
/nix/store/fhvy2550cpmjgcjcx5rzz328i0kfv3z3-env-manifest.nix
/nix/store/yzdk0xvr0b8dcwhi2nns6d75k2ha5208-env-manifest.nix
/nix/store/mp987abm20c70pl8p31ljw1r5by4xwfw-user-environment
/nix/store/ppr3qbq7fk2m2pa49i2z3i32cvfhsv7p-user-environment

Признайтесь, вы этого не ждали?
Оказывается, наши окружения зависят от hello.
Да, это значит, что окружения также находятся в хранилище, и поскольку они содержат симлинки на hello, каждое окружение зависит от hello.

Мы видим в списке два окружения, относящиеся к поколениям 2 и 3, так как именно они содержат установленную программу hello.

Файл manifest.nix содержит метаданные, относящиеся к окружению, например, список установленных порождений.
Команда nix-env может выводить, обновлять и удалять их.
И снова — текущий manifest.nix находится по пути ~/.nix-profile/manifest.nix.

Замыкания

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

$ nix-store -qR `which man`
[...]

Копирование всех этих порождений в хранилище на другой машине, позволит запустить на ней man, ничего больше не настраивая.
Это — основа развёртывания с помощью Nix. Думаю, вы уже догадываетесь, насколько это мощный и удобный инструмент для работы с облаком.

Вывод замыканий в удобном виде:

$ nix-store -q --tree `which man`
[...]

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

То же самое относится и к окружениям.
В качестве упражнения запустите nix-store -q --tree ~/.nix-profile и убедитесь, что прямыми наследниками окружения пользователя являются установленные порождения и файл manifest.nix.

Разрешение зависимостей

В Nix нет ничего похожего на утилиту apt которая решает задачу выполнимости булевых формул (SAT problem), чтобы подобрать зависимости с учётом верхних и нижних границ версий.
Вся эта сложность не нужна, потому что все зависимости статичны: если порождение X зависит от порождения Y, оно зависит от него всегда.
Порождение X, которое зависит от Z, должно быть другим порождением.

Ручное восстановление

$ nix-env -e '*'
uninstalling 'hello-2.10'
uninstalling 'nix-2.1.3'
[...]

Ой, команда удалила все порождения из окружения, включая Nix.
Это значит, что теперь мы не можем запустить даже nix-env.
Что делать?

Раньше мы получали доступ к nix-env из окружения.
Окружения удобны для пользователей, но Nix всё ещё находится в хранилище!

Сначала выберем одно из порождений nix-2.1.3: ls /nix/store/*nix-2.1.3. Пусть это будет /nix/store/ig31y9gfpp8pf3szdd7d4sf29zr7igbr-nix-2.1.3.

Первый способ всё починить — это откат:

$ /nix/store/ig31y9gfpp8pf3szdd7d4sf29zr7igbr-nix-2.1.3/bin/nix-env --rollback

Второй способ — установка nix-env, которая создаст новое поколение:

$ /nix/store/ig31y9gfpp8pf3szdd7d4sf29zr7igbr-nix-2.1.3/bin/nix-env -i /nix/store/ig31y9gfpp8pf3szdd7d4sf29zr7igbr-nix-2.1.3/bin/nix-env

Каналы

Откуда берутся пакеты?
Мы уже говорили об этом во второй статье.
Есть список каналов, откуда мы получаем пакеты, хотя обычно мы используем только один.
И есть утилита для управления каналами — nix-channel.

$ nix-channel --list
nixpkgs http://nixos.org/channels/nixpkgs-unstable

Если вы используете NixOS, команда может ничего не вывести (это зависит от настроек), либо вы можете увидеть канал, чьё имя начинается с "nixos-" вместо "nixpkgs".

По сути, это содержимое файла ~/.nix-channels.

?

~/.nix-channels — это не символическая ссылка на хранилище!

Для обновления канала запустите nix-channel --update.
Эта команда скачает новые выражения Nix (описания пакетов), создаст новое поколенение профиля каналов и распакует его в ~/.nix-defexpr/channels.

Она немного похожа на apt-get update.
(См. таблицу, где в первом приближении сравниваются средства управления пакетами Ubuntu и NixOS).

Заключение

Мы узнали, как исследовать окружение пользователя и изменять его, устанавливая и удаляя программы.
Обновлять программы тоже оказалось не сложно, подробности см. в руководстве (вкратце: nix-env -u обновит все пакеты в окружении).

Всякий раз, когда мы меняем среду, создаётся новое поколение.
Переключаться между поколениями легко и просто.

Далее, мы выяснили, как исследовать хранилище.
Мы изучили зависимости и обратные зависимости путей в хранилище.

Мы увидели, как симлинки используются для слияния путей из хранилища Nix — полезный трюк.

Подходящая аналогия с языками программирования: у вас есть куча с объектами, она похожа на хранилище Nix.
У вас есть объекты, которые указывают на другие объекты, что соответствует порождениям.
Это всего лишь наводящая метафора, возможно, она поможет нам двигаться в правильном направлении.

В следующей пилюле

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

Комментарии (0)