Погружаемся в среду
Добро пожаловать на третью Nix-пилюлю. Во второй пилюле мы установили Nix в свою систему. Сейчас мы, наконец, устроим пару экспериментов. Эта статья будет полезной, даже если вы используете NixOS, а не просто Nix.
Начинаем погружение
Если вы используете 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
Теперь программу можно запускать. Прежде, чем двигаться дальше, зафиксируем несколько важных моментов:
- Мы установили программу с правами пользователя 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
.
Этот путь деривации называется выходом сборки.
Слияние путей
Сейчас вы, возможно, хотите запустить 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
), bin
стал реальным каталогом, не симлинком.
$ 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
1.
Откат и переключение поколений
Последняя установленная команда — это 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-copy-closures
и nix-store --export
).
Просмотр замыкания в виде дерева зависимостей:
$ 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. Поэтому очень важно понимать как синтаксис, так и семантику языка.
Это значит, что путь к системному man
находится в списке путей позже и программа which
его не видит — примечание переводчика.