12. Packages
A package is a git repository containing Korrin source that another
program can import. This section is the normative description of the
manifest, the lockfile, how a bare import specifier resolves once packages
exist, and the korrin pkg command that manages them
(ADR 0031,
ADR 0032).
Packages, in the sense this section describes, are pure Korrin source. A dependency written in Rust and compiled in — a native module — is a related but distinct kind of dependency, covered separately in §13.
12.1 The manifest: korrin.toml
A directory with a korrin.toml and a src/lib.kor is a package.
[package]
name = "requests"
version = "0.3.0"
[dependencies]
json = { git = "https://github.com/alice/korrin-json", tag = "v1.2.0" }
[package].nameand[package].versionare the package's own declared identity. They play no role in how a dependent resolvesimport— see §12.3.[dependencies]is a table of local name → source. Each entry needs agitURL and exactly one oftag,branch, orrev. A package's own[dependencies]table must be empty — see §12.4.- The entry file is always
src/lib.kor, regardless of[package].name. - An entry may also set
native = true, marking it as a native module (§13) rather than.korsource. Everything in this section (name resolution, the lockfile, the collision rule) applies to a native dependency exactly as it does to a plain one; only what happens after fetching it differs.
12.2 The lockfile: korrin.lock
# @generated by `korrin pkg` — do not edit by hand.
version = 1
[[package]]
name = "json"
git = "https://github.com/alice/korrin-json"
rev = "a1b2c3d4e5f6..."
path = ".korrin/packages/json"
korrin.lock pins the exact commit resolved for every dependency, even one
specified in korrin.toml by tag or branch. korrin pkg install writes
it; korrin pkg update is the only command that moves an existing pin. An
application commits korrin.lock; a package intended to be depended on does
not.
Fetched packages are checked out locally at .korrin/packages/<name>/, next
to the korrin.toml that declares them.
12.3 Resolution: one merged namespace
import_statement = "import" , STRING , [ "as" , NAME ] ;
Extends §11.1's resolution
rule with a third outcome for a bare (non-./) specifier:
./…or../…— a file, as §11.1 describes. Unchanged.- anything else — checked against the built-in module table
(§11.4, §11.5)
first, then against the current package's installed dependencies. No new
syntax distinguishes the two —
import "math"andimport "requests"are written identically. A name cannot appear in both tables:korrin pkg add/installrefuses to add a dependency whose local name collides with a built-in module's name (ADR 0032). A name in neither table isE0314.
import "not_a_real_package"
# error: E0314
A package's own bare imports resolve against that package's installed
dependencies (from its own korrin.toml/korrin.lock), not the top-level
program's — but since packages are leaf-only (§12.4), a package's own
[dependencies] table is always empty, so in practice a package's bare
imports can only ever reach built-in modules. A package's relative
(./) imports resolve against its own directory, exactly like any other
file's.
12.4 Leaf-only packages
A package's own korrin.toml must declare an empty (or absent)
[dependencies] table. korrin pkg add/install rejects a package that
declares one:
korrin pkg: "json" (https://github.com/alice/korrin-json) declares
dependencies of its own — packages with dependencies are not supported
in Milestone 5
A package may depend on nothing. Depending on another package is not yet possible for a package itself, only for a top-level program.
12.5 The korrin pkg command
| Command | Effect |
|---|---|
korrin pkg add <git-url> [--tag T | --branch B | --rev R] [--name NAME] [--native] | Adds a dependency to korrin.toml and resolves it into korrin.lock. NAME defaults to the repository's basename. --native marks it a native module — see §13. |
korrin pkg remove <name> | Removes a dependency and re-resolves korrin.lock. |
korrin pkg install | Fetches everything korrin.toml declares that isn't already checked out at its pinned commit; writes or refreshes korrin.lock. |
korrin pkg update [name] | Re-resolves a tag- or branch-pinned dependency to its current tip commit. Updates every dependency if name is omitted. |
korrin pkg list | Prints each resolved dependency: name, git URL, pinned commit, local path. |
korrin pkg build | Regenerates and compiles this project's native-module runner — see §13.4. |
add/install/remove/update run korrin pkg build automatically
whenever they change the set of native dependencies; see
§13.4 for exactly when.
korrin pkg operations that fail (an unreachable git URL, a malformed
manifest, a rejected leaf-only or name-collision dependency) print a message
to standard error and exit non-zero. They are not Korrin diagnostics — there
is no source span to point at, since nothing runs a Korrin program during
korrin pkg add/install/update.
12.6 Errors
An installed-package import that cannot be resolved — no such name in the
lockfile, the checkout is missing on disk, or the package's src/lib.kor
fails to compile — is E0314, the same code a bad ./ or
built-in specifier already raises: all three are the same category of
problem ("this import could not be resolved, read, or compiled"), not
three different ones. A cycle that crosses from a program into a package and
back is E0315, exactly as for files (§11.6).