From aabcaefb78f1668ebb67b208f38eefd007cfb45d Mon Sep 17 00:00:00 2001 From: Marat Zimnurov Date: Sun, 4 Oct 2026 18:16:05 +0000 Subject: [PATCH] feat(site): the registry page is printed from the ledger ADR-0059 says the registry is a ledger of names served as a plain file over HTTP. Until now the ledger lived only in the tree: there was nowhere to see it, and its fingerprints rotted unseen -- four of the seven parted from the files, because no CI job called the registry at all (task 4909). What is new: * scripts/site/registry-page.fscript -- two plans. The printing plan reads scripts/registry-example/registry.list, recomputes sha256 of every address, compares it with the fingerprint field, and only then prints both halves of the site page. One character apart and the page is not printed at all: the plan fails with FLANG_REESTR_OTPECHATOK, exit code 1, naming the record, the address and both fingerprints. The publishing plan lays the ledger into the built site, with the same comparison on the way in. * docs/site/registry.ru.md and docs/site/registry.md -- the page itself, both halves printed by the run. Its table is a reversible encoding of the ledger: strip the leading and trailing pipes, drop the backticks, and the rows are the ledger lines again. So "the table agrees with the ledger" is answered by diff, not by eye. * The ledger is served at a stable address inside Pages, https://digitable-lol.github.io/flang/registry.list -- the address the page names and the one the HTTP order of the language fetches. * .flangrc -- two shortcuts, registry:page and registry:publish. Both are called by name from .github/workflows/pages.yml, so the guard of uncalled shortcuts stays green. * pages.yml reprints the page before the build, probes the check with a bent fingerprint (a red that does not name the planted record fails the step), and publishes the ledger after the build, because the build wipes the output directory. The four rotted fingerprints in scripts/registry-example/registry.list are rebuilt by the tool that owns them; only those four lines changed, and the check now answers "fingerprints agree for every record: 7". docs/site/packages.ru.md and its English half no longer say there is no registry: they link to the page and say what the registry is and is not. docs/tree-inventory.md and docs/javascript-inventory.md carry the five JavaScript lines added to docs/site/sitemap.mjs: 22660 becomes 22665. --- .flangrc | 2 + .github/workflows/pages.yml | 61 +++ docs/javascript-inventory.md | 4 +- docs/site/packages.md | 10 +- docs/site/packages.ru.md | 9 +- docs/site/registry.md | 77 ++++ docs/site/registry.ru.md | 75 ++++ docs/site/sitemap.flang | 4 +- docs/site/sitemap.mjs | 5 + docs/tree-inventory.md | 2 +- scripts/registry-example/registry.list | 8 +- scripts/site/registry-page.fscript | 541 +++++++++++++++++++++++++ 12 files changed, 781 insertions(+), 17 deletions(-) create mode 100644 docs/site/registry.md create mode 100644 docs/site/registry.ru.md create mode 100644 scripts/site/registry-page.fscript diff --git a/.flangrc b/.flangrc index 5f8476fef..d12c1b361 100644 --- a/.flangrc +++ b/.flangrc @@ -159,6 +159,8 @@ script.changelog:page = node scripts/site/build-changelog-page.mjs script.changelog:page:check = node scripts/site/build-changelog-page.mjs --check script.releases:page = bootstrap/flang io scripts/site/releases-page.fscript --max-steps 80000000 --на-веру script.releases:page:check = bootstrap/flang io scripts/site/releases-page-verify.fscript --max-steps 80000000 --на-веру +script.registry:page = bootstrap/flang io scripts/site/registry-page.fscript --plan 'Напечатать страницу реестра' +script.registry:publish = bootstrap/flang io scripts/site/registry-page.fscript --plan 'Выложить ведомость' script.reprint = sh scripts/bootstrap-reprint.sh script.reprint:check = sh scripts/bootstrap-reprint.sh --check script.bootstrap-point:check = bootstrap/flang io scripts/seed/bootstrap-point-by-binary.fscript --timeout 2400000 --на-веру diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 39e23cef1..dd604530b 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -38,6 +38,9 @@ on: - 'scripts/site/changelog.flang' - 'scripts/site/releases.flang' - 'scripts/site/releases-page.fscript' + - 'scripts/site/registry-page.fscript' + - 'scripts/registry-example/**' + - 'flang/stdlib/registry.flang' - '.github/workflows/pages.yml' # Подсветка блоков кода красит НАСТОЯЩИМ лексером языка, а он живёт в # двоичном компиляторе: правка точки раскрутки или двери к двоичному @@ -135,6 +138,53 @@ jobs: - name: Rebuild releases page run: LC_ALL=C.UTF-8 bootstrap/flang io scripts/site/releases-page.fscript --на-веру --max-steps 80000000 + # ПО ТОЙ ЖЕ ПРИЧИНЕ — И РЯДОМ С ЕЩЁ ОДНОЙ. Страница реестра печатается из + # ведомости `scripts/registry-example/registry.list`, и между правкой + # ведомости и перепечаткой она отстаёт; здесь она печатается заново, и + # опубликованное всегда свежее. Дерево при этом не правится. + # + # ВТОРОЕ, ЧТО ДЕЛАЕТ ЭТОТ ШАГ, И ОНО ГЛАВНОЕ: прогон пересчитывает sha256 + # каждого адреса ведомости и сличает с полем «отпечаток». Разошёлся знак — + # страница не печатается, прогон отвечает кодом 1, и сборка сайта краснеет + # ЗДЕСЬ, с именем записи и обоими отпечатками. До этого шага реестр не + # звала ни одна работа CI, и отпечатки примера гнили молча (задача 4909). + - name: Rebuild registry page + run: LC_ALL=C.UTF-8 bootstrap/flang run-script registry:page + + # ПРОБА: сверка отпечатков обязана покраснеть на подкрученном знаке. + # Иначе зелёный шаг выше неотличим от выключенного — ровно та беда, из-за + # которой отпечатки и прогнили. Портится ОДИН знак в ОДНОМ отпечатке + # ведомости; требуется код не 0 И имя подложенной записи в выводе + # (покраснеть по чужой причине — не довод); ведомость возвращается и + # сравнивается с копией побайтово. + - name: Probe registry fingerprint + run: | + vedomost=scripts/registry-example/registry.list + cp "$vedomost" "$RUNNER_TEMP/registry.list" + sed -i 's/^\(Списки | 1\.4\.2 | \)./\1X/' "$vedomost" + if cmp -s "$vedomost" "$RUNNER_TEMP/registry.list"; then + echo "ПОДЛОГ НЕ СОБРАЛСЯ: $vedomost не изменилась" >&2 + exit 1 + fi + if LC_ALL=C.UTF-8 bootstrap/flang run-script registry:page > "$RUNNER_TEMP/probe.out" 2>&1; then + cp "$RUNNER_TEMP/registry.list" "$vedomost" + echo "СВЕРКА ПРОМОЛЧАЛА: подкрученный отпечаток прошёл" >&2 + exit 1 + fi + cp "$RUNNER_TEMP/registry.list" "$vedomost" + if ! grep -F 'FLANG_REESTR_OTPECHATOK' "$RUNNER_TEMP/probe.out"; then + echo "ПОКРАСНЕЛО НЕ НА ОТПЕЧАТКЕ:" >&2 + tail -20 "$RUNNER_TEMP/probe.out" >&2 + exit 1 + fi + if ! grep -F 'Списки 1.4.2' "$RUNNER_TEMP/probe.out"; then + echo "ОТКАЗ НЕ НАЗВАЛ ПОДЛОЖЕННУЮ ЗАПИСЬ:" >&2 + tail -20 "$RUNNER_TEMP/probe.out" >&2 + exit 1 + fi + cmp "$vedomost" "$RUNNER_TEMP/registry.list" + LC_ALL=C.UTF-8 bootstrap/flang run-script registry:page + # Отдельным шагом до сборки: если ссылки битые, видно сразу и по имени, # а не среди вывода сборки. - name: Check links @@ -175,6 +225,17 @@ jobs: if: github.event_name != 'pull_request' run: node docs/site/build.mjs + # ВЕДОМОСТЬ РАЗДАЁТСЯ ФАЙЛОМ, А НЕ КАРТИНКОЙ НА СТРАНИЦЕ. Решение ADR-0059: + # реестр — строчный файл, раздаваемый обычным HTTP, и отвечает он адресом. + # Шаг кладёт ведомость в корень собранного сайта под именем `registry.list` + # — тот самый адрес, который называет страница и который берёт поручение + # «Запросить». Стоит ПОСЛЕ сборки: `build.mjs` вычищает `docs/site/out` + # целиком, и положенное до него не доехало бы. Сличение отпечатков идёт и + # здесь: выложить ведомость с гнилым отпечатком нельзя. + - name: Publish the registry ledger + if: github.event_name != 'pull_request' + run: LC_ALL=C.UTF-8 bootstrap/flang run-script registry:publish + - if: github.event_name != 'pull_request' uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 diff --git a/docs/javascript-inventory.md b/docs/javascript-inventory.md index 85c4567c1..d771ad373 100644 --- a/docs/javascript-inventory.md +++ b/docs/javascript-inventory.md @@ -73,8 +73,8 @@ HTML, CSS, awk, Erlang, Java, C#, Elixir, Go, Rust, Lua, vimscript, Ruby — долг вне JavaScript — **97 файлов, 18 427 строк при потолке 63**: храповик красен, разбор — задачи 4838 и 7405). Там же названы 569 строк JavaScript, лежащих ВНУТРИ файлов `.html`: счёт по именам файлов их не видит, и -22 660 строк этой описи — нижняя оценка. - +22 665 строк этой описи — нижняя оценка. + (29 августа здесь стояло 25 527: за два дня прибавилось 2 313 строк. Ещё 64 строки прибавились 2 сентября: `scripts/latin-collision-guard.mjs` сравнивает теперь ПРОСЬБЫ печати, а не объявленные имена, и довод к этому записан там же.) diff --git a/docs/site/packages.md b/docs/site/packages.md index ef39161bd..787d07b30 100644 --- a/docs/site/packages.md +++ b/docs/site/packages.md @@ -1,10 +1,12 @@ # Packages A flang package is **one file** that holds a library together with everything -it imports. There is no registry and no package cache. To publish a package, -commit the file to git; to use it, put the file next to your program and write -one import line. Building on another machine needs only your program and the -package file, and never touches the network. +it imports. There is no package cache, and the registry is a +[ledger of names](registry.html), not a store of code: it has no command of the +binary and answers with an address. To publish a package, commit the file to +git; to use it, put the file next to your program and write one import line. +Building on another machine needs only your program and the package file, and +never touches the network. Two commands of the `flang` binary do the work: `flang package` builds a package, `flang lock` writes a lock file for a whole program. Both have diff --git a/docs/site/packages.ru.md b/docs/site/packages.ru.md index d2e8b85ea..c6c4b5446 100644 --- a/docs/site/packages.ru.md +++ b/docs/site/packages.ru.md @@ -1,10 +1,11 @@ # Пакеты Пакет flang — **один файл**, в котором лежит библиотека вместе со всем, что она -импортирует. Реестра и кеша пакетов нет. Чтобы опубликовать пакет, закоммитьте -файл в git; чтобы им пользоваться, положите файл рядом с программой и напишите -одну строку импорта. Для сборки на другой машине нужны только ваша программа и -файл пакета, в сеть сборка не ходит никогда. +импортирует. Кеша пакетов нет, а реестр — [ведомость имён](registry.html), а не +склад кода: команды двоичного у него нет, он отвечает адресом. Чтобы +опубликовать пакет, закоммитьте файл в git; чтобы им пользоваться, положите файл +рядом с программой и напишите одну строку импорта. Для сборки на другой машине +нужны только ваша программа и файл пакета, в сеть сборка не ходит никогда. Работают две команды двоичного `flang`: `flang package` собирает пакет, `flang lock` пишет lock-файл для всей программы. У обеих есть `--help`. Примеры diff --git a/docs/site/registry.md b/docs/site/registry.md new file mode 100644 index 000000000..43b7e4e80 --- /dev/null +++ b/docs/site/registry.md @@ -0,0 +1,77 @@ +# The package registry + +The flang registry is a **ledger of names**, not a store of code. The ledger is +a line-based file: five fields per line separated by «|», and nothing else. Asked +which version of a package will do, the registry answers with an **address** +where the package lies, not with the package; a name gets a version here, in the +ledger, and nowhere else; the language gains no new word for any of it. No +server, no database and no accounts are needed — and by decision there are none. +The whole argument: +[ADR-0059](../adr/0059-the-registry-is-a-ledger-of-names-not-a-store-of-code.md). + +## The ledger is a file at a stable address + +``` +https://digitable-lol.github.io/flang/registry.list +``` + +It is a plain file served over HTTP. A flang program fetches it with the order +the language already has — «Запросить»: + +``` +вариант «Запросить» с способ равным "GET" + и адрес равным "https://digitable-lol.github.io/flang/registry.list" + и тело равным "" +``` + +What the site serves is a copy of the ledger in the tree, +[`scripts/registry-example/registry.list`](../../scripts/registry-example/registry.list), +byte for byte — put there by the same build that prints this page. + +## The five fields + +| field | what is in it | +|---|---| +| name | the package name — what stands in `использует` | +| version | three numbers: major, minor, patch | +| fingerprint | `sha256` of the package file | +| address | where the package file lies | +| needs | what the package requires of other names; empty means nothing | + +A need reads `name: range`, needs are separated by semicolons. There are four +ranges: `любая`, `ровно 1.2.3`, `не ниже 1.2.3`, `в пределах 1.x`. Parsing the +ledger and choosing a version are written and proved in +[`flang/stdlib/registry.flang`](../../flang/stdlib/registry.flang); the choice is +made by running a plan, not by a command of the binary. + +## The records as they stand + +The table below is printed **from the ledger** by +`flang run-script registry:page`; it is not edited by hand — an edit is lost at +the next printing. + +| name | version | fingerprint | address | needs | +|---|---|---|---|---| +| Логика | 1.0.0 | `1dc6da94a777a731150d896e28d9b20ce0afd6ca876b0cafe1c0d0d3d0b4c864` | `registry-example/logic-1.0.0.flang-package` | | +| Логика | 1.2.0 | `b2bda19546f5cbb2b7642a80f54458197bca3dfde517983356080a11c62870d2` | `registry-example/logic-1.2.0.flang-package` | | +| Логика | 2.0.0 | `5374735fb59ebaf5e374ffa1e4a985a8b66616f35a45f4cd35244697ed91c965` | `registry-example/logic-2.0.0.flang-package` | | +| Списки | 1.4.2 | `802d716b62ea8918ded9cdda7ed2fd04c16aa97da4d519381e3c98e4e3f5ccc9` | `registry-example/lists-1.4.2.flang-package` | Логика: не ниже 1.0.0 | +| Множество строк | 1.0.0 | `cf3a1697ccc1e7c2fa4fd72b3210ad5372590c0844f13e07119fa290a1f69931` | `registry-example/sets-1.0.0.flang-package` | Логика: не ниже 1.0.0 | +| Множество строк | 1.1.0 | `a9a776e153d9789c7e29f8c66ad92df36a834f21630c6388b41ebd4f8d2effc2` | `registry-example/sets-1.1.0.flang-package` | Списки: в пределах 1.x; Логика: в пределах 1.x | +| Опциональное значение | 0.9.0 | `17eac86ce77be366094d22be0f537d4bab5bb00958fb41df3bd7353060957c7d` | `registry-example/optional-0.9.0.flang-package` | Логика: ровно 2.0.0 | + +Records in the ledger: 7. + +## The fingerprint is checked against the file as the page is printed + +The fingerprint is the only thing trust in someone else's package rests on, and +it rots silently. So the same run that prints the table recomputes the `sha256` +of every address and compares it with the fingerprint field. One character apart +and the page is not printed at all: the run exits with 1 and +`FLANG_REESTR_OTPECHATOK`, names the record, both fingerprints and the address, +and the site build goes red on it instead of reaching the reader. + +The check is not a precaution: the fingerprints of the example ledger did part +from the files once, and there was nobody to see it — no CI job called the +registry at all (task +[4909](../tasks/4909-the-registry-resolution-rule-has-no-guard-and-example-fingerprints-rotted.md)). diff --git a/docs/site/registry.ru.md b/docs/site/registry.ru.md new file mode 100644 index 000000000..4d23bbd83 --- /dev/null +++ b/docs/site/registry.ru.md @@ -0,0 +1,75 @@ +# Реестр пакетов + +Реестр flang — это **ведомость имён**, а не склад кода. Ведомость — строчный +файл: в каждой строке пять полей через знак «|», и больше в ней ничего нет. На +вопрос «какая версия пакета годится» реестр отвечает **адресом**, по которому +лежит пакет, а не самим пакетом; имя получает версию только здесь, в ведомости; +ни одного нового слова в языке реестр не заводит. Ни сервера, ни базы, ни +учётных записей для этого не нужно — и по решению их нет. Довод целиком: +[ADR-0059](../adr/0059-the-registry-is-a-ledger-of-names-not-a-store-of-code.md). + +## Ведомость лежит файлом по постоянному адресу + +``` +https://digitable-lol.github.io/flang/registry.list +``` + +Это обычный файл, раздаваемый по HTTP. Программа на flang берёт его тем +поручением, которое у языка уже есть, — «Запросить»: + +``` +вариант «Запросить» с способ равным "GET" + и адрес равным "https://digitable-lol.github.io/flang/registry.list" + и тело равным "" +``` + +На сайте лежит копия ведомости дерева +[`scripts/registry-example/registry.list`](../../scripts/registry-example/registry.list) +— знак в знак, и кладёт её туда та же сборка, что печатает эту страницу. + +## Пять полей + +| поле | что в нём | +|---|---| +| имя | имя пакета — то, что стоит в `использует` | +| версия | три числа через точку: старшая, средняя, младшая | +| отпечаток | `sha256` файла пакета | +| адрес | где лежит файл пакета | +| нужды | чего пакет требует от других имён; пусто — ничего | + +Нужда пишется как `имя: диапазон`, нужды разделяются точкой с запятой. +Диапазонов четыре: `любая`, `ровно 1.2.3`, `не ниже 1.2.3`, `в пределах 1.x`. +Разбор ведомости и выбор версии написаны и доказаны в +[`flang/stdlib/registry.flang`](../../flang/stdlib/registry.flang); сдаётся выбор +прогоном плана, а не командой двоичного — нового слова реестр не заводит нигде. + +## Нынешние записи + +Таблица ниже напечатана **из ведомости** прогоном +`flang run-script registry:page`; руками её не правят — правка затрётся +следующей печатью. + +| имя | версия | отпечаток | адрес | нужды | +|---|---|---|---|---| +| Логика | 1.0.0 | `1dc6da94a777a731150d896e28d9b20ce0afd6ca876b0cafe1c0d0d3d0b4c864` | `registry-example/logic-1.0.0.flang-package` | | +| Логика | 1.2.0 | `b2bda19546f5cbb2b7642a80f54458197bca3dfde517983356080a11c62870d2` | `registry-example/logic-1.2.0.flang-package` | | +| Логика | 2.0.0 | `5374735fb59ebaf5e374ffa1e4a985a8b66616f35a45f4cd35244697ed91c965` | `registry-example/logic-2.0.0.flang-package` | | +| Списки | 1.4.2 | `802d716b62ea8918ded9cdda7ed2fd04c16aa97da4d519381e3c98e4e3f5ccc9` | `registry-example/lists-1.4.2.flang-package` | Логика: не ниже 1.0.0 | +| Множество строк | 1.0.0 | `cf3a1697ccc1e7c2fa4fd72b3210ad5372590c0844f13e07119fa290a1f69931` | `registry-example/sets-1.0.0.flang-package` | Логика: не ниже 1.0.0 | +| Множество строк | 1.1.0 | `a9a776e153d9789c7e29f8c66ad92df36a834f21630c6388b41ebd4f8d2effc2` | `registry-example/sets-1.1.0.flang-package` | Списки: в пределах 1.x; Логика: в пределах 1.x | +| Опциональное значение | 0.9.0 | `17eac86ce77be366094d22be0f537d4bab5bb00958fb41df3bd7353060957c7d` | `registry-example/optional-0.9.0.flang-package` | Логика: ровно 2.0.0 | + +Записей в ведомости: 7. + +## Отпечаток сверен с файлом при печати + +Отпечаток — единственное, на чём держится доверие к чужому пакету, и портится +он молча. Поэтому тот же прогон, который печатает таблицу, пересчитывает +`sha256` каждого адреса и сличает с полем «отпечаток». Разошёлся хоть один +знак — страница не печатается вовсе: прогон отвечает числом выхода 1 и +`FLANG_REESTR_OTPECHATOK`, называет запись, оба отпечатка и адрес, а сборка +сайта краснеет на нём и до читателя не доезжает. + +Проверка заведена не впрок: отпечатки ведомости примера однажды разошлись с +файлами, и увидеть это было некому — реестр не звала ни одна работа сборки +(задача [4909](../tasks/4909-the-registry-resolution-rule-has-no-guard-and-example-fingerprints-rotted.md)). diff --git a/docs/site/sitemap.flang b/docs/site/sitemap.flang index a7eea5b82..94312c05b 100644 --- a/docs/site/sitemap.flang +++ b/docs/site/sitemap.flang @@ -35,7 +35,7 @@ [ (запись «Раздел карты» с «имя» равным "Начало" и «англ» равным "Start" и «дляУчастников» равным нет и «страницы» равным [(запись «Страница карты» с «адрес» равным "index.html" и «имя» равным "Что такое flang" и «из» равным "docs/site/index.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "install.html" и «имя» равным "Установка" и «из» равным "docs/site/install.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "getting-started.html" и «имя» равным "Первая программа" и «из» равным "docs/site/getting-started.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "tutorial.html" и «имя» равным "Учебник" и «из» равным "docs/site/tutorial.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "editor.html" и «имя» равным "Настройка редактора" и «из» равным "docs/site/editor.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "learning.html" и «имя» равным "Как учить язык дальше" и «из» равным "docs/site/learning.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "troubleshooting.html" и «имя» равным "Устранение неполадок" и «из» равным "docs/site/troubleshooting.ru.md" и «печатается» равным нет)]), (запись «Раздел карты» с «имя» равным "Что изменилось" и «англ» равным "What changed" и «дляУчастников» равным нет и «страницы» равным [(запись «Страница карты» с «адрес» равным "releases.html" и «имя» равным "Выпуски" и «из» равным "docs/site/releases.ru.md" и «печатается» равным да), (запись «Страница карты» с «адрес» равным "roadmap.html" и «имя» равным "Что будет дальше" и «из» равным "docs/site/roadmap.ru.md" и «печатается» равным нет)]), - (запись «Раздел карты» с «имя» равным "Язык" и «англ» равным "Language" и «дляУчастников» равным нет и «страницы» равным [(запись «Страница карты» с «адрес» равным "language.html" и «имя» равным "Справочник конструкций" и «из» равным "docs/site/language.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "stdlib.html" и «имя» равным "Справочник библиотеки" и «из» равным "docs/site/stdlib.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "cli.html" и «имя» равным "Справочник команд" и «из» равным "docs/site/cli.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "fspec.html" и «имя» равным "Спеки: доказанное правило" и «из» равным "docs/site/fspec.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "operations.html" и «имя» равным "Операции языка" и «из» равным "docs/site/operations.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "diagnostics.html" и «имя» равным "Справочник отказов" и «из» равным "docs/site/diagnostics.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "glossary.html" и «имя» равным "Словарь языка" и «из» равным "docs/glossary.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "surfaces.html" и «имя» равным "Четыре поверхности записи" и «из» равным "docs/surfaces.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "packages.html" и «имя» равным "Как писать пакеты" и «из» равным "docs/site/packages.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "embedding.html" и «имя» равным "Как встроить flang в чужую программу" и «из» равным "docs/site/embedding.ru.md" и «печатается» равным нет)]), + (запись «Раздел карты» с «имя» равным "Язык" и «англ» равным "Language" и «дляУчастников» равным нет и «страницы» равным [(запись «Страница карты» с «адрес» равным "language.html" и «имя» равным "Справочник конструкций" и «из» равным "docs/site/language.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "stdlib.html" и «имя» равным "Справочник библиотеки" и «из» равным "docs/site/stdlib.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "cli.html" и «имя» равным "Справочник команд" и «из» равным "docs/site/cli.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "fspec.html" и «имя» равным "Спеки: доказанное правило" и «из» равным "docs/site/fspec.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "operations.html" и «имя» равным "Операции языка" и «из» равным "docs/site/operations.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "diagnostics.html" и «имя» равным "Справочник отказов" и «из» равным "docs/site/diagnostics.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "glossary.html" и «имя» равным "Словарь языка" и «из» равным "docs/glossary.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "surfaces.html" и «имя» равным "Четыре поверхности записи" и «из» равным "docs/surfaces.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "packages.html" и «имя» равным "Как писать пакеты" и «из» равным "docs/site/packages.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "registry.html" и «имя» равным "Реестр пакетов" и «из» равным "docs/site/registry.ru.md" и «печатается» равным да), (запись «Страница карты» с «адрес» равным "embedding.html" и «имя» равным "Как встроить flang в чужую программу" и «из» равным "docs/site/embedding.ru.md" и «печатается» равным нет)]), (запись «Раздел карты» с «имя» равным "Что язык умеет" и «англ» равным "What the language can do" и «дляУчастников» равным нет и «страницы» равным [(запись «Страница карты» с «адрес» равным "examples.html" и «имя» равным "Каталог примеров" и «из» равным "docs/site/examples.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "database.html" и «имя» равным "Базы данных" и «из» равным "docs/site/database.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "processes.html" и «имя» равным "Процессы, надзор, распределённость" и «из» равным "docs/site/processes.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "categories.html" и «имя» равным "Категорная поверхность" и «из» равным "docs/site/categories.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "shortener.html" и «имя» равным "Сокращатель ссылок: служба и клиент" и «из» равным "docs/site/shortener.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "browser-app.html" и «имя» равным "Приложение в браузере" и «из» равным "docs/site/browser-app.ru.md" и «печатается» равным нет)]), (запись «Раздел карты» с «имя» равным "Доказательства" и «англ» равным "Proofs" и «дляУчастников» равным нет и «страницы» равным [(запись «Страница карты» с «адрес» равным "what-is-proved.html" и «имя» равным "Что доказано, а что нет" и «из» равным "docs/site/what-is-proved.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "proof-refused.html" и «имя» равным "Ядро отказало: чья это ошибка" и «из» равным "docs/site/proof-refused.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "what-the-kernel-accepts.html" и «имя» равным "Какие постусловия prover доказывает" и «из» равным "docs/site/what-the-kernel-accepts.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "mathematics.html" и «имя» равным "Классика Coq и Lean: что берёт ядро" и «из» равным "docs/site/mathematics.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "proofs.html" и «имя» равным "Зачем и как" и «из» равным "docs/site/proofs.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "ai-assistant.html" и «имя» равным "Служба для ИИ-помощника" и «из» равным "docs/site/ai-assistant.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "case-studies.html" и «имя» равным "Разбор: 82 задачи с leetcode" и «из» равным "docs/site/case-studies.ru.md" и «печатается» равным нет)]), (запись «Раздел карты» с «имя» равным "Почему так" и «англ» равным "Why this way" и «дляУчастников» равным нет и «страницы» равным [(запись «Страница карты» с «адрес» равным "single-source.html" и «имя» равным "Один источник правды" и «из» равным "docs/guide/single-source.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "totality.html" и «имя» равным "Что даёт признак «тотальная»" и «из» равным "docs/guide/totality.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "bootstrap-circle.html" и «имя» равным "Круг раскрутки: компилятор собирает сам себя" и «из» равным "docs/guide/bootstrap-circle.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "developing.html" и «имя» равным "Развитие языка" и «из» равным "docs/guide/developing.ru.md" и «печатается» равным нет), (запись «Страница карты» с «адрес» равным "limits.html" и «имя» равным "Известные ограничения" и «из» равным "docs/guide/limits.ru.md" и «печатается» равным нет)]), @@ -51,7 +51,7 @@ тотальная функция «Все страницы карты» возвращает список «Страница карты» - обеспечивает «страниц сорок шесть» (длина результат) равен 46 + обеспечивает «страниц сорок семь» (длина результат) равен 47 свёртка («Разделы») начиная с пустой список как акк и раздел «Соединить страницы» от акк и (раздел.«страницы») diff --git a/docs/site/sitemap.mjs b/docs/site/sitemap.mjs index 22ab94a0b..b57816bb9 100644 --- a/docs/site/sitemap.mjs +++ b/docs/site/sitemap.mjs @@ -124,6 +124,11 @@ export const РАЗДЕЛЫ = [ { адрес: 'glossary.html', имя: 'Словарь языка', из: 'docs/glossary.md', безПары: 'английской редакции ещё нет — долг задачи 7660' }, { адрес: 'surfaces.html', имя: 'Четыре поверхности записи', из: 'docs/surfaces.md', безПары: 'английской редакции ещё нет — долг задачи 7660' }, { адрес: 'packages.html', имя: 'Как писать пакеты', из: 'docs/site/packages.ru.md' }, + /* РЕЕСТР СТОИТ СРАЗУ ЗА ПАКЕТАМИ: соседка выше говорит, как собрать пакет + одним файлом, эта — как имя пакета получает версию и адрес. Страница + ПЕЧАТАЕТСЯ из ведомости (scripts/site/registry-page.fscript), обе + половины; руками её не правят. */ + { адрес: 'registry.html', имя: 'Реестр пакетов', из: 'docs/site/registry.ru.md', печатается: true }, // Встраивание стоит ПОСЛЕ пакетов и ДО спецификации намеренно: пакет — // это как собрать библиотеку на flang, встраивание — как отдать её // программе на чужом языке. Второй вопрос задаётся только после первого, diff --git a/docs/tree-inventory.md b/docs/tree-inventory.md index 78057c001..09bdb6363 100644 --- a/docs/tree-inventory.md +++ b/docs/tree-inventory.md @@ -84,7 +84,7 @@ $ bootstrap/flang io scripts/guards/tree-inventory.fscript --max-steps 50000000 | CSS | 1 | 586 | 0 | 0 | | awk | 1 | 79 | 1 | 79 | | Erlang | 1 | 69 | 0 | 0 | -| JavaScript | 48 | 22 660 | считает [`javascript-inventory.md`](javascript-inventory.md) || +| JavaScript | 48 | 22 665 | считает [`javascript-inventory.md`](javascript-inventory.md) || | Java | 7 | 3 941 | 0 | 0 | | C# | 7 | 4 472 | 0 | 0 | | Elixir | 4 | 4 634 | 0 | 0 | diff --git a/scripts/registry-example/registry.list b/scripts/registry-example/registry.list index dcfb682b7..9b633e4d6 100644 --- a/scripts/registry-example/registry.list +++ b/scripts/registry-example/registry.list @@ -1,8 +1,8 @@ # реестр flang, схема 1: имя | версия | отпечаток sha256 | адрес | нужды -Логика | 1.0.0 | 2ea2d0b70b7544b7384fbfafe5ba216e8911b672634996747ed15d507c302350 | registry-example/logic-1.0.0.flang-package | -Логика | 1.2.0 | 6707a8be727a223ea0cde049193f8d4ac62bae8e0ac1f0556438e0f2c4a52b98 | registry-example/logic-1.2.0.flang-package | -Логика | 2.0.0 | 6fcb5fee384b623d77430c973aedd5ad1c9e567da7a2430eb9084824fbf988b6 | registry-example/logic-2.0.0.flang-package | -Списки | 1.4.2 | cb87ffcd4fb3d6dee44117ca1ce404367bf42667341b0a1ac0cdd7cf0e2b8204 | registry-example/lists-1.4.2.flang-package | Логика: не ниже 1.0.0 +Логика | 1.0.0 | 1dc6da94a777a731150d896e28d9b20ce0afd6ca876b0cafe1c0d0d3d0b4c864 | registry-example/logic-1.0.0.flang-package | +Логика | 1.2.0 | b2bda19546f5cbb2b7642a80f54458197bca3dfde517983356080a11c62870d2 | registry-example/logic-1.2.0.flang-package | +Логика | 2.0.0 | 5374735fb59ebaf5e374ffa1e4a985a8b66616f35a45f4cd35244697ed91c965 | registry-example/logic-2.0.0.flang-package | +Списки | 1.4.2 | 802d716b62ea8918ded9cdda7ed2fd04c16aa97da4d519381e3c98e4e3f5ccc9 | registry-example/lists-1.4.2.flang-package | Логика: не ниже 1.0.0 Множество строк | 1.0.0 | cf3a1697ccc1e7c2fa4fd72b3210ad5372590c0844f13e07119fa290a1f69931 | registry-example/sets-1.0.0.flang-package | Логика: не ниже 1.0.0 Множество строк | 1.1.0 | a9a776e153d9789c7e29f8c66ad92df36a834f21630c6388b41ebd4f8d2effc2 | registry-example/sets-1.1.0.flang-package | Списки: в пределах 1.x; Логика: в пределах 1.x Опциональное значение | 0.9.0 | 17eac86ce77be366094d22be0f537d4bab5bb00958fb41df3bd7353060957c7d | registry-example/optional-0.9.0.flang-package | Логика: ровно 2.0.0 diff --git a/scripts/site/registry-page.fscript b/scripts/site/registry-page.fscript new file mode 100644 index 000000000..bd4bf6396 --- /dev/null +++ b/scripts/site/registry-page.fscript @@ -0,0 +1,541 @@ +модуль «Печать страницы реестра» + использует «Registry» из "../../flang/stdlib/registry.flang" + +тотальная функция «Слить» + принимает первые: список строки, вторые: список строки + возвращает список строки + пример «Порядок строк сохраняется» + дано первые равно ["раз"] + дано вторые равно ["два"] + ожидается ["раз", "два"] + свёртка вторые начиная с первые как акк и строчка → (добавить строчка к акк) + +тотальная функция «Путь ведомости» + возвращает строка + пример «Ведомость лежит в каталоге примера, рядом с пакетами» + ожидается "../registry-example/registry.list" + "../registry-example/registry.list" + +тотальная функция «Путь пакета» + принимает адрес: строка + возвращает строка + пример «Адрес ведомости считается от scripts, а план лежит на уровень глубже» + дано адрес равно "registry-example/logic-1.0.0.flang-package" + ожидается "../registry-example/logic-1.0.0.flang-package" + соединить ["../", адрес] по "" + +тотальная функция «Имя ведомости» + возвращает строка + пример «Имя файла, под которым ведомость лежит на сайте» + ожидается "registry.list" + "registry.list" + +тотальная функция «Адрес ведомости» + возвращает строка + пример «Постоянный адрес ведомости на Pages» + ожидается "https://digitable-lol.github.io/flang/registry.list" + соединить ["https://digitable-lol.github.io/flang/", («Имя ведомости»)] по "" + +тотальная функция «Путь выкладки» + возвращает строка + пример «Ведомость кладётся в корень собранного сайта тем же именем» + ожидается "../../docs/site/out/registry.list" + соединить ["../../docs/site/out/", («Имя ведомости»)] по "" + +тотальная функция «Путь половины» + принимает язык: строка + возвращает строка + пример «Английская половина лежит рядом, без суффикса» + дано язык равно "en" + ожидается "../../docs/site/registry.md" + пример «Русская половина носит суффикс языка» + дано язык равно "ru" + ожидается "../../docs/site/registry.ru.md" + если язык равен "en" + то "../../docs/site/registry.md" + иначе "../../docs/site/registry.ru.md" + +тотальная функция «Строка таблицы из полей» + принимает имя: строка, версия: строка, отпечаток: строка, адрес: строка, нужды: строка + возвращает строка + пример «Трубы по краям, кавычки вокруг отпечатка и адреса — превращение обратимо» + дано имя равно "Логика" + дано версия равно "1.0.0" + дано отпечаток равно "ab12" + дано адрес равно "registry-example/logic.flang-package" + дано нужды равно "" + ожидается "| Логика | 1.0.0 | `ab12` | `registry-example/logic.flang-package` | |" + соединить ["| ", имя, " | ", версия, " | `", отпечаток, "` | `", адрес, "` | ", нужды, " |"] по "" + +тотальная функция «Строка таблицы» + принимает з: «Запись реестра» + возвращает строка + пусть версия равно («Версия строкой» от (з.«версия»)) + пусть нужды равно («Нужды строкой» от (з.«нужды»)) + «Строка таблицы из полей» от (з.«имя») и версия и (з.«отпечаток») и (з.«адрес») и нужды + +тотальная функция «Шапка таблицы» + принимает язык: строка + возвращает список строки + пример «Шапка английской половины названа по-английски» + дано язык равно "en" + ожидается ["| name | version | fingerprint | address | needs |", "|---|---|---|---|---|"] + если язык равен "en" + то ["| name | version | fingerprint | address | needs |", "|---|---|---|---|---|"] + иначе ["| имя | версия | отпечаток | адрес | нужды |", "|---|---|---|---|---|"] + +тотальная функция «Таблица» + принимает язык: строка, записи: список «Запись реестра» + возвращает список строки + «Слить» от («Шапка таблицы» от язык) и (отобразить записи как з → «Строка таблицы» от з) + +тотальная функция «Вступление по-русски» + возвращает список строки + ["# Реестр пакетов", + "", + "Реестр flang — это **ведомость имён**, а не склад кода. Ведомость — строчный", + "файл: в каждой строке пять полей через знак «|», и больше в ней ничего нет. На", + "вопрос «какая версия пакета годится» реестр отвечает **адресом**, по которому", + "лежит пакет, а не самим пакетом; имя получает версию только здесь, в ведомости;", + "ни одного нового слова в языке реестр не заводит. Ни сервера, ни базы, ни", + "учётных записей для этого не нужно — и по решению их нет. Довод целиком:", + "[ADR-0059](../adr/0059-the-registry-is-a-ledger-of-names-not-a-store-of-code.md).", + "", + "## Ведомость лежит файлом по постоянному адресу", + "", + "```", + "https://digitable-lol.github.io/flang/registry.list", + "```", + "", + "Это обычный файл, раздаваемый по HTTP. Программа на flang берёт его тем", + "поручением, которое у языка уже есть, — «Запросить»:", + "", + "```", + "вариант «Запросить» с способ равным \"GET\"", + " и адрес равным \"https://digitable-lol.github.io/flang/registry.list\"", + " и тело равным \"\"", + "```", + "", + "На сайте лежит копия ведомости дерева", + "[`scripts/registry-example/registry.list`](../../scripts/registry-example/registry.list)", + "— знак в знак, и кладёт её туда та же сборка, что печатает эту страницу.", + "", + "## Пять полей", + "", + "| поле | что в нём |", + "|---|---|", + "| имя | имя пакета — то, что стоит в `использует` |", + "| версия | три числа через точку: старшая, средняя, младшая |", + "| отпечаток | `sha256` файла пакета |", + "| адрес | где лежит файл пакета |", + "| нужды | чего пакет требует от других имён; пусто — ничего |", + "", + "Нужда пишется как `имя: диапазон`, нужды разделяются точкой с запятой.", + "Диапазонов четыре: `любая`, `ровно 1.2.3`, `не ниже 1.2.3`, `в пределах 1.x`.", + "Разбор ведомости и выбор версии написаны и доказаны в", + "[`flang/stdlib/registry.flang`](../../flang/stdlib/registry.flang); сдаётся выбор", + "прогоном плана, а не командой двоичного — нового слова реестр не заводит нигде.", + "", + "## Нынешние записи", + "", + "Таблица ниже напечатана **из ведомости** прогоном", + "`flang run-script registry:page`; руками её не правят — правка затрётся", + "следующей печатью.", + ""] + +тотальная функция «Заключение по-русски» + принимает сколько: число + возвращает список строки + ["", + (соединить ["Записей в ведомости: ", (к строке сколько), "."] по ""), + "", + "## Отпечаток сверен с файлом при печати", + "", + "Отпечаток — единственное, на чём держится доверие к чужому пакету, и портится", + "он молча. Поэтому тот же прогон, который печатает таблицу, пересчитывает", + "`sha256` каждого адреса и сличает с полем «отпечаток». Разошёлся хоть один", + "знак — страница не печатается вовсе: прогон отвечает числом выхода 1 и", + "`FLANG_REESTR_OTPECHATOK`, называет запись, оба отпечатка и адрес, а сборка", + "сайта краснеет на нём и до читателя не доезжает.", + "", + "Проверка заведена не впрок: отпечатки ведомости примера однажды разошлись с", + "файлами, и увидеть это было некому — реестр не звала ни одна работа сборки", + "(задача [4909](../tasks/4909-the-registry-resolution-rule-has-no-guard-and-example-fingerprints-rotted.md)).", + ""] + +тотальная функция «Вступление по-английски» + возвращает список строки + ["# The package registry", + "", + "The flang registry is a **ledger of names**, not a store of code. The ledger is", + "a line-based file: five fields per line separated by «|», and nothing else. Asked", + "which version of a package will do, the registry answers with an **address**", + "where the package lies, not with the package; a name gets a version here, in the", + "ledger, and nowhere else; the language gains no new word for any of it. No", + "server, no database and no accounts are needed — and by decision there are none.", + "The whole argument:", + "[ADR-0059](../adr/0059-the-registry-is-a-ledger-of-names-not-a-store-of-code.md).", + "", + "## The ledger is a file at a stable address", + "", + "```", + "https://digitable-lol.github.io/flang/registry.list", + "```", + "", + "It is a plain file served over HTTP. A flang program fetches it with the order", + "the language already has — «Запросить»:", + "", + "```", + "вариант «Запросить» с способ равным \"GET\"", + " и адрес равным \"https://digitable-lol.github.io/flang/registry.list\"", + " и тело равным \"\"", + "```", + "", + "What the site serves is a copy of the ledger in the tree,", + "[`scripts/registry-example/registry.list`](../../scripts/registry-example/registry.list),", + "byte for byte — put there by the same build that prints this page.", + "", + "## The five fields", + "", + "| field | what is in it |", + "|---|---|", + "| name | the package name — what stands in `использует` |", + "| version | three numbers: major, minor, patch |", + "| fingerprint | `sha256` of the package file |", + "| address | where the package file lies |", + "| needs | what the package requires of other names; empty means nothing |", + "", + "A need reads `name: range`, needs are separated by semicolons. There are four", + "ranges: `любая`, `ровно 1.2.3`, `не ниже 1.2.3`, `в пределах 1.x`. Parsing the", + "ledger and choosing a version are written and proved in", + "[`flang/stdlib/registry.flang`](../../flang/stdlib/registry.flang); the choice is", + "made by running a plan, not by a command of the binary.", + "", + "## The records as they stand", + "", + "The table below is printed **from the ledger** by", + "`flang run-script registry:page`; it is not edited by hand — an edit is lost at", + "the next printing.", + ""] + +тотальная функция «Заключение по-английски» + принимает сколько: число + возвращает список строки + ["", + (соединить ["Records in the ledger: ", (к строке сколько), "."] по ""), + "", + "## The fingerprint is checked against the file as the page is printed", + "", + "The fingerprint is the only thing trust in someone else's package rests on, and", + "it rots silently. So the same run that prints the table recomputes the `sha256`", + "of every address and compares it with the fingerprint field. One character apart", + "and the page is not printed at all: the run exits with 1 and", + "`FLANG_REESTR_OTPECHATOK`, names the record, both fingerprints and the address,", + "and the site build goes red on it instead of reaching the reader.", + "", + "The check is not a precaution: the fingerprints of the example ledger did part", + "from the files once, and there was nobody to see it — no CI job called the", + "registry at all (task", + "[4909](../tasks/4909-the-registry-resolution-rule-has-no-guard-and-example-fingerprints-rotted.md)).", + ""] + +тотальная функция «Вступление» + принимает язык: строка + возвращает список строки + если язык равен "en" то («Вступление по-английски») иначе («Вступление по-русски») + +тотальная функция «Заключение» + принимает язык: строка, сколько: число + возвращает список строки + если язык равен "en" + то «Заключение по-английски» от сколько + иначе «Заключение по-русски» от сколько + +тотальная функция «Страница» + принимает язык: строка, записи: список «Запись реестра» + возвращает строка + пусть начало равно («Слить» от («Вступление» от язык) и («Таблица» от язык и записи)) + соединить («Слить» от начало и («Заключение» от язык и (длина записи))) по "\n" + +объект «Дело» + «что»: строка + «текст»: строка + +тип «Ход» + вариант «Ждём ведомость» содержит что: строка + вариант «Ждём хеш» содержит дело: «Дело», эта: «Запись реестра», прочие: список «Запись реестра», беды: список строки + вариант «Ждём русскую» содержит сколько: число, английская: строка + вариант «Ждём английскую» содержит сколько: число + вариант «Ждём выкладку» содержит сколько: число + +тотальная функция «Начать печать» + возвращает «Ход» + пример «Печать начинается с чтения ведомости» + ожидается вариант «Ждём ведомость» с что равным "печать" + вариант «Ждём ведомость» с что равным "печать" + +тотальная функция «Начать выкладку» + возвращает «Ход» + пример «Выкладка начинается с того же чтения» + ожидается вариант «Ждём ведомость» с что равным "выкладка" + вариант «Ждём ведомость» с что равным "выкладка" + +тотальная функция «Беды ведомости» + принимает реестр: «Реестр» + возвращает строка + пример «Каждая негодная строка названа отдельно» + дано реестр равно запись «Реестр» с «записи» равным пустой список и «беды» равным ["раз", "два"] + ожидается "ведомость не разобрана, бед 2:\n · раз\n · два" + пусть сколько равно (к строке (длина (реестр.«беды»))) + пусть шапка равно (соединить ["ведомость не разобрана, бед ", сколько, ":"] по "") + соединить (приписать шапка к (реестр.«беды»)) по "\n · " + +тотальная функция «Кто это» + принимает з: «Запись реестра» + возвращает строка + пусть версия равно («Версия строкой» от (з.«версия»)) + соединить [(з.«имя»), " ", версия, " (", (з.«адрес»), ")"] по "" + +тотальная функция «Слова расхождения» + принимает кто: строка, было: строка, пересчитано: строка + возвращает строка + пример «Названы запись с адресом и оба отпечатка» + дано кто равно "Логика 1.0.0 (registry-example/logic.flang-package)" + дано было равно "ab12" + дано пересчитано равно "cd34" + ожидается "Логика 1.0.0 (registry-example/logic.flang-package): в ведомости ab12, пересчитано cd34" + соединить [кто, ": в ведомости ", было, ", пересчитано ", пересчитано] по "" + +тотальная функция «Слова отказа sha256sum» + принимает кто: строка, код: число, ошибки: строка + возвращает строка + пример «Названы запись, число выхода и то, что сказал прибор» + дано кто равно "Логика 1.0.0 (а)" + дано код равно 1 + дано ошибки равно "No such file\n" + ожидается "Логика 1.0.0 (а): sha256sum ответил кодом 1: No such file" + пусть чем равно (соединить [": sha256sum ответил кодом ", (к строке код), ": "] по "") + соединить [кто, чем, («Обрезать» от ошибки)] по "" + +тотальная функция «Первое слово» + принимает текст: строка + возвращает строка + пример «sha256sum печатает отпечаток, два пробела и путь» + дано текст равно "ab12 registry-example/logic.flang-package\n" + ожидается "ab12" + голова (разделить текст по " ") + +тотальная функция «Слова расхождений» + принимает беды: список строки, сошлось: число + возвращает строка + пример «Шапка называет оба числа, записи идут списком» + дано беды равно ["раз"] + дано сошлось равно 6 + ожидается "отпечатков не сошлось: 1, сошлось 6\n · раз" + пусть шапка равно (соединить ["отпечатков не сошлось: ", (к строке (длина беды)), + ", сошлось ", (к строке сошлось)] по "") + соединить (приписать шапка к беды) по "\n · " + +тотальная функция «Беда записи» + принимает путь: строка, сообщение: строка + возвращает строка + пример «Путь впереди, причина за ним» + дано путь равно "a.md" + дано сообщение равно "места нет" + ожидается "a.md: места нет" + соединить [путь, ": ", сообщение] по "" + +тотальная функция «Учесть отпечаток» + принимает беды: список строки, з: «Запись реестра», слово: строка + возвращает список строки + если слово равен (з.«отпечаток») + то беды + иначе добавить («Слова расхождения» от («Кто это» от з) и (з.«отпечаток») и слово) к беды + +тотальная функция «Учесть отказ» + принимает беды: список строки, з: «Запись реестра», код: число, ошибки: строка + возвращает список строки + добавить («Слова отказа sha256sum» от («Кто это» от з) и код и ошибки) к беды + +тотальная функция «Записать» + принимает путь: строка, содержимое: строка, потом: «Ход» + возвращает «Продолжение» + пусть поручение равно (вариант «Записать файл» с путь равным путь и содержимое равным содержимое) + вариант «Сделать» с поручение равным поручение и потом равным потом + +тотальная функция «Печатать половины» + принимает записи: список «Запись реестра» + возвращает «Продолжение» + пусть английская равно («Страница» от "en" и записи) + пусть сколько равно (длина записи) + пусть потом равно (вариант «Ждём русскую» с сколько равным сколько и английская равным английская) + «Записать» от («Путь половины» от "ru") и («Страница» от "ru" и записи) и потом + +тотальная функция «Выкладывать» + принимает дело: «Дело», сколько: число + возвращает «Продолжение» + пусть потом равно (вариант «Ждём выкладку» с сколько равным сколько) + «Записать» от («Путь выкладки») и (дело.«текст») и потом + +тотальная функция «Итог сверки» + принимает дело: «Дело», беды: список строки + возвращает «Продолжение» + пусть реестр равно («Разобрать реестр» от (дело.«текст»)) + пусть записи равно (реестр.«записи») + пусть слова равно («Слова расхождений» от беды и ((длина записи) минус (длина беды))) + если (длина беды) больше 0 + то вариант «Провал» с код равным "FLANG_REESTR_OTPECHATOK" и сообщение равным слова + иначе если (дело.«что») равен "печать" + то «Печатать половины» от записи + иначе «Выкладывать» от дело и (длина записи) + +тотальная функция «Поручение отпечатка» + принимает з: «Запись реестра» + возвращает «Поручение» + пусть доводы равно [(«Путь пакета» от (з.«адрес»))] + вариант «Запустить процесс» с программа равным "sha256sum" и аргументы равным доводы + +тотальная функция «Шаг хеша следующий» + принимает дело: «Дело», з: «Запись реестра», осталось: список «Запись реестра», беды: список строки + возвращает «Ход» + вариант «Ждём хеш» с дело равным дело и эта равным з и прочие равным осталось и беды равным беды + +тотальная функция «Пойти по записям» + принимает дело: «Дело», осталось: список «Запись реестра», беды: список строки + возвращает «Продолжение» + разбор осталось + случай пусто + то «Итог сверки» от дело и беды + случай голова первая и хвост остальные + то пусть шаг равно («Шаг хеша следующий» от дело и первая и остальные и беды) + вариант «Сделать» с поручение равным («Поручение отпечатка» от первая) и потом равным шаг + +тотальная функция «После ведомости» + принимает что: строка, текст: строка + возвращает «Продолжение» + пусть реестр равно («Разобрать реестр» от текст) + пусть дело равно (запись «Дело» с «что» равным что и «текст» равным текст) + если (длина (реестр.«беды»)) больше 0 + то вариант «Провал» с код равным "FLANG_REESTR_STROKA" и сообщение равным («Беды ведомости» от реестр) + иначе «Пойти по записям» от дело и (реестр.«записи») и пустой список + +тотальная функция «Ждать ведомость» + принимает что: строка + возвращает «Продолжение» + пусть поручение равно (вариант «Прочитать файл» с путь равным («Путь ведомости»)) + пусть потом равно (вариант «Ждём ведомость» с что равным что) + вариант «Сделать» с поручение равным поручение и потом равным потом + +тотальная функция «Шаг ведомости» + принимает что: строка, отклик: «Отклик» + возвращает «Продолжение» + разбор отклик + случай вариант «Пока ничего» + то «Ждать ведомость» от что + случай вариант «Прочитано» с содержимое как текст + то «После ведомости» от что и текст + случай вариант «Сбой» с код как код и сообщение как сообщение + то пусть слова равно («Беда записи» от («Путь ведомости») и сообщение) + вариант «Провал» с код равным код и сообщение равным слова + случай любое + то вариант «Провал» с код равным "FLANG_IO_ORDER" и сообщение равным "ждали ведомость" + +тотальная функция «Шаг хеша» + принимает дело: «Дело», з: «Запись реестра», осталось: список «Запись реестра», беды: список строки, отклик: «Отклик» + возвращает «Продолжение» + разбор отклик + случай вариант «Процесс завершён» с код как код и вывод как вывод и ошибки как ошибки + то если код равен 0 + то «Пойти по записям» от дело и осталось и («Учесть отпечаток» от беды и з и («Первое слово» от вывод)) + иначе «Пойти по записям» от дело и осталось и («Учесть отказ» от беды и з и код и ошибки) + случай вариант «Сбой» с код как код и сообщение как сообщение + то пусть слова равно («Беда записи» от "sha256sum не запустился" и сообщение) + вариант «Провал» с код равным код и сообщение равным слова + случай любое + то вариант «Провал» с код равным "FLANG_IO_ORDER" и сообщение равным "ждали ответ sha256sum" + +тотальная функция «Шаг русской» + принимает сколько: число, английская: строка, отклик: «Отклик» + возвращает «Продолжение» + разбор отклик + случай вариант «Записано» с сколько как знаков + то пусть потом равно (вариант «Ждём английскую» с сколько равным сколько) + «Записать» от («Путь половины» от "en") и английская и потом + случай вариант «Сбой» с код как код и сообщение как сообщение + то пусть слова равно («Беда записи» от («Путь половины» от "ru") и сообщение) + вариант «Провал» с код равным код и сообщение равным слова + случай любое + то вариант «Провал» с код равным "FLANG_IO_ORDER" и сообщение равным "ждали подтверждение записи" + +тотальная функция «Слова печати» + принимает сколько: число + возвращает строка + пример «Итог называет число записей и то, что сверка прошла» + дано сколько равно 7 + ожидается "Напечатано: записей 7, обе половины страницы; отпечатки сошлись у всех." + соединить ["Напечатано: записей ", (к строке сколько), + ", обе половины страницы; отпечатки сошлись у всех."] по "" + +тотальная функция «Шаг английской» + принимает сколько: число, отклик: «Отклик» + возвращает «Продолжение» + разбор отклик + случай вариант «Записано» с сколько как знаков + то вариант «Конец работы» с значение равным («Слова печати» от сколько) + случай вариант «Сбой» с код как код и сообщение как сообщение + то пусть слова равно («Беда записи» от («Путь половины» от "en") и сообщение) + вариант «Провал» с код равным код и сообщение равным слова + случай любое + то вариант «Провал» с код равным "FLANG_IO_ORDER" и сообщение равным "ждали подтверждение записи" + +тотальная функция «Слова выкладки» + принимает сколько: число, знаков: число + возвращает строка + пусть куда равно (соединить [" знаков в ", («Путь выкладки»), "; адрес на сайте "] по "") + соединить ["Выложено: записей ", (к строке сколько), ", ", (к строке знаков), куда, + («Адрес ведомости»)] по "" + +тотальная функция «Шаг выкладки» + принимает сколько: число, отклик: «Отклик» + возвращает «Продолжение» + разбор отклик + случай вариант «Записано» с сколько как знаков + то вариант «Конец работы» с значение равным («Слова выкладки» от сколько и знаков) + случай вариант «Сбой» с код как код и сообщение как сообщение + то пусть чем равно (соединить [сообщение, " — сайт не собран? сначала site:build"] по "") + вариант «Провал» с код равным код и сообщение равным («Беда записи» от («Путь выкладки») и чем) + случай любое + то вариант «Провал» с код равным "FLANG_IO_ORDER" и сообщение равным "ждали подтверждение записи" + +тотальная функция «Дальше» + принимает ход: «Ход», отклик: «Отклик» + возвращает «Продолжение» + разбор ход + случай вариант «Ждём ведомость» с что как что + то «Шаг ведомости» от что и отклик + случай вариант «Ждём хеш» с дело как дело и эта как з и прочие как осталось и беды как беды + то «Шаг хеша» от дело и з и осталось и беды и отклик + случай вариант «Ждём русскую» с сколько как сколько и английская как английская + то «Шаг русской» от сколько и английская и отклик + случай вариант «Ждём английскую» с сколько как сколько + то «Шаг английской» от сколько и отклик + случай вариант «Ждём выкладку» с сколько как сколько + то «Шаг выкладки» от сколько и отклик + +план «Напечатать страницу реестра» + состояние «Ход» + начинает с «Начать печать» + обрабатывает «Дальше» + +план «Выложить ведомость» + состояние «Ход» + начинает с «Начать выкладку» + обрабатывает «Дальше» + +тотальная функция «Объявление короткой команды registry:page» + возвращает строка + "bootstrap/flang io --plan 'Напечатать страницу реестра' — напечатать страницу реестра из ведомости" + +тотальная функция «Объявление короткой команды registry:publish» + возвращает строка + "bootstrap/flang io --plan 'Выложить ведомость' — выложить ведомость реестра в собранный сайт"