Guidedog Manual 0.2.0
Language
On this page
Guidedog / Documentation 0.2.0

gds

Package gds is the GDS process of docs/gds (GDS 0001) as a library: it loads the discussion records of a directory into a Catalog, plans changes to them (a new draft, a promotion, a state or label change, the regenerated index) as a Plan, applies a plan as one recoverable transaction under a lock. RST publication uses the project engine; Typst typesets PDF. Failure is a Problem that carries the exit status, never a panic. It allocates with context.allocator and frees nothing, so a caller runs it in an arena, as guidedog gds does, and frees the arena when done.

Types

gds.Catalog :: struct
records: [dynamic]Record
reserved: int
gds.Change :: struct
path: string
before: string
after: string
existed: bool
present: bool
gds.Field :: struct
name: string
literal: string
gds.Options :: struct
dir: string
command: string
identifier: string
author: string
slug: string
labels: string
state: string
label: string
to: string
reason: string
evidence: string
discussion: string
record: string
target: string
number: int
dry_run: bool
check_only: bool
historical: bool
render: bool
rollback: bool
gds.Plan :: struct
changes: [dynamic]Change
summary: string
gds.Problem :: struct
code: string
title: string
path: string
message: string
hint: string
exit: int
gds.Record :: struct
number: string
slug: string
title: string
state: string
kind: string
created: string
updated: string
discussion: string
authors: []string
labels: []string
path: string
text: string
historical: bool
fields: [dynamic]Field

Procedures

gds.apply :: proc(dir: string, plan: Plan) -> Problem

apply writes a plan’s changes as one transaction under dir: each file must still have the contents the plan was made from, a journal records the originals first, and every file is replaced atomically, so an interrupted apply can be rolled back by recover. Hold lock while planning and applying.

gds.build :: proc(o: Options, c: Catalog, engine: string) -> (string, Problem)

build publishes o.target “pdf”, “html”, or “both” (the default). An RST catalog uses the project engine: HTML is a complete site and o.record selects separate PDF books. A legacy Typst catalog compiles records directly into docs/build. It returns the output paths, comma-separated. Typst is needed only for RST PDF or legacy publication; engine names its program, unless the compiler is embedded. Publication is staged so a compiler failure cannot replace a previously good output.

gds.check_index :: proc(dir: string, c: Catalog) -> Problem

check_index is a Problem when the registry or bundle of dir differs from what index_plan would write.

gds.check_sources :: proc(c: Catalog) -> Problem

check_sources checks that every record other than a historical one has the sections the discussion template requires; the first missing one is a Problem.

gds.edit_plan :: proc(o: Options, c: Catalog) -> (plan: Plan, p: Problem)

edit_plan plans the change o.command asks of the record o.identifier names: promote (a draft takes the next number), state (a move the process allows, with its reason and evidence), or label; with the index refreshed. It changes nothing; apply writes the plan. A historical record, or a move the process forbids, is a Problem.

gds.index_plan :: proc(dir: string, c: Catalog) -> (plan: Plan, p: Problem)

index_plan plans the regenerated registry.typ and bundle.typ of dir for the catalog; the plan has no changes when they are current.

gds.load :: proc(dir: string) -> (catalog: Catalog, p: Problem)

load reads the discussion directory dir (records/*.rst or legacy *.typ), and the numbers it reserves, into a catalog allocated in the context arena. It fails with a Problem, and changes nothing, when an update awaits recovery, a record is unreadable, too large, or malformed, or two records claim one number or slug.

gds.lock :: proc(dir: string) -> (^os.File, Problem)

lock takes the lock of the discussion directory dir and returns its file, which the caller holds while it plans and applies, and closes to release; another command holding it is a Problem. A kernel lock is released even if the process crashes. The lock file is kept: unlinking it would allow two processes to lock different inodes at the same path.

gds.new_plan :: proc(o: Options, c: Catalog) -> (plan: Plan, p: Problem)

new_plan plans a new draft record for o.identifier: its file, from the template, and the refreshed index. It changes nothing; apply writes the plan. A bad or taken slug, or no author (–author, or git’s user.name), is a Problem.

gds.next_number :: proc(o: Options, c: Catalog) -> (int, Problem)

next_number is the number a promoted draft takes: o.number when it is free, else one past the highest that a record, the registry’s reservation, or a gds/ branch of the repository in o.dir holds. A number already reserved, or above 9999, is a Problem.

gds.now :: proc() -> datetime.DateTime

now is the moment a build is stamped with. As in Sphinx and other reproducible builds, SOURCE_DATE_EPOCH (seconds since 1970, in UTC) sets it; otherwise it is the local time, in the local time zone, which stays loaded for the life of the process.

gds.parse_record :: proc(path, source: string) -> (r: Record, p: Problem)

parse_record reads RST metadata or legacy #let gds-… lines from source; the record borrows path and source. A missing, repeated, unknown, or invalid field, a bad slug, or dates out of order is a Problem.

gds.problem :: proc(code, title, path, message, hint: string, exit := 1) -> Problem

problem makes a Problem: its code (“gds.slug”), title, the path it concerns, what went wrong, a hint, and the exit status the command returns for it.

gds.recover :: proc(dir: string, dry_run: bool) -> Problem

recover finishes an interrupted apply: it restores every file the journal names to its original contents and removes the journal; dry_run only checks that it can. No journal is no work.

gds.replace_field :: proc(source, key, literal: string) -> string

replace_field returns source with the value of the metadata field key replaced by the Typst literal (quoted, as “\”accepted\””), allocated in the context arena.

gds.resolve :: proc(c: Catalog, id: string) -> (Record, Problem)

resolve finds the one record an identifier names: its number (7 or “0007”), slug, title, or file name. The record borrows the catalog; no match, or more than one, is a Problem that lists the candidates.

gds.today :: proc() -> string

today is now’s date, as YYYY-MM-DD.

Constants

gds.LABELS
gds.STATES :: []string{"prediscussion", "discussion", "accepted", "published", "committed", "abandoned"}