Documentation
¶
Overview ¶
Package util contains small, cross-layer helpers with no business ownership.
Keep package contents generic and dependency-light. Helpers that belong to a specific subsystem should live with that subsystem instead of being added here.
Index ¶
- Constants
- func CanonicalPublicID(s string) (string, bool)
- func ClipRunes(s string, maxRunes int) string
- func FormatDuration(d time.Duration) string
- func FormatMinute(t time.Time) string
- func NewPublicID() (string, error)
- func Ptr[T any](v T) *T
- func ResolvePath(root, userPath string) (string, error)
- func ResolveWorkspaceRoot(dir string) (string, error)
- func TruncateRunes(s string, maxRunes int) string
- func WithEnvVar(envKey, value string, fn func() error) error
- func WriteFileAtomic(path string, data []byte, perm os.FileMode) error
Constants ¶
const (
// PublicIDLen is the canonical text length.
PublicIDLen = 20
)
A public ID is the only handle a server entity is allowed to show the outside world. It is 96 bits of crypto-random data rendered as 20 lowercase base32 characters, and that text form is also what the database stores:
gsyt7at6cjfr33d73mta
The alphabet is deliberately narrower than base64url. A public ID reaches Kubernetes Job names, object-storage paths on case-insensitive filesystems, URLs, and people retyping it, and base32 is the widest encoding that survives all four unchanged. Storing the text rather than the raw bytes costs 8 bytes per value and makes every direct database query readable; the raw-byte form died with that trade. See docs/design/entity-identity.md §4.2.
Variables ¶
This section is empty.
Functions ¶
func CanonicalPublicID ¶
CanonicalPublicID reports whether s is a public ID and returns its one canonical text form.
Input is accepted in either case, so an ID retyped from a title-cased document still resolves. The text is decoded and re-encoded to prove it was canonical apart from case: 20 base32 characters carry 100 bits, and the 4 bits past the value must be zero. Without that check, several texts would name one row.
func ClipRunes ¶
ClipRunes returns at most the first maxRunes runes of s without adding a suffix. If maxRunes is non-positive, it returns the empty string.
func FormatDuration ¶
FormatDuration formats a duration in a compact human-readable way.
func FormatMinute ¶
FormatMinute formats an instant as YYYY-MM-DD HH:MM in local time.
The reader is a person — a tool result or a listing — so local time is the useful rendering. Stored and transported instants stay UTC.
func NewPublicID ¶
NewPublicID returns a fresh public ID in canonical text form.
It returns an error rather than panicking on entropy failure: that must surface as one failed create, not as a process abort inside a request.
func Ptr ¶
func Ptr[T any](v T) *T
Ptr returns a pointer to v. Useful for filling optional pointer fields.
func ResolvePath ¶
ResolvePath resolves a user-supplied path relative to root, ensuring the result stays under root. Returns the absolute, cleaned path. Includes a Windows-safe prefix check (filepath.Rel can return an absolute path when roots differ on different drives). Does NOT stat the path — callers handle existence and type checks.
func ResolveWorkspaceRoot ¶
ResolveWorkspaceRoot resolves and absolutizes a workspace root directory. If dir is empty, the current working directory is used.
func TruncateRunes ¶
TruncateRunes truncates s to at most maxRunes runes and appends an ellipsis when truncation happens. If maxRunes is non-positive, it returns the empty string.
func WithEnvVar ¶
WithEnvVar sets envKey to value for the duration of fn, then restores the previous process env state.
func WriteFileAtomic ¶
WriteFileAtomic writes data to path so that a reader sees either the previous file or the complete new one, never a half-written mix. os.WriteFile truncates the target before writing, so an interruption part-way through destroys the only copy of a document that was fine a moment earlier.
The temporary file is created in the target's own directory, because a rename is only atomic within one filesystem. Its bytes are synced before the rename publishes them: a rename that beat its own data to disk would swap in a file whose contents never arrived. The parent directory is created if it is missing, so callers do not need their own MkdirAll.
This makes a write all-or-nothing, which is not the same as making it durable. The directory entry is not synced, so a power loss immediately after a successful return may still show the previous file. That is the intended weaker guarantee — the previous file is complete and parsable, which is what callers of this helper need.
Types ¶
This section is empty.