fix(yaml): bit-perfect YAML round-trip cs1=cs2=cs3 + автоматизация прогона#3282
Merged
Conversation
…ping
`Koi8rYamlEmitter::Value` теперь определяет режим литерального блока
по количеству trailing '\n' (без content -> keep |+2; 0 -> strip |-2;
1 -> clip |2; >=2 -> keep |+2), и переключается в literal-block для
любого значения с embedded '\n', даже если caller не передал
literal=true (plain/quoted scalar их теряет на reload).
Закрывает классы расхождений: embedded \n в коротких именах комнат,
пустые literal-блоки ("\n" в описаниях), и multi-\n в текстах справки.
…sc в обратном порядке, exit-keywords с правильным indent * SaveTriggers: пустые `cmd` сериализуются как " " (одиночный пробел); ParseTriggerScript на reload TrimRight'ит обратно в "", сохраняя количество node'ов cmd_list. Без этого whitespace-only строки из legacy `.trg` теряются и чексумма триггера сдвигается. * SaveObjects: extra_descriptions эмитятся в обратном порядке. LoadObjects делает prepend (а не append), поэтому in-memory список reverse'ом относительно файла. Эмитя в обратном — получаем стабильный round-trip, без флипа порядка на каждом save. * SaveRooms (и SaveObjects ex_desc): для `keywords` оборачиваем `yaml.Value` в IncreaseIndent/DecreaseIndent — чтобы content литерального блока попадал в правильную колонку (parent_indent + 2), иначе многострочные keyword'ы не парсились на reload.
Команды зон 1 и 40 ссылались на mob/obj vnum'ы, которых нет в small world (в `lib.template/world/mob/` только 1.mob/2.mob/40.mob, аналогично obj/). ResolveZoneCmdVnumArgsToRnums при boot'е помечал такие команды как '*', и они тихо терялись при пересохранении -- что ломало YAML round-trip. Удалено 8 dangling-команд: * zon/1.zon: `O 1053` (obj отсутствует), `M 1127` (mob отсутствует), `O 1069` (obj отсутствует). * zon/40.zon: `G 1900/1903/1906/1909` (obj'ы отсутствуют), `M 27073` (mob отсутствует).
`run_load_tests.sh` теперь оркестрирует все этапы одной командой: setup -> build -> load tests -> YAML round-trip -> admin API. * Новая стадия `run_roundtrip_test()`: для YAML-сборки запускает `circle -S world_v2`, подменяет world на свежесохранённый, и переиспользует `run_test` для boot'а с `-W` -> получает cs3. Сравнение cs2 vs cs3 добавлено в CHECKSUM COMPARISON. Стадия работает как для small, так и для full. * Admin API тесты сдвинуты в самый конец (они ремэйкают мир, поэтому всё order-sensitive должно идти до них). Round-trip между checksums и admin API. * `FULL_WORLD_ARCHIVE` теперь обязательная переменная для full-world тестов -- никакого hardcoded `~/repos/world.tgz`. Small-world прогоны её игнорируют. * Extraction архива через `tar --strip-components=1`, чтобы скрипт работал с любым top-dir'ом архива (`lib/`, `world.YYYYMMDD/`, ...). * Auto-skip SQLite если `pkg-config sqlite3` не находит dev-headers и не указан явно `--loader=sqlite`. Раньше скрипт падал, требуя `libsqlite3-dev` сразу. `should_run_test` тоже понимает round-trip-стадию (как и admin API, игнорирует FILTER_CHECKSUMS).
…tra_values в '-S' режиме Справочник int->name для ObjVal-ключей (POTION_SPELL*_NUM/LVL, POTION_PROTO_VNUM) инициализируется в `text_id::Init()`, который зовётся только из `BootMudDataBase()` (comm.cpp:807). А режимы `-S <out_dir>` и `-c` (scheck) возвращаются раньше -- между `BootWorld()` и `BootMudDataBase()`. В итоге YAML round-trip терял `extra_values` блок: * `ConvertDrinkconSkillField` на boot копирует значения potion-прототипа в kLiquidContainer/kFountain через `SetPotionValueKey(POTION_SPELL1_NUM, ...)` и т.п. -- m_values заполняется. * `SaveObjects` итерирует `obj->get_all_values()` и через `text_id::ToStr` пытается перевести ключ в строку -- но справочник пустой, ToStr возвращает "", и все ключи отфильтровываются. * В YAML записывается всё, кроме `extra_values`. На cs3 boot конвертер уже не сработает (spec_param=-1 после прошлого boot'а), m_values пустой, чексумма расходится -- ~100 жидкостных контейнеров в full world. Перенос `text_id::Init()` в `GameLoader::BootWorld` гарантирует, что справочник готов до любого пути, способного сериализовать объекты. Init использует unordered_map::insert, так что повторный вызов из `BootMudDataBase()` безопасен (no-op для уже добавленных пар).
…uch file'
LEGACY_BIN/SQLITE_BIN/YAML_BIN задаются статически наверху скрипта, поэтому
`[ -n "$BIN" ]` всегда truthy. Когда соответствующий лоадер скипается
(auto-skip sqlite или filter loader/world), run_test/run_admin_api_test всё
равно пытаются стартовать несуществующий бинарь:
line 658: /home/kvirund/repos/mud/build_sqlite/circle: No such file
or directory
Меняем на `-x` (файл существует и исполняется) -- ровно то, что нужно
для гейта запуска.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Контекст
Серия фиксов на YAML round-trip начала жить как #3279. Тот PR ушёл в master большим пакетом из 22 коммитов:
22 коммита из #3279 (уже в master)
После этого мерджа в логе round-trip'а оставалось 6 строк диффа (только OBJ-чексуммы жидкостных контейнеров + 2 зоны со сломанными ссылками). Этот PR закрывает остаток до bit-perfect-а cs1=cs2=cs3 и собирает все стадии тестирования в одну команду.
Что нового в этом PR (6 коммитов поверх master)
Koi8rYamlEmitter— литеральный блок forced при любом\nв значении (plain/quoted scalar теряют embedded\nна reload), 4-сторонний выбор chomping по count'у trailing\n(|+2/|-2/|2) для бит-точного round-trip'а описаний/триггер-скриптов.SaveTriggers— пустыеcmdсохраняются как одиночный пробел; на reloadParseTriggerScript::TrimRightвозвращает"", count node'ов cmd_list сохраняется.SaveObjects—extra_descriptionsэмитятся в обратном порядке (LoadObjects делает prepend, иначе порядок флипает на каждом round-trip'е);keywordsобёрнуты в IncreaseIndent чтобы content литерала попадал в правильную колонку.text_id::Init()перенесён вBootWorld(). До этого справочник int↔name для ObjVal-ключей инициализировался только вBootMudDataBase()(comm.cpp:807), а-S <out_dir>и-c(scheck) возвращаются до него. В результатеSaveObjectsфильтровал все POTION_* ключи как «нерезолвимые» иextra_valuesблок не писался → ~100 жидкостных контейнеров расходились по чексумме.lib.template/world/zon/{1,40}.zon— убраны 8 ссылок на отсутствующие vnum'ы (mob 1127, obj 1053/1069/1900/1903/1906/1909, mob 27073). ResolveZoneCmd при boot'е помечал их*и они тихо терялись при resave, ломая cs3.tools/run_load_tests.sh— добавленrun_roundtrip_test()(resave → swap → reboot → cs3); вызывается после YAML checksums и до admin API, чтобы admin API запускался последним (он рекреирует мир).FULL_WORLD_ARCHIVEтеперь обязательная переменная; extract идёт через--strip-components=1(работает с любым top-dir-ом архива); SQLite авто-скипается еслиpkg-config sqlite3не находит dev-headers;[ -n "$X_BIN" ]→[ -x "$X_BIN" ]чтобы не пытаться стартовать несуществующий бинарь.Результат
Admin API: 4/4 PASSED (Small/Full × Legacy/YAML).
Запуск одной командой:
Использован архив
world.20260427.cleaned.tgz— это мастер-архивworld.20260427.tgzс вычищеннымиM ... -1 ...командами в зонах 822/823 (41 строка, см. issue-тред #3273). Оригинальный архив тоже почистится через любой OLCzedit save.Test plan
./tools/run_load_tests.sh(с указанием FULL_WORLD_ARCHIVE) — все 4 MATCH'а + admin API PASSED./tools/run_load_tests.sh --quick— small world MATCH'и + admin API