dwe vars — работа с песочницей vars:
vars: — единственный формализованный дом для произвольных, специфичных для
проекта значений в объединённом 3-слойном конфиге (см. workspace.md → Строгий
корень + песочница vars:).
Поскольку теперь каждое пользовательское значение живёт под одним namespace,
dwe vars — это первоклассный инструмент для перечисления, чтения,
редактирования и трассировки этих значений.
Содержание
Заголовок раздела «Содержание»- Модель данных
- Подкоманды
- Сохраняющая комментарии запись в
local.yml - Статическое сканирование использований
- JSON-вывод
- Поведение в контейнере и
bridge.vars_writable - Связанные команды
Модель данных
Заголовок раздела «Модель данных»Var — это листовой dot-path под vars: — например, vars.db.password.
Вложенные map’ы — это namespace’ы (узлы дерева), а не vars. Для:
vars: db: user: root password: secret app: timeout: 30листья (vars) — это vars.db.user, vars.db.password и vars.app.timeout;
vars.db и vars.app — namespace’ы.
Каждый var разрешается по трём слоям конфига:
| Слой | Источник | Значение |
|---|---|---|
| default | workspace.yml / defaults.yml | Трекаемый, общекомандный дефолт |
| local | workspace/local.yml | Gitignore’нутый, персональный override |
| current | после merge | То, во что реально разрешается ${vars.x} (local побеждает) |
Origin var’а — это наивысший слой, дающий значение, то есть файл, который «выигрывает» merge для этого пути.
Префикс
vars.необязателен. Внутриdwe varsлюбой путь — это var, поэтомуget,set,inspectи фильтр namespace уlistпринимают сокращённую форму:dwe vars get db.hostэквивалентноdwe vars get vars.db.host. Префикс также убирается из вывода (в JSON, автодополнении и хранилище остаётся канонический путь). Голова не изvarsнормализуется внутрь песочницы (project.name→vars.project.name) и никогда не резолвится в реальный конфиг проекта — так что ограничение на чтение и allowlist на запись из контейнера сохраняются.
Подкоманды
Заголовок раздела «Подкоманды»dwe vars list
Заголовок раздела «dwe vars list»dwe vars list [namespace]Плоский список каждого листа vars.* с его эффективным значением и бейджем слоя
(local, когда действует override из local.yml, иначе default).
Необязательный аргумент namespace фильтрует поддерево (например,
dwe vars list db), зеркаля dwe commands list.
dwe vars get
Заголовок раздела «dwe vars get»dwe vars get <var>Вывести одно значение. Листовой путь печатает скаляр; путь-namespace (vars.db)
печатает всё поддерево как YAML. Показывается эффективное (после merge)
значение. Путь, который ни во что не разрешается, — это типизированная ошибка
vars_not_found. Чтение ограничено vars.* — путь, чей первый сегмент не
vars (например, project.name), возвращает vars_not_found, а не
разрешается по остальному конфигу проекта, чтобы доступная из контейнера
поверхность vars не утекала произвольный конфиг хоста.
dwe vars inspect
Заголовок раздела «dwe vars inspect»dwe vars inspect <var>Полная картина по одному var’у:
- Значения по слоям — default (общекомандный), local-override, current (после merge).
- Origin — относительный к проекту файл, выигрывающий merge.
- Каждое статическое использование — каждое место ссылки на var, как
file:lineс текстом совпавшей строки. См. статическое сканирование использований.
Var, который нигде не разрешается и не имеет использований, — это
vars_not_found. Inspect сопоставляет как точный путь, так и префикс namespace:
dwe vars inspect db показывает использования vars.db.host,
vars.db.user и т. д. Как и get, инспекция ограничена vars.* — путь не
из vars даёт vars_not_found.
dwe vars set
Заголовок раздела «dwe vars set»dwe vars set <var> [value]Записать override var’а в workspace/local.yml, сохраняя окружающие комментарии
и форматирование (см. сохраняющая комментарии запись).
-
Ограничение пути до
vars.*— любой<var>, чей первый сегмент неvars, отклоняется сvars_path_invalid. Это также граница доверия контейнера (см. поведение в контейнере). -
Приведение значения — аргумент
valueпарсится как один YAML-скаляр. Типизированные скаляры становятся типизированными:true/false→ bool,42→ int,1.5→ float, простой текст → строка. Явное кавычивание оставляет строку:set x '"42"'записывает строку"42". Map’ы ({a: b}) и последовательности ([a]) отклоняются — var это лист. Закреплённые неоднозначные случаи:Ввод Результат ""(пустой аргумент, съеден shell)YAML null '""'(явный пустой литерал)пустая строка null,~YAML null yes/no/on/offстрока (не bool YAML 1.1) 0755,01(ведущий ноль)строка (без потери при octal-реинтерпретации) 1.2.3строка 2024-01-02(голый timestamp)строка -
Без
value(интерактивно) — открывает формуhuhс одним полем ввода и контекстом в стиле inspect (текущие значения по слоям). Submit пишет через тот же путь. В JSON / неинтерактивном режиме опусканиеvalue— это типизированная ошибкаvars_value_required(форма не открывается).
set захватывает проектные локи (симметрия с dwe services enable/disable,
которые делят тот же writer local.yml — set без локов мог бы гонками
пересечься с держащим лок toggle на том же файле). Он не запускает preflight
(это не мутация lifecycle/стека). При любой ошибке после записи прежние байты
local.yml восстанавливаются, затем конфиг перезагружается, чтобы последующий
вывод отражал запись.
dwe vars (без аргументов) — TUI-браузер
Заголовок раздела «dwe vars (без аргументов) — TUI-браузер»Запуск dwe vars без подкоманды открывает интерактивный браузер (тот же виджет,
что и у dwe commands): дерево namespace’ов всех vars, оверлей inspect и
действие edit (Enter на листе).
Редактирование без выхода (терминалы ≥ 80 колонок). Enter открывает форму
set как оверлей поверх браузера — дерево остаётся видимым (затемнённым) под
ней. Введите новое значение (некорректный ввод — map, последовательность,
непреобразуемый скаляр — отклоняется на месте), нажмите Enter для сохранения, и
оверлей закроется: отредактированная строка обновится на месте (новое значение +
бейдж слоя), оверлей inspect отразит новое значение, а в строке статуса на ~2
секунды мигнёт подтверждение ✓ <path> = <value>. esc отменяет и возвращает в
браузер с сохранённым состоянием (курсор, раскрытие, фильтр); ctrl+c завершает
весь браузер. Если блокировки проекта заняты (например, приостановленный
dwe deploy run), сохранение не проходит и в строке статуса мигает ошибка
блокировки — браузер остаётся открытым, а local.yml не изменяется.
Два наблюдаемых поведения отличаются от отдельного dwe vars set:
- Подтверждения — это временная вспышка в строке статуса, а не stdout. После
выхода из браузера в терминале нет следов правок — при выходе ничего не
печатается. (Используйте
dwe vars get <path>или заново откройте браузер, чтобы проверить значение.) - Редактирование без выхода работает только на пути оверлея ≥ 80 колонок. На
более узком терминале браузер использует плоский запасной селектор, который
выходит, чтобы запустить форму
set, и затем открывается заново — старый цикл «выход после коммита», по одной правке за раз.
В неинтерактивном контексте — нет TTY, DWE_NONINTERACTIVE=1 или запуск
внутри контейнера — голая команда откатывается к dwe vars list. Аргумент
namespace (dwe vars vars.db) тоже выводит список, а не браузер.
Сохраняющая комментарии запись в local.yml
Заголовок раздела «Сохраняющая комментарии запись в local.yml»dwe vars set пишет workspace/local.yml через round-trip yaml.Node:
загружает файл как дерево узлов, патчит только целевой путь и сериализует
заново. Комментарии, пустые строки и порядок ключей сохраняются; меняется только
отредактированный узел значения. Приведение учитывается на уровне узла —
перезапись закавыченной строки на true/42 выдаёт голый скаляр, чтобы он
перезагрузился типизированным.
Этот writer стоит за dwe vars set, dwe services enable/disable и
мастером настройки, так что комментарии в local.yml переживают любую
правку под управлением DWE. Коллизии map-над-скаляром отклоняются
(чтобы не отбрасывать молча данные разработчика), с единственным
задокументированным исключением — легаси голый-int порт-лист апгрейдится до
map’а {port: N}.
Статическое сканирование использований
Заголовок раздела «Статическое сканирование использований»inspect (и оверлей inspect в браузере) сообщает каждое место, где на var
статически ссылаются. Сканирование field-aware, а не сплошной grep по
файлу — оно обходит каждый конфиг-файл и инспектирует только те поля, которые
runtime реально рендерит, поэтому избегает ложных срабатываний (комментарии,
закавыченные литералы, не рендерящиеся поля) и ложных пропусков (ссылки в
структурных ключах). Отслеживаются два синтаксиса ссылок:
- Шаблонные ссылки
${vars.x}— в полях, рендерящихся движком${...}(декларативные командыcmd/argv/compose_args/argv_append_from/env/with, шаги пайплайнаtimeout/files_gate.command,info.ymltext/value, скалярныйwhen:,docker.ymlproject_name, подтверждающие промпты) и в config-шаблонах рендера подworkspace/templates/config/**(произвольный текст → построчный скан и${vars.x}, и{{ resolve .Raw "vars.x" }}). Это шаблоны, которые материализует подсистема config-рендера; соседние пакеты ide / ai / git используют сырой субстрат{{ }}(без разрешения${...}) и не сканируются. Внутренние пробелы (${ vars.x }) и ведущая цифра не совпадают — сканер переиспользует собственный паттерн рендерера. - Структурные dot-path’ы
vars.x— значенияfrom:/default_from:и ссылки внутри типизированногоwhen.expr(не голый скалярwhen: vars.x).
Сопоставление по точному пути или префиксу namespace: ${vars.db.host}
засчитывается и vars.db.host, и vars.db.
Сам блок vars: верхнего уровня не сканируется: его значения — это данные
конфига, разрешаемые по dot-path и никогда не рендерящиеся повторно, поэтому
${vars.x} или from:, появляющиеся внутри vars:, не являются использованием
во время выполнения.
Оговорка (печатается в выводе): динамически собираемые пути и доступ к полям
через Go-шаблоны (.Vars.x / .Raw.vars.x в шаблонах {{ ... }}) не
отслеживаются. Сканирование покрывает только формы ${...} и
структурный-dot-path.
JSON-вывод
Заголовок раздела «JSON-вывод»Каждая read-only подкоманда поддерживает --output json (с --pretty) и держит
stdout чистым — типизированные ошибки сериализуются в конверт {"error":{…}} на
stderr.
| Команда | Форма |
|---|---|
get | {"var": "...", "value": <any>} |
list | {"vars": [{"path": "...", "value": <any>, "layer": "local|default"}]} |
inspect | {"var": "...", "layers": {"default": <any>, "default_set": <bool>, "local": ..., "local_set": ..., "current": ..., "current_set": ...}, "origin": "...", "usages": [{"file": "...", "line": N, "kind": "...", "text": "..."}]} |
set (со значением) | {"var": "...", "value": <any>} |
Булевы *_set на слоях inspect отличают явное значение null от
отсутствующего слоя. set без значения в JSON-режиме — это ошибка
vars_value_required (форма не открывается).
Поведение в контейнере и bridge.vars_writable
Заголовок раздела «Поведение в контейнере и bridge.vars_writable»dwe vars достижима изнутри bridged-контейнера, но записи запрещены
по умолчанию (deny-by-default):
get/list/inspectдостижимы всегда.setдостижима, но контейнерныйsetуспешен только когда целевой var совпадает с записью в allowlist’е проектаbridge.vars_writable. Несовпадающий var отклоняется сvars_not_container_writable. С хостаsetнеограничен.- TUI авто-отключается в контейнере (неинтерактивный откат к
list).
Конфиг-блок bridge.vars_writable
Заголовок раздела «Конфиг-блок bridge.vars_writable»bridge.vars_writable — это top-level конфиг-блок, отличный от
per-service блока services.<name>.bridge: в service.yml, который управляет
включением контейнера. Этот top-level блок — это общепроектная политика
контейнерной записи: в какие vars контейнеризованный dwe vars set может писать
в хостовый local.yml.
# workspace.yml (или любой слой — 3-слойный merge)bridge: vars_writable: - vars.db.password # точный путь - vars.app.* # префиксный wildcard (граница по точке)bridge входит в строгий корневой allowlist; он мёржится по трём слоям, как
любой другой формализованный блок. Семантика паттернов использует реальную
границу по точке, а не наивное префиксное совпадение:
- Точный паттерн (
vars.db.password) совпадает только с этим идентичным путём. - Wildcard
vars.x.*совпадает сtargetтолько когдаtargetначинается сbase + ".". Такvars.db.*разрешаетvars.db.host, но запрещаетvars.db,vars.dbx.hostиvars.database.host.
Пустой или отсутствующий список vars_writable означает отсутствие
контейнерных записей — безопасный дефолт. Некорректные паттерны fail closed
(запрет).
Что на самом деле даёт добавление вара в allowlist. Поля шага пайплайна
(cmd:, when.cmd, check.cmd, timeout:) рендерятся через подстановку
${...}, а отрендеренный cmd: уходит в хостовый sh -c как текст
программы — подстановка текстовая, без shell-квотирования (см.
Шаблоны в полях шага). Поэтому вар, который одновременно
доступен на запись из контейнера и используется в команде пайплайна,
позволяет контейнеру выбрать часть хостовой командной строки: значение
x; some-command выполнит some-command на хосте при следующем
dwe deploy run. Это и есть естественная комбинация — контейнер обычно хочет
записать вар именно потому, что его читает пайплайн, — так что считайте
vars_writable делегированием ввода в хостовый shell тому, кто имеет доступ к
контейнеру, и держите в списке вары, которые потребляются как данные (рендер
конфигов, exports.env), а не подставляются в команды.
render config из контейнера
Заголовок раздела «render config из контейнера»Чтобы контейнер мог регенерировать конфиги сервисов после set, dwe render config тоже достижима из контейнера (остальные подкоманды render — env /
ide / ai / git — остаются только хостовыми). Поскольку render config --harvest мутирует хостовое состояние (.dwe/generated.yml), контейнерный
render config --harvest отклоняется с render_harvest_host_only — границу
пересекает только read-only render.
Связанные команды
Заголовок раздела «Связанные команды»dwe vars get <var>— вывести эффективное значение var’аdwe vars list [namespace]— перечислить листьяvars.*dwe vars inspect <var>— значения по слоям, origin и использованияdwe vars set <var> [value]— записать override вlocal.yml(с сохранением комментариев)dwe render env/dwe render config— регенерировать.env/ конфиги сервисов из объединённого конфигаdwe services enable/disable— переключатели сервисов (с сохранением комментариев)