Существует способ, позволяющий dhall
создавать "автономные" сборки, что означает, что менеджер пакетов выбирает все зависимости Dhall, а не извлекает их из Dhall.
Фактически, я реализовал кое-что именно для Nixpkgs , который вы можете перевести на Bazel:
Объяснение высокого уровня
Основной трюк c состоит в том, чтобы воспользоваться преимуществом системы импорта Dhall, которая заключается в том, что если кешируется пакет, защищенный проверкой целостности semanti c (т.е. "semanti c ha sh"), то Dhall будет использовать кеш вместо загрузки пакета. Вы можете использовать этот трюк, чтобы менеджер пакетов обходил удаленный импорт Dhall, внедряя зависимости таким образом.
Здесь вы можете найти логику, связанную с Nix c, для этого здесь:
... но я постараюсь объяснить, как это работает независимо от менеджера пакетов.
Структура пакета
Во-первых, конечным продуктом "пакета" Dhall, созданного с использованием Nix, является каталог со следующей структурой:
$ nix-build --attr 'dhallPackages.Prelude."13.0.0"'
…
$ tree result
Содержимое этого каталога:
./cache/dhall/1220XXX…XXX
Действительный каталог кэша для Dhall, содержащий один продукт сборки: двоичное кодирование интерпретированного выражения Dhall.
Вы можете создать такой двоичный файл, используя dhall encode
, и вы можете вычислить имя файла, заменив XXX…XXX
выше кодировкой выражения sha256
, которую можно получить с помощью команды dhall hash
.
./binary.dhall
A удобный файл Dhall, содержащий выражение missing sha256:XXX…XXX
. Интерпретация этого выражения будет успешной только в том случае, если созданное нами выражение, совпадающее с ha sh sha256:XXX…XXX
, уже кэшировано.
Файл называется binary.dhall
, поскольку это эквивалент Dhall "двоичного" распределения пакетов, Это означает, что импорт может быть получен только из двоичного кэша и не может быть выбран и интерпретирован из источника.
Необязательно: ./source.dhall
Это файл, содержащий полностью αβ-нормализованное выражение, эквивалентное выражению, которое было кэшировано. По умолчанию это должно быть пропущено для всех пакетов, кроме, возможно, пакета верхнего уровня, поскольку оно содержит то же выражение, которое хранится в ./cache/1220XXX…XXX
, хотя и менее эффективно (поскольку двоичная кодировка более компактна)
Этот файл называется ./source.dhall
, потому что это эквивалент Dhall «исходного» дистрибутива пакета, который содержит действительный исходный код для получения того же результата.
Пользовательский интерфейс
Функция для сборки пакета принимает четыре аргумента:
Имя пакета
Это не материал для сборки. Это просто название, так как каждый пакет Nix должен иметь удобочитаемое имя.
Зависимости для сборки
Каждая из этих зависимостей является продуктом сборки, который создает дерево каталогов точно так же, как я описал выше (то есть каталог ./cache
, файл ./binary.dhall
и необязательный файл ./source.dhall
)
выражение Dhall
Это может быть произвольный исходный код Dhall только с одним предупреждением: все удаленные импорты, на которые ссылается выражение, должны быть защищены проверками целостности, и эти импорты должны соответствовать одной из зависимостей этого пакета Dhall (так, чтобы импорт может быть выполнено через кеш вместо времени выполнения Dhall, извлекающего URL)
Логическая опция, указывающая, сохранять ли файл ./source.dhall
, который по умолчанию False
Реализация
Способ работы сборщика пакетов Dhall:
Сначала создайте пакет Haskell Dhall с флагом -f-with-http
Этот флаг компилирует поддержку удаленного импорта HTTP, таким образом, если пользователь забудет предоставить зависимость для удаленного импорта, он получит сообщение об ошибке, говорящее Import resolution is disabled
Мы будем использовать этот исполняемый файл для всех последующих шагов
Создайте каталог кэша в текущем рабочем каталоге с именем .cache/dhall
... и заполните каталог кэша сохраненными двоичными файлами внутри каталога ./cache/
каждой зависимости
Сконфигурируйте интерпретатор для использования каталога кэша, который мы создали
..., установив XDG_CACHE_HOME
для указания на .cache
каталог, который мы только что создали в нашем текущем рабочем каталоге
Интерпретировать и α-нормализовать исходный код Dhall для нашего пакета
... с помощью команды dhall --alpha
. Сохраните результат в $out/source.dhall
, где $out
- это каталог, в котором будет храниться конечный продукт сборки
Получите выражение ha sh
... используя команда dhall hash
. Нам понадобится это ha sh для следующих двух шагов.
Создайте соответствующий двоичный файл кэша
... с помощью команды dhall encode
и сохраните файл в $out/cache/dhall/1220${HASH}
Создайте файл ./binary.dhall
..., просто записав текстовый файл в $out/binary.dhall
, содержащий missing sha256:${HASH}
Необязательно: Удалите файл ./source.dhall
..., если пользователь не запросил сохранить файл. Пропуск этого файла по умолчанию помогает сэкономить место в хранилище пакетов, не сохраняя одно и то же выражение дважды (как двоичный файл и исходный код).
Соглашения об упаковке
Если у вас есть эта функция, есть пара соглашений, которые могут помочь упростить выполнение «в целом»
По умолчанию пакет должен создавать файл ./package.dhall
проекта
Упрощение переопределения версии пакета
Упрощение переопределения файла, встроенного в пакет
Другими словами Если пользователь предпочитает импортировать отдельные файлы, такие как https://prelude.dhall-lang.org/List/map
, вместо файла ./package.dhall
верхнего уровня, у них должен быть способ указать зависимость, такую как Prelude.override { file = "./List/map"; }
, для получения пакета, который создает и кэширует этот отдельный файл.
Заключение
Надеюсь, это поможет! Если у вас есть дополнительные вопросы о том, как это сделать, вы можете задать их здесь или обсудить больше на нашем форуме, особенно в теме, где впервые возникла эта идиома: