Documentation
¶
Overview ¶
Package notice authors bentoo notices: one input becomes a GLEP 42 news item in the overlay and a YAML file in the site repository, sharing one ID.
The package is pure where it can be — validation and both renderers touch no disk — so every file format is pinned by tests before anything is written. It prints nothing and logs nothing: errors and warnings are returned to the command, which owns the terminal.
Index ¶
- Variables
- func AffectsString(a Affects) string
- func EditBody(ctx context.Context, initial string, env func(string) string, run Runner) (body string, err error)
- func NewsPath(overlay, id string) string
- func ReadBody(ctx context.Context, bodyFile string, env func(string) string, run Runner) (string, error)
- func RenderNews(n Notice) (text string, warnings []string)
- func RenderSiteYAML(n Notice) ([]byte, error)
- func SiteNoticesDir(sitePath string) string
- func SitePath(sitePath, id string) string
- func TerminalRunner(ctx context.Context, name string, args ...string) error
- func ValidateSeverity(s string) error
- func ValidateSummary(s string) error
- func ValidateTitle(s string) error
- type Affects
- type BodyEditor
- type Changes
- type Input
- type Notice
- type Range
- type Result
- type Runner
Constants ¶
This section is empty.
Variables ¶
var ( ErrNoEditor = errors.New("no editor: pass --body-file, or set VISUAL or EDITOR") ErrEditorFailed = errors.New("the editor failed") ErrEmptyBody = errors.New("the notice body is empty") )
Errors of ReadBody.
var ( ErrType = errors.New("invalid notice type") ErrSeverity = errors.New("invalid notice severity") ErrName = errors.New("invalid notice name") ErrTitle = errors.New("invalid notice title") ErrSummary = errors.New("invalid notice summary") ErrPublished = errors.New("invalid publication date") ErrFuture = errors.New("publication date is in the future") ErrControlChar = errors.New("forbidden control character") ErrAffectsRequired = errors.New("this notice type needs at least one --affects") )
Sentinel errors. Every error New returns wraps one of these and names the flag or field involved, so a caller can branch with errors.Is and a person can read which input to fix.
var ( ErrBadID = errors.New("invalid notice ID") ErrNewsExists = errors.New("the overlay already has a news item with this ID") ErrSiteDirMissing = errors.New("the site has no notices directory") ErrSiteExists = errors.New("the site already has a notice file with this ID") )
Errors of Publish and Revise.
var ( ErrNotFound = errors.New("no news item with this ID") ErrSiteMissing = errors.New("the site has no notice file with this ID") ErrNothingToRevise = errors.New("nothing to revise: the text is unchanged and no field was given") ErrMalformedNews = errors.New("malformed news item") ErrMalformedSite = errors.New("malformed site notice") )
Errors of Revise.
var ErrAffects = errors.New("invalid --affects value")
ErrAffects is wrapped by every --affects parse error.
Functions ¶
func AffectsString ¶
AffectsString renders a in the --affects syntax it was parsed from.
func EditBody ¶
func EditBody(ctx context.Context, initial string, env func(string) string, run Runner) (body string, err error)
EditBody opens initial in the user's editor on a temporary file and returns the text saved (see editedText), with surrounding blank lines trimmed. The temporary file is removed on every path.
func ReadBody ¶
func ReadBody(ctx context.Context, bodyFile string, env func(string) string, run Runner) (string, error)
ReadBody returns the notice body: the content of bodyFile when it is given, otherwise what the user writes in $VISUAL, else $EDITOR (see editedText). env reads the environment (os.Getenv in production).
func RenderNews ¶
RenderNews renders n as a GLEP 42 news item (format 2.0): the headers in order, one Display-If-Installed per affects entry, one blank line, then the body wrapped at 72 columns with tabs expanded.
Display-If-Installed headers combine with OR, while the ranges of one feed entry combine with AND, so an entry with several ranges cannot be one header: it is written as the bare package and reported in warnings.
func RenderSiteYAML ¶
RenderSiteYAML renders n as the site's notice file, with the fields of the site's notice data model: id, type, severity, title, summary, body, affects, published, updated, in that order. The schema has no author and no revision — those live in the news item only.
The document is built as a yaml.Node tree rather than marshalled from a struct, because the site's YAML parser types every plain scalar: a version `1.10` written bare reads back as the float 1.1, a slot `1` as an integer, and a timestamp as a date. Every such scalar is therefore double-quoted, and the body is a literal block so its lines survive as written.
The reader is js-yaml (YAML 1.2), not yaml.v3 (YAML 1.1), and the two disagree on what a plain scalar means: js-yaml reads `2026-10-02 10:00:00Z` or `._5` as a date or a number that yaml.v3 would leave plain. Title and summary are free text, so they are always quoted too.
func SiteNoticesDir ¶
SiteNoticesDir is where the site keeps its notice files.
func TerminalRunner ¶
TerminalRunner runs the editor on the user's terminal. It never goes through a shell, and it stays in bentoo's process group on purpose: an interactive editor that is moved out of the foreground group loses the terminal's signals and its job control.
func ValidateSeverity ¶
ValidateSeverity checks a --severity value.
func ValidateSummary ¶
ValidateSummary checks a --summary value: 1..300 code points, single line, no forbidden control character.
func ValidateTitle ¶
ValidateTitle checks a --title value: 1..50 code points, single line, no forbidden control character.
Types ¶
type Affects ¶
Affects is one affected package: a category/package, an optional slot, and zero or more ranges that combine with AND.
func ParseAffects ¶
ParseAffects parses one --affects value, `<category>/<package>[:<slot>][ <range>[,<range>…]]`, where a range is an operator from <, <=, =, >=, > immediately followed by a Gentoo version. A rejection quotes the value and the part that failed.
type BodyEditor ¶
BodyEditor opens current in the user's editor and returns the edited text. Revise takes one, so the command decides how the body is edited.
func NewBodyEditor ¶
func NewBodyEditor(env func(string) string, run Runner) BodyEditor
NewBodyEditor returns the BodyEditor `notice revise` uses: the current text, below the instructions and the scissors line, opened in $VISUAL or $EDITOR. Saved untouched, it comes back unchanged, `#` lines included.
type Changes ¶
Changes are the fields `notice revise` replaces. An empty string or a nil slice means the flag was not given.
type Input ¶
type Input struct {
Type, Severity, Name, Title, Summary, Published, Author string
Affects []string
Body string
}
Input is the raw, unvalidated notice as the command received it: flag values verbatim, plus the body read from a file or the editor.
type Notice ¶
type Notice struct {
ID, Type, Severity, Title, Summary, Author, Body string
Affects []Affects
// Published and Updated are UTC. A new notice has both at midnight of
// its publication date; a revision moves Updated only.
Published, Updated time.Time
// Revision is the news item's Revision header: 1 for a new notice.
Revision int
}
Notice is a validated notice, the single source both files are rendered from.
type Range ¶
type Range struct {
Op, Ver string
}
Range is one version bound of an affects entry: an operator from <, <=, =, >=, > and a Gentoo version.
type Result ¶
type Result struct {
// Paths lists every file written, the news item first.
Paths []string
// YAML is the site document, for the command to print when no
// notice.site_path is configured.
YAML []byte
// Warnings are the news renderer's.
Warnings []string
}
Result is what a publish or a revision wrote.
func Publish ¶
Publish writes n as a news item in overlay and, when sitePath is not empty, as a site notice file. Every destination is checked before anything is written; both files are created without replacing anything; and when the site file cannot be written the news item is removed again, so the ID stays free.
func Revise ¶
func Revise(ctx context.Context, id string, changes Changes, overlay, sitePath string, edit BodyEditor, now time.Time, ) (Result, error)
Revise opens the text of notice id in edit, applies changes, and rewrites the news item in overlay and — when sitePath is not empty — the site file, each replaced atomically. The news item's Revision goes up by one and the site file's updated becomes now in UTC; Posted, published and the ID stay. Nothing is written when the text comes back unchanged and no field was given, or when any check fails.