fix: PageHead header alignment, analytics proxy, and infra improvements (#64)
🤖 Pull request created from `various-fixes` containing PageHead
breadcrumbs and navigation alignment fixes, Umami analytics proxy, and
infrastructure updates.
This commit is contained in:
1 parent
ff5a50bad8
commit
9ee672504f
110 files changed
+2649
-1760
No files matched your search
@@ -1,19 +1,19 @@
|
||||
---
|
||||
title: "Действия и оверлей"
|
||||
description: "Контракт действия и как узло-локальные проприетарии затеняют действия commons."
|
||||
description: "Контракт действия и затенение действий commons локальными проприетариями узла."
|
||||
weight: 13
|
||||
---
|
||||
|
||||
Каждая единица автоматизации в apex — это [действие](/apex/glossary#action): один Python-модуль, который [движок](/apex/glossary#engine) диспетчеризует по имени. [Оверлей](/apex/glossary#overlay) позволяет [проприетариям](/apex/glossary#proprietaries) узла добавлять, переопределять или отключать действия [«commons»](/apex/glossary#commons), не форкая их. Эта страница определяет контракт действия, декларативные дескрипторы аргументов и правила разрешения.
|
||||
Каждая единица автоматизации в apex — это [действие](/apex/glossary#action): один Python-модуль, который [движок](/apex/glossary#engine) диспетчеризует по имени. [Оверлей](/apex/glossary#overlay) позволяет [проприетариям](/apex/glossary#proprietaries) узла добавлять, переопределять или отключать действия [«commons»](/apex/glossary#commons) без создания форков. На этой странице описаны контракт действия, декларативные дескрипторы аргументов и правила разрешения.
|
||||
|
||||
## Контракт действия {#contract}
|
||||
|
||||
Действие — это один файл `.py` в дереве `actions/`. Путь к файлу **является** именем действия: `actions/<group>/<action>.py` вызывается как `apex <group>/<action> [args...]`. Нет реестра, который нужно обновлять — размещение файла в дереве публикует действие.
|
||||
Действие — это отдельный файл `.py` в дереве `actions/`. Путь к файлу служит именем действия: `actions/<group>/<action>.py` вызывается как `apex <group>/<action> [args...]`. Обновлять реестр не нужно: появление файла в дереве сразу публикует действие.
|
||||
|
||||
Модуль должен предоставлять две вещи:
|
||||
|
||||
- **`METADATA = Meta(...)`** → краткое описание и дескрипторы аргументов, которые управляют как текстом справки, так и парсингом. Система дескрипторов пришла на смену heredoc-у `action_metadata()` bash-фреймворка «root» commons, предшественника apex.
|
||||
- **`run(ctx, args)`** → точка входа. `ctx` — это построенный движком контекст выполнения; `args` — распарсенное пространство имён `argparse`.
|
||||
- **`METADATA = Meta(...)`** → краткое описание и дескрипторы аргументов, управляющие как текстом справки, так и парсингом. Система дескрипторов пришла на смену heredoc-блоку `action_metadata()` bash-фреймворка «root» commons, предшественника apex.
|
||||
- **`run(ctx, args)`** → точка входа. `ctx` — сформированный движком контекст выполнения; `args` — распарсенное пространство имён `argparse`.
|
||||
|
||||
```python {filename="actions/<group>/<action>.py"}
|
||||
from engine.descriptor import Meta, Arg, Flag
|
||||
@@ -31,38 +31,38 @@ def run(ctx, args):
|
||||
return 0
|
||||
```
|
||||
|
||||
Возвращаемое значение `run` становится кодом завершения процесса. Нецелочисленный возврат (включая `None`) трактуется как успех (`0`). Необработанное исключение логируется с префиксом контекста и завершается с кодом `1`.
|
||||
Возвращаемое значение `run` становится кодом завершения процесса. Нецелочисленный результат (включая `None`) трактуется как успешное завершение (`0`). Необработанное исключение логируется с префиксом контекста, после чего процесс завершается с кодом `1`.
|
||||
|
||||
> [!NOTE]
|
||||
> `METADATA` технически необязательна — модуль без неё диспетчеризуется с пустым `Meta` и не принимает аргументов — но каждое настоящее действие должно её объявлять, поскольку вывод в перечислении и `--help` генерируется из неё.
|
||||
> Технически `METADATA` необязательна: модуль без неё диспетчеризуется с пустым `Meta` и не принимает аргументов. Однако в реальных действиях её объявлять необходимо, поскольку вывод перечисления и справка `--help` генерируются именно из неё.
|
||||
|
||||
## Декларативные аргументы {#arguments}
|
||||
|
||||
`Meta.args` — это список дескрипторов. Каждый отображается ровно на одну конструкцию `argparse`:
|
||||
`Meta.args` — это список дескрипторов. Каждый отображается ровно на одну конструкцию `argparse`:
|
||||
|
||||
| Дескриптор | Отображается на | Поведение |
|
||||
| --- | --- | --- |
|
||||
| `Arg("name")` | позиционный аргумент | Обязателен по умолчанию; `required=False` делает его опциональным позиционным (`nargs="?"`, по умолчанию `None`). |
|
||||
| `Opt("--name", default=...)` | опция со значением | Опциональный флаг, принимающий значение, с объявленным значением по умолчанию. |
|
||||
| `Arg("name")` | позиционный аргумент | Обязателен по умолчанию; `required=False` делает его опциональным позиционным (`nargs="?"`, по умолчанию `None`). |
|
||||
| `Opt("--name", default=...)` | опция со значением | Опциональный флаг, принимающий значение, с объявленным значением по умолчанию. |
|
||||
| `Flag("--name")` | булев флаг | `store_true`; наличие означает `True`. |
|
||||
| `Rest("name")` | остаток | Жадная сквозная передача всех оставшихся argv (`argparse.REMAINDER`). |
|
||||
| `Rest("name")` | остаток | Жадная сквозная передача всех оставшихся аргументов командной строки (`argparse.REMAINDER`). |
|
||||
|
||||
Движок строит парсер как `apex <group>/<action>` и парсит оставшиеся argv перед вызовом `run`. `--help` обрабатывается на этапе парсинга. Ошибка использования — неизвестный флаг, отсутствующий позиционный аргумент — печатает usage и завершается с кодом `64` (`EX_USAGE`) вместо стандартного для argparse `2`.
|
||||
Движок строит парсер как `apex <group>/<action>` и разбирает оставшиеся аргументы перед вызовом `run`. Флаг `--help` обрабатывается на этапе парсинга. При ошибке использования (неизвестный флаг, отсутствующий позиционный аргумент) выводится справка по синтаксису (usage), а процесс завершается с кодом `64` (`EX_USAGE`) вместо стандартного для argparse кода `2`.
|
||||
|
||||
## Перечисление без импорта {#listing}
|
||||
|
||||
`apex` без аргументов (или `--help`) перечисляет каждое доступное действие. Перечисление никогда не импортирует модули действий: движок статически сканирует каждый файл модулем `ast` и извлекает только краткое описание `METADATA` и любую константу `DISABLED`. Поэтому код действия не может выполниться — или упасть — во время перечисления; файл, который не удаётся распарсить, перечисляется как `(unparseable)`, а не ломает перечисление.
|
||||
Команда `apex` без аргументов (или с флагом `--help`) выводит список всех доступных действий. Перечисление никогда не импортирует модули действий: движок статически сканирует каждый файл с помощью модуля `ast` и извлекает только краткое описание `METADATA` и любую константу `DISABLED`. Поэтому код действия не выполняется и не может вызвать сбой во время перечисления: файл, который не удалось распарсить, помечается как `(unparseable)`, не нарушая работу всей команды.
|
||||
|
||||
Каждая запись помечается своим источником оверлея:
|
||||
|
||||
- нет метки → действие commons,
|
||||
- `(local)` → существует только в проприетариях,
|
||||
- `(local override)` → действие проприетариев, затеняющее действие commons,
|
||||
- `[DISABLED: reason]` → действие объявляет `DISABLED`.
|
||||
- нет метки → действие commons;
|
||||
- `(local)` → существует только в проприетариях;
|
||||
- `(local override)` → действие проприетариев, затеняющее действие commons;
|
||||
- `[DISABLED: reason]` → действие объявляет константу `DISABLED`.
|
||||
|
||||
## Оверлей {#overlay}
|
||||
|
||||
Имена действий разрешаются по двум деревьям, сначала проприетарии:
|
||||
Имена действий разрешаются по двум деревьям, начиная с проприетариев:
|
||||
|
||||
{{< filetree/container >}}
|
||||
{{< filetree/folder name="node repository" state="open" >}}
|
||||
@@ -81,26 +81,26 @@ def run(ctx, args):
|
||||
{{< /filetree/folder >}}
|
||||
{{< /filetree/container >}}
|
||||
|
||||
Движок определяет эту схему по своему собственному расположению: когда он запускается из каталога `commons/`, родитель которого содержит `node.env`, родитель является корнем репозитория [узла](/apex/glossary#node), а `proprietaries/actions/` — деревом оверлея. Автономный checkout commons является собственным корнем и не имеет слоя оверлея. Внутри репозитория узла [идентичность узла](/apex/glossary#node-identity) разрешается из FQDN хоста перед диспетчеризацией.
|
||||
Движок определяет структуру размещения по своему расположению на диске: если запуск происходит из каталога `commons/`, а в родительском каталоге присутствует `node.env`, родительский каталог считается корнем репозитория [узла](/apex/glossary#node), а `proprietaries/actions/` — деревом оверлея. Автономный checkout commons сам выступает в качестве корня и не имеет слоя оверлея. Внутри репозитория узла [идентичность узла](/apex/glossary#node-identity) разрешается из FQDN хоста перед диспетчеризацией.
|
||||
|
||||
Разрешение для заданного имени проверяет `proprietaries/actions/<name>.py` первым и `commons/actions/<name>.py` вторым; ровно один модуль загружается по пути. Неизвестное имя — это ошибка (код завершения `1`). Оверлей поддерживает четыре приёма:
|
||||
При разрешении имени движок сначала проверяет `proprietaries/actions/<name>.py`, а затем `commons/actions/<name>.py`; по найденному пути загружается ровно один модуль. Неизвестное имя считается ошибкой (код завершения `1`). Оверлей поддерживает четыре сценария:
|
||||
|
||||
- **Добавление (Add)** → файл, существующий только в проприетариях, становится узло-локальным действием, перечисляется как `(local)`.
|
||||
- **Переопределение (Override)** → файл проприетариев по тому же относительному пути полностью затеняет реализацию commons; путь commons записывается в разрешении как `shadowed`.
|
||||
- **Обёртывание (Wrap)** → переопределяющий модуль может делегировать реализации, которую он затеняет, через `ctx.commons.run(args)`, добавляя узло-локальное поведение до или после логики commons вместо её замены.
|
||||
- **Отключение (Disable)** → модуль, присваивающий `DISABLED = "reason"`, отклоняется при диспетчеризации: движок логирует причину и завершается с кодом `1`. Перечисление показывает `[DISABLED: reason]`. Голый `DISABLED = True` также отключает, с обобщённой причиной `disabled`; пустая строка не отключает.
|
||||
- **Добавление (Add)** → файл, существующий только в проприетариях, становится локальным действием узла и отображается в списке как `(local)`.
|
||||
- **Переопределение (Override)** → файл проприетариев по тому же относительному пути полностью затеняет реализацию commons; путь commons помечается при разрешении как `shadowed`.
|
||||
- **Обёртывание (Wrap)** → переопределяющий модуль может делегировать вызов затенённой реализации через `ctx.commons.run(args)`, дополняя поведение commons локальной логикой узла до или после её вызова.
|
||||
- **Отключение (Disable)** → модуль с объявлением `DISABLED = "reason"` отклоняется при диспетчеризации: движок логирует причину и завершается с кодом `1`. При перечислении выводится `[DISABLED: reason]`. Простое значение `DISABLED = True` также отключает действие со стандартной причиной `disabled`; пустая строка действие не отключает.
|
||||
|
||||
## Коды завершения {#exit-codes}
|
||||
|
||||
Действия и движок следуют фиксированному соглашению о кодах завершения:
|
||||
Действия и движок следуют единому соглашению о кодах завершения:
|
||||
|
||||
| Код | Значение | Типичная причина |
|
||||
| --- | --- | --- |
|
||||
| `0` | успех | `run` вернул `0` или нецелочисленное значение. |
|
||||
| `0` | успех | Функция `run` вернула `0` или нецелочисленное значение. |
|
||||
| `1` | общая ошибка | Неизвестное действие, отключённое действие, необработанное исключение, нецелочисленный `SystemExit`. |
|
||||
| `64` | ошибка использования | Аргументы отклонены парсером (`EX_USAGE`). |
|
||||
| `65` | ошибка данных | Некорректные входные данные (`EX_DATAERR`), поднимается библиотеками движка. |
|
||||
| `66` | отсутствующий ввод | Требуемый ввод отсутствует (`EX_NOINPUT`), поднимается библиотеками движка. |
|
||||
| `65` | ошибка данных | Некорректные входные данные (`EX_DATAERR`), выбрасывается библиотеками движка. |
|
||||
| `66` | отсутствующий ввод | Требуемый ввод отсутствует (`EX_NOINPUT`), выбрасывается библиотеками движка. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in new issue
Block a user