Перейти к содержанию

Контракт шаблонов

Нормативная версия документации - английская

Эта страница переведена с английского языковой моделью. При любом расхождении верен английский оригинал.

Крейт поставляет шаблон для cargo generate. Шаблон проверяется в CI того же крейта, поэтому заготовка не расходится с его API.

Форма

Шаблон - это каталог, по которому cargo generate создаёт заготовку:

templates/<name>/
├── cargo-generate.toml   # манифест: описание, объявленные плейсхолдеры
├── Cargo.toml.liquid     # name = "{{project-name}}"; пины ruststream + крейта брокера
└── src/
    ├── main.rs           # билдер #[ruststream::app]
    ├── orders.rs         # обработчики #[subscriber]
    └── routes.rs         # Router, собирающий обработчики
  • Плейсхолдеры записываются на Liquid-синтаксисе cargo-generate. Плейсхолдер {{project-name}} встроен и принимает значение --name, поэтому минимальный шаблон не объявляет своих.
  • Манифест пакета называется Cargo.toml.liquid. При генерации cargo-generate убирает суффикс .liquid. Суффикс здесь не украшение: при поиске пакетов в git-источнике cargo разбирает каждый Cargo.toml репозитория и не смотрит на exclude. Из-за плейсхолдера в имени пакета cargo отвергает манифест, и эту ошибку видит любой, кто зависит от крейта по git-источнику. Так же называйте и любой другой шаблонный файл, который стал бы разбирать cargo.
  • Манифест пакета закрепляет ruststream на поддерживаемой минорной версии, а крейт брокера - на его собственной.
  • Один шаблон на транспорт или топологию брокера: например, nats и nats-js или redis-stream, redis-pubsub, redis-list.

Исходники шаблона содержат плейсхолдеры {{...}} и до генерации не проходят разбор ни как Rust, ни как TOML. Держите их вне рабочего пространства cargo: exclude = ["templates"].

Сборка в CI (сам контракт)

CI создаёт заготовку из каждого шаблона и компилирует её с закреплёнными версиями. Изменение API, ломающее заготовку, останавливает CI крейта, а не первую сборку у пользователя. Задача проверки:

  1. устанавливает cargo-generate,
  2. создаёт заготовку во временном каталоге (cargo generate --path templates/<name> --name smoke),
  3. запускает cargo check в этой заготовке.

Задача правит заготовку дважды. Сначала она переписывает требование версии на ту, которую собирает, и только это позволяет разрешиться неопубликованному предрелизу: [patch.crates-io] меняет источник крейта, но не диапазон версий, а предрелиз в диапазон без предрелиза не попадает. Затем она добавляет сам [patch.crates-io] с путём к локальной копии ядра. Это та же раскладка с соседними репозиториями, которой уже пользуется CI брокеров.

Только аддитивные блоки

Блоки под фичи только добавляют код: {% else %} и отрицательные ветки {% if not flag %} в шаблоне запрещены. Тогда заготовка без флагов - строгое подмножество заготовки со всеми фичами, и один cargo check со всеми фичами на шаблон обнаруживает любое расхождение с API.

С выключенными флагами возможны только ошибки написания шаблона: висящий use, незаполненный слот. Проверяйте их локально.

Кому что принадлежит

  • Ядро (ruststream) владеет только шаблоном templates/memory на своём in-memory брокере, поэтому cargo generate по умолчанию работает офлайн и без зависимости от крейта брокера.
  • Крейт брокера владеет шаблонами своих транспортов и проверяет их в своём CI.