Добро пожаловать на третью 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.
Поэтому очень важно понимать как синтаксис, так и семантику языка.