Documentation
¶
Overview ¶
Package authzmapgen — ПРОИЗВОДИТЕЛЬ двух таблиц типов пакета `authzmap` из манифестов модулей (задача #1092).
───────────────────────────────────────────────────────────────────────────── ПРЕДМЕТ: СВЕРКУ ЗАМЕНЯЕТ ВЫВОД
Перечень «набор глагольных отношений каждого типа» жил в Go рукописным литералом, а манифест модуля объявлен источником истины о том, что у платформы существует. Два места об одном предмете обязаны совпадать — и совпадение стерёг гейт.
Гейт равенства и вывод решают одну задачу с разной ценой ошибки: гейт ловит расхождение ПОСЛЕ того, как оно внесено, и требует править Go при объявлении действия; вывод делает расхождение невыразимым by construction. «Объявить действие» перестаёт быть правкой Go.
───────────────────────────────────────────────────────────────────────────── КРУГ «ПРОИЗВОДИТЕЛЬ СПРАШИВАЕТ У СВОЕГО ПРОДУКТА» — РАЗОРВАН (задача #1930)
Здесь стояло: вторую таблицу каталога — `objectTypes` — вывести НЕЛЬЗЯ, потому что загрузчик проверяет `objectType` каждой записи на членство в ней же, и новый тип не проходит ни одной из двух дверей. Это было верно ровно до смены РЕФЕРЕНТА, и абзац оставлен разбором, а не удалён: следующий, кто упрётся в тот же круг, обязан найти здесь способ, а не запрет.
Что теперь верно: `Collect` зовёт `manifest.CheckTreeForGeneration`, и в этом проходе загрузчик существование типа НЕ СУДИТ — судит его канон, сверку с которым в обе стороны ведёт `modelrender.Sweep` («манифест порождает тип, которого в каноне НЕТ» и обратное). Форму — «тип назван дословно» — загрузчик судит по-прежнему и при любом референте.
Полоса ПОТРЕБЛЕНИЯ не тронута: чтение доставленных манифестов на старте службы идёт умолчанием, то есть таблицей, и там она законный судья — к тому моменту она уже произведена и вкомпилирована. Почему это ОДИН предикат с двумя законными референтами, а не два места об одном предмете — `manifest.TypeReferent`.
───────────────────────────────────────────────────────────────────────────── ГРАНИЦА, КОТОРУЮ НАДО ЗНАТЬ: ПРОИЗВОДИТЕЛЬ ЗАВИСИТ ОТ СВОЕГО ПРОДУКТА
Загрузчик манифеста импортирует `authzmap` — тот самый пакет, в который пишется продукт. Значит перегенерация возможна только из СОБИРАЮЩЕГОСЯ состояния: удали продукт — и производитель перестанет собираться вместе с ним. Штатный случай (манифест изменился, продукт устарел) от этого не страдает: устаревший продукт компилируется. Смена референта эту границу НЕ снимает: она про импорт пакета, а не про содержимое таблицы, — и это надо сказать прямо, иначе разбор выше прочтётся шире сделанного.
───────────────────────────────────────────────────────────────────────────── ПОЧЕМУ ГЕНЕРАТОР ЖИВЁТ ЗДЕСЬ, А НЕ В `tools/`
Форму манифеста судит ОДИН исполнитель — загрузчик `services/iam/internal/manifest`, — и он закрыт правилом видимости Go для пакетов вне `services/iam/`. Генератор в `tools/` пришлось бы снабдить ВТОРЫМ разбором той же формы, и разошлись бы они молча: генератор перестал бы видеть ключ, который загрузчик принимает, а таблица тихо потеряла бы тип. Тот же довод уже записан у гейта манифестов в `internal/repohygiene`, где отступление названо вместе с причиной — она свойство языка, а не выбор.
Здесь свойство языка работает В НАШУ ПОЛЬЗУ: генератор внутри `services/iam/` зовёт настоящий загрузчик, и второго объявления формы не заводится.
───────────────────────────────────────────────────────────────────────────── ПОЧЕМУ ГЕЙТ ДРЕЙФА С МОДЕЛЬЮ ОСТАЁТСЯ
Он сверяет таблицы с КАНОНИЧЕСКОЙ МОДЕЛЬЮ, а не с манифестом, и предмет у него другой: манифест и канон — два рендера одного замысла, и их согласие есть утверждение, которое кто-то обязан проверять. Снять его вместе с заведением вывода значило бы оставить дерево без обоих.
Index ¶
Constants ¶
const GeneratedRelPath = "services/iam/internal/authzmap/tables_gen.go"
GeneratedRelPath — координата порождённого файла от корня репозитория.
Объявлена ЗДЕСЬ и один раз: её знают команда записи и гейт свежести, и второе объявление развело бы их молча — гейт сверял бы файл, которого никто не пишет.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Census ¶
type Census struct {
ManifestsRead int
PathsSeen int
Modules int
Resources int
VerbBearing int
VerbRelations int
// InternalExcluded — действий ВНУТРЕННЕЙ плоскости, не вошедших в набор.
//
// В `StableSummary` (а значит и в порождённый файл) НЕ входит намеренно:
// туда идут только величины, из которых собран сам файл, а исключённое в
// него по построению не попало. Здесь же число несущее — без него
// «отношений действия 109» неотличимо от «внутренних действий нет вовсе»,
// и снятая ветвь исключения выглядела бы как исправная работа.
InternalExcluded int
}
Census — ОБЪЁМ осмотренного. Печатается вызывающим всегда: «ноль расхождений» обязано быть отличимо от «ноль прочитанного».
func CheckFresh ¶
CheckFresh — ОДИН предикат свежести на обоих вызывающих: гейт дерева и доказательство его способности упасть.
Второй экземпляр сравнения (одно в теле пробы дерева, другое в инъекции) разошёлся бы с первым молча — и доказательство говорило бы о коде, которого гейт не исполняет.
Отдаёт перепись ВСЕГДА, включая исход отказа: без неё «файл отстал» не отличается от «манифестов не нашлось», а чинятся эти два состояния по-разному.
func (Census) StableSummary ¶
StableSummary — перепись для ПОРОЖДЁННОГО ФАЙЛА: только величины, зависящие от манифестов.
Объём обхода сюда НЕ входит намеренно. Он считает файлы всего дерева, то есть меняется от всякой правки где угодно, — и файл, несущий его, расходился бы со своим производителем на изменении, которое к таблицам отношения не имеет. Гейт свежести краснел бы, а находка называла бы не предмет: прокси-предикат, ломающийся раньше того, что он стережёт.
type Tables ¶
Tables — то, что генератор вывел из дерева.
func Collect ¶
Collect читает манифесты ДЕРЕВА тем же обходом и тем же загрузчиком, каким их читает проверка дерева, и выводит обе таблицы.
Находка обхода — ОТКАЗ, а не пропуск записи: таблица, собранная из части манифестов, выглядит целой и молча теряет тип, а потерянный тип не резолвится краем — вопрос о нём не задаётся вовсе, и проверка выглядит пройденной.
Беспредметный обход — тоже отказ: «манифестов ноль» неотличимо от «манифесты прочитаны и в них ничего нет», а порождённая из пустоты таблица снесла бы каталог целиком.
func (Tables) ObjectTypeSet ¶
ObjectTypeSet — множество типов модели, которые производитель эмитит.
Отдаётся ОТСЮДА, а не собирается вызывающим: второй обход тех же записей разошёлся бы с первым на первом же новом виде записи.
type TypeEntry ¶
type TypeEntry struct {
// Dotted — имя в словаре КАТАЛОГА: `<модуль>.<ресурс>`.
Dotted string
// ObjectType — имя в словаре МОДЕЛИ ПРАВ.
ObjectType string
// VerbRelations — набор `v_*`, объявленный этим типом, отсортированно.
//
// Пусто означает «тип не глагольный»: строки в `typeVerbRelations` он не
// даёт вовсе. Различать это от «набор пуст» обязан читатель — потому и
// отдаётся nil, а не пустой срез.
VerbRelations []string
}
TypeEntry — одна строка обеих таблиц сразу.
Строка одна, потому что и точечное имя, и набор отношений объявляет ОДНА запись манифеста: разведя их по двум структурам, генератор завёл бы два обхода одного предмета.
type TypeTableSurvey ¶
type TypeTableSurvey struct {
// FilesRead — не-тестовых файлов Go прочитано.
FilesRead int
// MapsRead — package-level карт прочитано, включая не-типовые.
MapsRead int
// Generated — таблиц типов в ПОРОЖДЁННОМ файле.
Generated int
// HandWritten — таблиц типов вне порождённого файла.
HandWritten int
// HandWrittenNames — их имена, отсортированно: находка обязана называть
// предмет, иначе читатель идёт искать его сам.
HandWrittenNames []string
}
TypeTableSurvey — объём осмотренного и вердикт.
Печатается ВСЕГДА: «рукописных одна» неотличимо от «прочитано ноль файлов», если объём не назван.
func SurveyTypeTables ¶
func SurveyTypeTables(dir string, types map[string]struct{}) (TypeTableSurvey, error)
SurveyTypeTables обходит каталог пакета продукта и считает таблицы типов.
Каталог подаётся ПУТЁМ, а не содержимым: инъекция подаёт синтетический тем же путём, каким гейт подаёт настоящий, поэтому доказательство способности упасть относится к ЭТОЙ функции, а не к её копии.
Пустой набор типов — ОТКАЗ, а не «таблиц ноль»: предикат «все элементы суть типы» на пустом наборе не выполняется никогда, и перепись молча объявила бы пакет свободным от таблиц.