LevitateOS

Documentation

Helpers Overview

Helper functions available in recipe scripts. All helpers are pure functions that take explicit inputs and return explicit outputs.

Section

Introduction

Helper functions are organized by lifecycle phase. All functions are pure - they take explicit paths as input and return paths or results. This makes data flow visible and enables caching.

Command
rhai
let ctx = #{
    name: "foo",
    version: "1.0",
    source_dir: "",
};

fn acquire(ctx) {
    let archive = download(
        "https://example.com/foo-1.0.tar.gz",
        join_path(BUILD_DIR, "foo.tar.gz")
    );
    extract(archive, BUILD_DIR);
    ctx.source_dir = join_path(BUILD_DIR, "foo-1.0");
    ctx
}

fn build(ctx) {
    shell_in(ctx.source_dir, "./configure --prefix=" + PREFIX);
    shell_in(ctx.source_dir, "make -j" + NPROC);
    ctx
}

fn install(ctx) {
    shell("install -Dm755 " + join_path(ctx.source_dir, "foo") + " " + join_path(PREFIX, "bin/foo"));
    ctx
}

Section

Categories

  • Acquire - Download, clone, and verify sources
  • Build - Extract archives
  • Install - Install files to PREFIX
  • Filesystem - File and directory operations
  • Environment - Environment variables
  • Commands - Shell command execution
  • HTTP - HTTP requests and GitHub API
  • Paths - Path manipulation utilities
  • LLM - AI-assisted version/URL extraction

Section

Built-in Variables

These constants are available in all recipe scripts:

Variable Description Example
PREFIX Installation prefix (or $OUT if set) /usr/local
BUILD_DIR Temporary build directory /tmp/recipe-build-xxx
ARCH Target architecture x86_64, aarch64
NPROC Number of CPU cores 8
RPM_PATH RPM repository path (from env) /var/cache/rpms

Section

Pure Function Design

All helpers take explicit inputs and return explicit outputs. For example, download(url, dest) returns the path where the file was saved, and extract(archive, dest) takes that path as input:

Command
rhai
// Explicit data flow - you can see where files come from and go
let archive = download(url, join_path(BUILD_DIR, "foo.tar.gz"));
verify_sha256(archive, "abc123...");
extract(archive, BUILD_DIR);

This pure function design enables the living ctx persistence model - since all data flow is explicit through ctx, the engine can safely persist state to disk after each phase. There's no hidden state that could become stale or inconsistent.

Section

Complete Example

A full recipe demonstrating multiple helper categories:

File ripgrep.rhai
rhai
let ctx = #{
    name: "ripgrep",
    version: "14.1.0",
    repo: "BurntSushi/ripgrep",
    description: "Fast line-oriented search tool",
    extract_dir: "",
};

fn is_acquired(ctx) {
    let dir = join_path(BUILD_DIR, "ripgrep-" + ctx.version + "-" + ARCH + "-unknown-linux-musl");
    if is_file(join_path(dir, "rg")) {
        ctx.extract_dir = dir;
        return ctx;
    }
    throw "not acquired";
}

fn acquire(ctx) {
    mkdir(BUILD_DIR);
    let pattern = "ripgrep-*-" + ARCH + "-unknown-linux-musl.tar.gz";
    let archive = github_download_release(ctx.repo, ctx.version, pattern);
    extract(archive, BUILD_DIR);
    ctx.extract_dir = join_path(BUILD_DIR, "ripgrep-" + ctx.version + "-" + ARCH + "-unknown-linux-musl");
    ctx
}

fn is_installed(ctx) {
    if is_file(join_path(PREFIX, "bin/rg")) {
        return ctx;
    }
    throw "not installed";
}

fn install(ctx) {
    let src = ctx.extract_dir;
    shell("install -Dm755 " + join_path(src, "rg") + " " + join_path(PREFIX, "bin/rg"));
    shell("install -Dm644 " + join_path(src, "doc/rg.1") + " " + join_path(PREFIX, "share/man/man1/rg.1"));

    if dir_exists(join_path(src, "complete")) {
        shell("install -Dm644 " + join_path(src, "complete/_rg") + " " + join_path(PREFIX, "share/zsh/site-functions/_rg"));
    }
    ctx
}

fn check_update() {
    let latest = github_latest_release(ctx.repo);
    if latest != ctx.version { latest } else { () }
}