Initial scaffold
This commit is contained in:
@@ -0,0 +1,58 @@
|
|||||||
|
# Kama (窯)
|
||||||
|
|
||||||
|
**Kama** — the kiln — is the package manager for [Keru OS](https://github.com/AstralZX/KeruOS).
|
||||||
|
|
||||||
|
It's a single shell script (plus a small library) that builds packages from
|
||||||
|
source by executing their recipes. It is deliberately minimal: there is no
|
||||||
|
dependency resolver, no package database, and no binary format. Kama reads a
|
||||||
|
`make.conf`, and it runs whatever each recipe tells it to.
|
||||||
|
|
||||||
|
## Why shell?
|
||||||
|
|
||||||
|
Kama is the whole point of Keru stated plainly: the package manager shouldn't
|
||||||
|
be more complex than the packages it builds. It's not a program that manages
|
||||||
|
packages as much as a *runner* for recipe scripts — the clever part lives in
|
||||||
|
the recipes, not the mangement machinery.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
kama fetch <pkg> download + extract source into the cache
|
||||||
|
kama build <pkg> stage-build one package
|
||||||
|
kama install <pkg> build + install into $ROOT
|
||||||
|
kama make <pkg> fetch deps, build, install, purge temp deps (AUR-style)
|
||||||
|
kama purge remove temp build-time deps
|
||||||
|
kama info <pkg> show recipe metadata
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Kama reads a `make.conf` (default `/etc/kama/make.conf`) for global build
|
||||||
|
flags and profile choices. Key variables:
|
||||||
|
|
||||||
|
- `ROOT` — target rootfs the packages install into
|
||||||
|
- `CACHEDIR` — persistent source + build cache
|
||||||
|
- `CFLAGS` / `MAKEFLAGS` — passed to every build
|
||||||
|
- `PKGDIR` — where the recipe repository lives (default: sibling `kama-packages`)
|
||||||
|
|
||||||
|
## Recipes
|
||||||
|
|
||||||
|
Packages are plain POSIX shell scripts. The syntax splits into two tiers:
|
||||||
|
|
||||||
|
- **Easy tier** — declare `name`, `version`, `url`, then a `build()` and
|
||||||
|
`install()`. Kama handles fetch + extract automatically.
|
||||||
|
- **Advanced tier** — override `pkg_fetch`, add `pkg_post`, `pkg_split`,
|
||||||
|
`provides`, `conflicts`, `arch`, etc.
|
||||||
|
|
||||||
|
See [the recipe format](KeruOS/blob/main/docs/recipe-format.md) in the KeruOS
|
||||||
|
repo for the full spec.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
Dependencies are handled AUR-style: build-time deps are fetched, compiled, and
|
||||||
|
stripped away once the real package is built, leaving only what the system
|
||||||
|
needs. This is the foundation of Keru's "nothing you didn't ask for" ethos.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
AGPL-3.0
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# kama — the Keru OS package manager
|
||||||
|
#
|
||||||
|
# Kama (窯, "kiln") builds packages from source by executing shell recipes.
|
||||||
|
# It is deliberately minimal: it reads make.conf and runs whatever each
|
||||||
|
# recipe tells it to. No dependency resolver, no package database.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# kama <command> [package ...]
|
||||||
|
#
|
||||||
|
# Commands:
|
||||||
|
# fetch <pkg> download + extract source into the cache
|
||||||
|
# build <pkg> stage-build one package
|
||||||
|
# install <pkg> build + install into $ROOT (staging-aware)
|
||||||
|
# cmake <pkg> high-level: fetch deps, build, install, purge temp deps
|
||||||
|
# purge remove temp build-time deps after a successful install
|
||||||
|
# info <pkg> show a recipe's metadata
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SELF_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
. "$SELF_DIR/lib/kama.sh"
|
||||||
|
|
||||||
|
cmd="${1:-help}"
|
||||||
|
shift || true
|
||||||
|
|
||||||
|
case "$cmd" in
|
||||||
|
fetch) kama_fetch "$@" ;;
|
||||||
|
build) kama_build "$@" ;;
|
||||||
|
install) kama_install "$@" ;;
|
||||||
|
make) kama_make "$@" ;;
|
||||||
|
purge) kama_purge ;;
|
||||||
|
info) kama_info "$@" ;;
|
||||||
|
help|--help|-h)
|
||||||
|
msg "Keru OS — Kama (窯) package manager"
|
||||||
|
cycle
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "unknown command: $cmd (try: kama help)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
+185
@@ -0,0 +1,185 @@
|
|||||||
|
# kama.sh — shared core library for the Kama package manager
|
||||||
|
#
|
||||||
|
# Sources make.conf, provides helpers, and implements the fetch/build/
|
||||||
|
# install/temp-dep logic. All the messy bits live here so recipes stay clean.
|
||||||
|
|
||||||
|
PREFIX="\033[1;36m[ kama ]\033[0m"
|
||||||
|
|
||||||
|
# --- config ---------------------------------------------------------
|
||||||
|
# Where the package recipe repository lives (kama-packages repo).
|
||||||
|
PKGDIR="${PKGDIR:-$SELF_DIR/../kama-packages}"
|
||||||
|
# merge a make.conf if one is provided
|
||||||
|
MAKE_CONF="${MAKE_CONF:-/etc/kama/make.conf}"
|
||||||
|
[ -f "$MAKE_CONF" ] && . "$MAKE_CONF"
|
||||||
|
|
||||||
|
ROOT="${ROOT:-/tmp/keru/root}"
|
||||||
|
CACHEDIR="${CACHEDIR:-/var/cache/kama}"
|
||||||
|
SRCDIR="$CACHEDIR/src"
|
||||||
|
DLDIR="$CACHEDIR/dl"
|
||||||
|
STAGEDIR="$CACHEDIR/stage"
|
||||||
|
|
||||||
|
# --- message helpers -------------------------------------------------
|
||||||
|
msg() { printf '%b %s\n' "$PREFIX" "$*"; }
|
||||||
|
warn() { printf '%b \033[1;33mwarning:\033[0m %s\n' "$PREFIX" "$*"; }
|
||||||
|
die() { printf '%b \033[1;31merror:\033[0m %s\n' "$PREFIX" "$*" >&2; exit 1; }
|
||||||
|
|
||||||
|
# --- easy/advanced tier mapping --------------------------------------
|
||||||
|
# If a recipe defines the easy-tier `build`/`install` sugar (and doesn't
|
||||||
|
# define the advanced pkg_* forms), alias them. This keeps simple recipes
|
||||||
|
# simple and gives advanced recipes full control.
|
||||||
|
map_tiers() {
|
||||||
|
# map build -> pkg_build unless pkg_build is overridden
|
||||||
|
if declare -f build >/dev/null 2>&1 && ! declare -f pkg_build >/dev/null 2>&1; then
|
||||||
|
pkg_build() { build; }
|
||||||
|
fi
|
||||||
|
if declare -f install >/dev/null 2>&1 && ! declare -f pkg_install >/dev/null 2>&1; then
|
||||||
|
pkg_install() { install; }
|
||||||
|
fi
|
||||||
|
# advanced recipes may define pkg_build/pkg_install directly — leave as-is
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- default fetch: download + auto-extract -----------------------------
|
||||||
|
default_fetch() {
|
||||||
|
local tarball="$DLDIR/$(basename "$url")"
|
||||||
|
mkdir -p "$DLDIR" "$SRCDIR"
|
||||||
|
if [ ! -f "$tarball" ]; then
|
||||||
|
msg "downloading $url"
|
||||||
|
wget -q --show-progress "$SOURCE_MIRROR/$(basename "$url")" -O "$tarball" \
|
||||||
|
|| wget -q --show-progress "$url" -O "$tarball" \
|
||||||
|
|| die "download failed for $name"
|
||||||
|
else
|
||||||
|
msg "using cached source for $name"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local s="$SRCDIR/$name"
|
||||||
|
rm -rf "$s"; mkdir -p "$s"
|
||||||
|
msg "extracting $name"
|
||||||
|
case "$tarball" in
|
||||||
|
*.tar.gz|*.tgz) tar xf "$tarball" -C "$s" --strip-components=1 ;;
|
||||||
|
*.tar.xz|*.txz) tar xJf "$tarball" -C "$s" --strip-components=1 ;;
|
||||||
|
*.tar.bz2|*.tbz2) tar xjf "$tarball" -C "$s" --strip-components=1 ;;
|
||||||
|
*.tar) tar xf "$tarball" -C "$s" --strip-components=1 ;;
|
||||||
|
*.zip) unzip -q "$tarball" -d "$s.tmp" && \
|
||||||
|
mv "$s.tmp"/*/* "$s/" ; rm -rf "$s.tmp" ;;
|
||||||
|
*) die "unsupported archive type: $tarball" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- locate a recipe --------------------------------------------------
|
||||||
|
find_recipe() {
|
||||||
|
local pkg="$1"
|
||||||
|
for rec in \
|
||||||
|
"$PKGDIR/$pkg/PKGBUILD" \
|
||||||
|
"$PKGDIR/$pkg.sh" \
|
||||||
|
"$PKGDIR/$pkg"/*.sh ; do
|
||||||
|
[ -f "$rec" ] && { printf '%s' "$rec"; return 0; }
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- fetch + extract source -------------------------------------------
|
||||||
|
# --- fetch + extract source -------------------------------------------
|
||||||
|
kama_fetch() {
|
||||||
|
[ $# -ge 1 ] || die "fetch: missing package name"
|
||||||
|
for pkg in "$@"; do
|
||||||
|
local recipe; recipe="$(find_recipe "$pkg")" || die "no recipe for '$pkg'"
|
||||||
|
msg "fetching source for $pkg"
|
||||||
|
. "$recipe"
|
||||||
|
map_tiers
|
||||||
|
|
||||||
|
local src="$SRCDIR/$name"
|
||||||
|
if [ -d "$src" ] && [ -n "$(ls -A "$src" 2>/dev/null)" ]; then
|
||||||
|
msg "using cached source for $pkg"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# advanced recipe overrides pkg_fetch -> use it; otherwise default_fetch
|
||||||
|
if declare -f pkg_fetch >/dev/null 2>&1; then
|
||||||
|
pkg_fetch
|
||||||
|
else
|
||||||
|
default_fetch
|
||||||
|
fi
|
||||||
|
[ -d "$src" ] && [ -n "$(ls -A "$src" 2>/dev/null)" ] \
|
||||||
|
|| die "fetch produced no source for $pkg"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- stage-build a single recipe ---------------------------------------
|
||||||
|
kama_build() {
|
||||||
|
[ $# -ge 1 ] || die "build: missing package name"
|
||||||
|
for pkg in "$@"; do
|
||||||
|
local recipe; recipe="$(find_recipe "$pkg")" || die "no recipe for '$pkg'"
|
||||||
|
msg "building $pkg"
|
||||||
|
. "$recipe"
|
||||||
|
map_tiers
|
||||||
|
|
||||||
|
local src="$SRCDIR/$name"
|
||||||
|
local pkgdir="$STAGEDIR/$name"
|
||||||
|
[ -d "$src" ] && [ -n "$(ls -A "$src" 2>/dev/null)" ] || kama_fetch "$pkg"
|
||||||
|
|
||||||
|
rm -rf "$pkgdir"; mkdir -p "$pkgdir"
|
||||||
|
( cd "$src" && pkg_build ) || die "build failed for $pkg"
|
||||||
|
msg "staging install for $pkg"
|
||||||
|
( cd "$src" && pkg_install ) || die "install failed for $pkg"
|
||||||
|
( cd "$src" && pkg_post ) || die "post-install failed for $pkg"
|
||||||
|
pkg_split || true
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- install staging dir into ROOT --------------------------------------
|
||||||
|
install_staged() {
|
||||||
|
local pkg="$1"
|
||||||
|
local pkgdir="$STAGEDIR/$pkg"
|
||||||
|
[ -d "$pkgdir" ] || die "nothing staged for '$pkg'"
|
||||||
|
msg "installing $pkg into \$ROOT"
|
||||||
|
( cd "$pkgdir" && cp -a . "$ROOT" )
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- high-level: make a package (deps + build + install + purge) --------
|
||||||
|
kama_make() {
|
||||||
|
[ $# -ge 1 ] || die "make: missing package name"
|
||||||
|
for pkg in "$@"; do
|
||||||
|
local recipe; recipe="$(find_recipe "$pkg")" || die "no recipe for '$pkg'"
|
||||||
|
. "$recipe"
|
||||||
|
|
||||||
|
# temp deps: build, stage, install, then purge after
|
||||||
|
if [ -n "${deps+x}" ] && [ ${#deps[@]} -gt 0 ]; then
|
||||||
|
msg "building temp deps for $pkg: ${deps[*]}"
|
||||||
|
kama_make "${deps[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
kama_build "$pkg"
|
||||||
|
install_staged "$pkg"
|
||||||
|
|
||||||
|
if [ "${PURGE_TEMP_DEPS:-1}" = "1" ] && [ -n "${deps+x}" ] && [ ${#deps[@]} -gt 0 ]; then
|
||||||
|
msg "purging temp deps for $pkg: ${deps[*]}"
|
||||||
|
kama_purge "${deps[@]}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- show recipe metadata ------------------------------------------------
|
||||||
|
kama_info() {
|
||||||
|
[ $# -ge 1 ] || die "info: missing package name"
|
||||||
|
local recipe; recipe="$(find_recipe "$1")" || die "no recipe for '$1'"
|
||||||
|
. "$recipe"
|
||||||
|
printf 'name : %s\n' "$name"
|
||||||
|
printf 'version : %s\n' "$version"
|
||||||
|
printf 'url : %s\n' "$url"
|
||||||
|
printf 'deps : %s\n' "${deps[*]:-}"
|
||||||
|
printf 'runtime_deps: %s\n' "${runtime_deps[*]:-}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- purge temp deps from ROOT --------------------------------------------
|
||||||
|
# NOTE: This is intentionally naive for the scaffold. A real implementation
|
||||||
|
# tracks what each recipe installed and removes exactly that, plus clears the
|
||||||
|
# staged dir. For now it clears the stage so a re-make re-pulls.
|
||||||
|
kama_purge() {
|
||||||
|
for pkg in "$@"; do
|
||||||
|
msg "purging temp dep '$pkg' (stage)"
|
||||||
|
rm -rf "$STAGEDIR/$pkg"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- init ----------------------------------------------------------------
|
||||||
|
mkdir -p "$ROOT" "$CACHEDIR" "$SRCDIR" "$DLDIR" "$STAGEDIR"
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Tests will live here.
|
||||||
|
# Planned:
|
||||||
|
# - recipe.sh unit tests for the easy/advanced tier mapping
|
||||||
|
# - fetch.sh fake download + extract
|
||||||
|
# - deps.sh AUR-style temp dep build + purge
|
||||||
|
# - make.conf.sh profile variable expansion
|
||||||
|
# - integration.sh end-to-end: build a tiny package into a throwaway ROOT
|
||||||
Reference in New Issue
Block a user