packages
so far every module a program imported was either in the standard library or in a directory beside it. this chapter depends on code someone else published. kanso calls a package a hako, and the package manager is the kanso binary itself: kanso install, kanso list and kanso update.
three rules cover most of it. a hako's name is its GitHub path, such as kanso-lang/kanso-json, so there is no registry and no account to create. the import is the manifest: there is no separate file listing dependencies, because the import lines already say what the program uses. and a release is a git tag of the form vX.Y.Z, recorded in a lock file so that every build fetches the same code.
a program that imports a hako
kanso-json is the decoder chapter 13 reads closely, published on its own as a hako. (the standard library ships the same decoder as std/json; here it stands in for any library you depend on.) this program reads an order and prints it:
import json "kanso-lang/kanso-json"
import "std/os"
os/read_file! "order.json" .> json/decode!
.> (order -> print "{order["tea"]}, {order["grams"]} grams")
{"tea": "sencha", "grams": 3}
an import's last path segment is the qualifier its names are used under, so import "std/os" gives you os/read_file!. the last segment of kanso-lang/kanso-json is kanso-json, and a hyphen cannot appear in a name, so the import gives the module a name of its own: import json "kanso-lang/kanso-json" makes its functions json/decode! and json/encode.
a program that has never been installed cannot build, because nothing has fetched the hako yet. here is the same program in a directory that has not been installed:
error: cannot resolve import "kanso-lang/kanso-json" — a bare path names a hako, and it is not in the cache (run `kanso install`)
installing
kanso install reads the program's imports, finds each hako's highest release tag, fetches it into a local cache, and writes the lock:
installed 1 hako(s):
kanso-lang/kanso-json v0.1.0
kanso-lang/kanso-json v0.1.0 a68bd47d0e8147231b159357736c7f8df95277bf git
the lock has one line per hako: its name, the release tag, the sha git reported for that tag, and the protocol it was fetched with. commit it with the program. anyone who clones the repository and runs kanso install fetches exactly the same code, and a build never chooses a version on its own.
the cache lives in ~/.hako, keyed by name and that sha, and KANSO_HAKO moves it. the compiler itself never touches the network: a build reads the lock and the cache, so once a hako is installed the program builds offline.
sencha, 3 grams
staying current
kanso list prints what the lock pins. when a newer release exists upstream, the line says so.
kanso-lang/kanso-json v0.1.0 a68bd47d0e81 git
kanso update walks each pin forward to the highest release and rewrites the lock. given a hako's name as well, kanso update teaorder kanso-lang/kanso-json, it moves that hako alone. run the tests after an update: the lock changing is the whole of what happened, so a failing test points straight at the dependency.
every hako is already at its highest release
working against a branch
sometimes you need a fix that has not been released yet. kanso install teaorder --from kanso-lang/kanso-json@main pins the hako to the commit that branch points at. the lock records the branch name, kanso list marks the line as an interim pin, and kanso update will not walk it forward, because a branch is not a release. when the fix ships in a tag, delete that hako's line from hako.lock and run kanso install, which takes the newest release.
publishing your own
a hako is a GitHub repository of kanso source. to publish a release, tag a commit and push the tag:
git tag -a v0.1.0 -m "v0.1.0"
git push origin v0.1.0
a tag is permanent history. a lock records what it named, so moving a published tag would change what other people's locks mean; publish a new version instead. only tags of the form vX.Y.Z count as releases, so a prerelease such as v1.0.0-rc1 is never chosen by install or update.
what you can do now
you can depend on a published hako by importing it, give it a qualifier when its name does not make one, install it, and commit the lock that makes every build fetch the same code. you can see what is out of date with kanso list, move forward with kanso update, pin a branch while you wait for a release, and publish a release of your own by pushing a tag.
exercises
- delete
teaorder/hako.lockand runkanso install teaorderagain. compare the new lock with the old one: what decided which release it picked? - point
KANSO_HAKOat an empty directory and runkanso run teaorder. read the error, then install and run again. - change the import to
import "kanso-lang/kanso-json"and runkanso check teaorder. why can't the program reach the module's functions now? - add a second hako to the program, install it, and read the lock again.