Documentation
¶
Overview ¶
forge:exclude-contract devstack is CLI-internal dev-stack orchestration glue (dev-block wiring, git-facts, lockfile) for `forge up`, not a contract-shaped service the bootstrap wires. Opt out of the require-contract rule.
Package devstack owns forge's parallel-dev-stack primitives: the raw git facts that distinguish one working tree from another, and a memoized port-block allocator. Together they let N dev stacks (one per git worktree) run in parallel against shared clusters without colliding — DECLARATIVELY: forge supplies the facts + the allocator, KCL composes them.
There is deliberately NO "instance" abstraction and NO user-visible index. forge exposes two raw git facts as KCL options and lets the KCL author decide which to key on:
option("worktree") -> the LINKED-worktree directory basename, or "" on
the PRIMARY checkout (any branch).
option("branch") -> the current git branch, sanitized DNS-safe, always.
and one resolved builtin that hides the port arithmetic entirely:
forge.allocate_port(base, key) -> base + block(key)*100
where block(key) is a small int forge assigns the first time it sees key and persists (see blocks.go). The default — primary checkout, key "" — renders byte-identically to a stack with no dev-stack parameterization.
Index ¶
- func ActiveDArgs() []string
- func AllocateBlock(projectDir, key string) (int, error)
- func AllocatePort(projectDir string, base int, key string) (int, error)
- func Branch(projectDir string) string
- func Sanitize(s string) string
- func SetActive(o Options)
- func Worktree(projectDir string) string
- type Block
- type Options
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ActiveDArgs ¶
func ActiveDArgs() []string
ActiveDArgs is the convenience the render paths call: the `-D` bindings to push the active git facts into KCL (nil for the default stack).
func AllocateBlock ¶
AllocateBlock returns the stable block index for key, assigning the next free one (≥1) on first use. key == "" is block 0 (the default stack) and is never stored or locked. Atomic under the registry lock.
func AllocatePort ¶
AllocatePort is the engine behind the forge.allocate_port(base, key) KCL builtin. It returns base + block(key)*100, where block(key) is the small integer forge assigns the FIRST time it sees key and MEMOIZES in the lock-guarded registry. The block index is INTERNAL — it never surfaces in KCL; KCL only ever sees the final port.
Semantics (the contract):
- key == "" ⇒ block 0 ⇒ returns base UNCHANGED, with no registry/lock touch (the byte-identical default-stack path).
- One block PER KEY: every allocate_port(*, key) call for the same key shares that key's block, so all of a stack's ports shift by the SAME offset.
- DETERMINISTIC: base + block*100, NO availability stepping. A port that must equal an externally-fixed value (a k3d pre-mapped host port; the host reliant's LISTEN port) must never step off a held port, so up and deploy — and the external mapping — always agree.
The registry read-modify-write happens entirely under the file lock, so a concurrent first-`up` of two worktrees cannot race two keys to the same block. Persistence makes the block stable across runs AND identical under both `forge up` and `forge deploy` (both call this through the same builtin), which is the permanent up-vs-deploy port fix.
func Branch ¶
Branch returns the current git branch for projectDir, sanitized DNS-safe, or "" outside a repo or on a detached HEAD. Unlike Worktree, Branch is reported for the primary checkout too — a consumer that WANTS to key on branch (e.g. a stack-per-branch workflow) can; one that wants the primary checkout to stay default keys on Worktree instead. The author chooses.
func Sanitize ¶
Sanitize lowercases s and reduces it to a DNS-safe label: [a-z0-9-], collapsed dash runs, no leading/trailing dash, bounded length. Returns "" when nothing survives (e.g. an all-symbol branch name).
func SetActive ¶
func SetActive(o Options)
SetActive records the git facts for this process's subsequent renders. Call once, before the first render, on the up/deploy path only.
func Worktree ¶
Worktree returns the LINKED-worktree directory basename for projectDir, or "" on the PRIMARY checkout (regardless of branch) and outside any git repo. This is the fact a consumer keys on when it wants the primary checkout to stay the DEFAULT stack on every branch — the everyday dev loop is then byte-identical to today, and only a `git worktree add`'ed checkout gets its own stack.
The parallelism unit here is the WORKTREE, never the branch: branches change constantly and the primary checkout must always render default.
Detection: a linked worktree's per-worktree git dir (`git rev-parse --absolute-git-dir` → …/.git/worktrees/<name>) differs from the repo's common dir (`--git-common-dir` → the primary's …/.git). The primary checkout has them equal. This is git's own authoritative distinction — far more robust than sniffing whether `.git` is a file vs a directory (which submodules and some tooling also make a file). The returned value is sanitized DNS-safe.
Types ¶
type Options ¶
type Options struct {
Worktree string // option("worktree"): linked-worktree basename, "" on primary
Branch string // option("branch"): sanitized current branch, always
}
Options are the raw git facts pushed INTO KCL as options for this forge command. The zero value (both fields "") is the default stack — it emits NO -D args, so a plain render sees option("worktree") == None (KCL default "") and option("branch") == None, rendering byte-identically to a stack with no dev-stack parameterization.
func Active ¶
func Active() Options
Active returns the options set by SetActive (zero value when unset).
func Resolve ¶
Resolve gathers the git facts for projectDir. Cheap and side-effect-free (no files, no lock): the durable state lives in the block registry, which allocate_port touches lazily. Outside a repo both facts are "".
func (Options) DArgs ¶
DArgs returns the `-D key=value` KCL option bindings that push these git facts into the render — the extension of the existing namespace/image_tag option seam. An empty fact is OMITTED (not emitted as ""), so the default stack returns NO args and renders byte-identically. Values are QUOTED KCL string literals so an all-digit worktree/branch name stays str, never an int (the same coercion fix as image_tag).