Rakudo

NAME

App::Ariza::Rakudo - fetch, cache and unpack the Rakudo runtime a bundle embeds

SYNOPSIS


use App::Ariza::Rakudo;
use App::Ariza::Versions;

my %rt = App::Ariza::Rakudo.provision(
    :bundle-dir($work),
    :slug<macos-arm64>,
    :versions(App::Ariza::Versions.load),
);

say %rt<root>;      # …/moneymoor-0.2.0-macos-arm64/rakudo
say %rt<raku>;      # …/rakudo/bin/raku
say %rt<zef>;       # …/rakudo/share/perl6/site/bin/zef
say %rt<tag>;       # 2026.07-01
say %rt<sha256>;    # 9f3c…
say %rt<cached>;    # True on the second build

# The pieces, separately:
my @entries = App::Ariza::Rakudo.fetch-index;
my %entry   = App::Ariza::Rakudo.select-entry(@entries,
                  :slug<linux-x86_64-glibc>, :version<2026.07>, :revision<01>);
say %entry<url>;

DESCRIPTION

A bundle carries its own interpreter, so nothing about the user's machine — whether Raku is installed, which version, which module repositories are in the chain — can affect it. This module puts that interpreter in the bundle.

The runtime is not built: it is the official archive from rakudo.org, pinned in App::Ariza::Versions by [rakudo] version and revision, downloaded once and cached for every subsequent build.

The release index

https://rakudo.org/dl/rakudo serves a JSON array, one object per downloadable file, covering every release since 2009. The fields that matter are platform (macos, linux, win, src), arch, ver, build_rev, type (only archive is a runtime; the rest are signatures and checksum files) and url.

Matching is exact on all five. A pin of 2026.07 / 01 selects build_rev 1 and nothing else — never "the newest 2026.07", never "whatever is latest" — because the whole point of the pin is that two builds a month apart embed the same bytes.

Which platforms can be bundled

rakudo.org publishes binaries for four of the eight slugs App::Ariza::Platform knows:

  • macos-arm64, macos-x86_64

  • linux-x86_64-glibc

  • windows-x86_64

The others — musl, Linux aarch64, Windows on ARM — are real platforms with no upstream archive to embed. Asking for one dies naming the four that work, rather than assembling a URL that will 404. Making one of them bundleable means building a runtime and publishing it somewhere this map can point at; it is not a code change here.

Caching: record, then verify

Archives land in $XDG_CACHE_HOME/ariza/rakudo (~/.cache/… when that is unset), each beside a .sha256 sidecar written at download time.

There is no upstream checksum to compare against — rakudo.org publishes one, but fetching it only moves the trust boundary — so the digest is recorded on first download and verified on every reuse. That catches exactly the failure this cache can actually suffer: a file that changed after it was written, because a process was killed mid-transfer or a disk lied. A mismatch is not fatal; the cached copy is discarded, noted on STDERR, and re-downloaded.

Downloads themselves land in a .part file and are renamed on success (see App::Ariza::Tools), so an interrupted transfer is never mistaken for a cache hit. An archive that is present but has no sidecar — dropped in by hand, or left by a much older run — is adopted: its digest is recorded now and verified from then on.

METHODS

provision(:$bundle-dir!, :$slug!, :$versions!, :$cache-dir, :$url, :&fetch, :&download --> Hash)

The whole job: resolve the pin against the index, fetch or reuse the archive, unpack it to < <bundle-dir>/rakudo > (stripping the wrapper directory), and verify that the two entry points later stages need actually exist.

Returns root, raku, zef, archive, sha256, cached, url, version, revision and tag.

fetch-index(:$url, :&fetch --> List)

The index, parsed. An unreachable host dies saying so explicitly — "a bundle needs network access the first time it is built" — rather than as a JSON parse error on an empty body.

select-entry(@entries, :$slug!, :$version!, :$revision! --> Hash)

The one matching archive entry. No match dies listing the most recent versions the index does have for that platform, so a stale pin is obvious. Two matches also dies: upstream publishing two archives for one platform, version and revision (a second toolchain, say) is a choice that belongs in the pin file, not in a tiebreak here.

fetch-archive(%entry, :$cache-dir, :&download --> Hash)

Download or reuse. Returns archive, sha256 and cached.

unpack(IO() $archive, IO() $bundle-dir --> IO::Path)

Extract into < <bundle-dir>/rakudo >, stripping the single top-level directory the archive wraps everything in. Any existing rakudo/ is replaced, so a rebuild into the same workdir is clean.

raku-bin(IO() $root, :$slug --> IO::Path) / zef-bin(IO() $root, :$slug --> IO::Path)

The interpreter and the zef entry point inside an unpacked runtime (raku.exe on Windows).

On POSIX, zef-bin is a shell wrapper, not a Raku script — it finds its sibling raku relocatably and execs it. Run it directly. Passing it to bin/raku as a script is a syntax error, because it is sh.

The official Windows zip ships no zef.bat, so on Windows zef-bin returns zef.raku instead — the .raku stub every zef install ships (sub MAIN(*@, *%) { CompUnit::RepositoryRegistry.run-script("zef") }), byte-identical across platforms. It has to be run under the bundled raku, not exec'd; App::Ariza::Site is where that invocation is built. The zip also ships a compiled zef.exe, but a compiled wrapper's raku-discovery behaviour inside a relocated bundle is unverified, while the run-script stub depends on nothing but the raku it is handed.

cache-dir(--> IO::Path) / fetchable-slugs(--> List) / index-platform(Str --> Hash)

The cache root, the bundleable slugs, and a slug's index coordinates.

SEE ALSO

App::Ariza::Versions for the pin, App::Ariza::Site for what is installed into the runtime once it is unpacked.

AUTHOR

Matt Doughty

COPYRIGHT AND LICENSE

Copyright 2026 Matt Doughty

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

App::Ariza v0.2.4

bundler and distribution tool for Raku terminal apps

Authors

  • Matt Doughty

License

Artistic-2.0

Dependencies

Config::TOML:ver<0.1.3+>:auth<zef:raku-community-modules>JSON::Fast:ver<0.19+>:auth<cpan:TIMOTIMO>Template::Jinja2:ver<0.3.0+>:auth<zef:apogee>

Test Dependencies

Provides

  • App::Ariza
  • App::Ariza::Bundle
  • App::Ariza::CI
  • App::Ariza::Config
  • App::Ariza::Installer
  • App::Ariza::Launcher
  • App::Ariza::Licensing
  • App::Ariza::Native
  • App::Ariza::Platform
  • App::Ariza::Rakudo
  • App::Ariza::Resources
  • App::Ariza::Runner
  • App::Ariza::Site
  • App::Ariza::Smoke
  • App::Ariza::Tools
  • App::Ariza::Update
  • App::Ariza::Versions

The Camelia image is copyright 2009 by Larry Wall. "Raku" is a trademark of the Yet Another Society. All rights reserved.

Built with Podlite — the markup and publishing tools behind this site.