Raku Modules in Gentoo Portage
The last couple of days I’ve been taking another look at getting modules for the Raku programming language into Gentoo’s Portage tree. Making new packages available in Gentoo is incredibly easy with their overlay system.
The more complex part was Raku’s side of things. While most languages just have
a certain directory to drop files in, Raku should use a
CompUnit::Repository
object, which exposes the .install
method. This is
obviously slower than just copying the files around, but there are merits to
this method. For one, it allows installation of the same module with different
versions, or from different authors. It also handles all the Unicode complexity
for you.
After an email to the Raku users mailing list, I got some pointers over IRC. I let these sink in for a couple days, considering how to approach the problem properly. Then, one night, a solution came to mind, and I set out to test it.
It actually worked. And a similar method should be usable for other distributions too, such as Debian, OpenSUSE or Archlinux, to create packages out of Raku modules. This should greatly improve the ability to ship Raku programs to end-users, without requiring them to learn how Raku’s ecosystem is modeled, or which module manager it uses.
The most important part of this approach is the
module-installer.raku
program, which is part of dev-lang/raku::raku-overlay
. It accepts a path to
the module to install. It does not depend on any one module manager, so it can
be used to bootstrap a user-friendly module manager (such as
zef
) for the user.
#| Install a Raku module.
sub MAIN (
#| The path to the Raku module sources.
IO() $path,
#| The repository to install it in. Options are "site" (ment for
#| user-installed modules), "vendor" (ment for distributions that want
#| to include more modules) and "core" (ment for modules distributed
#| along with Raku itself).
Str:D :$repo = 'site',
#| Force installation of the module.
Bool:D :$force = True,
) {
CATCH {
default { $_.say; exit 1; }
}
die "This script should be used by Portage only!" unless %*ENV<D>;
my $prefix = %*ENV<D>.IO.add('usr/share/perl6').add($repo);
my $repository = CompUnit::Repository::Installation.new(:$prefix);
my $meta-file = $path.add('META6.json');
my $dist = Distribution::Path.new($path, :$meta-file);
$repository.install($dist, :$force);
}
It’s a fairly straightforward program. It checks for $D
to be set in the
environment, which is a variable Portage sets as the destination directory to
install new files in. This directory gets merged into the root filesystem to
finalize installation of any package.
If $D
is set, I append the path used by Raku in Gentoo to it, followed by a
repo name. Next I create a CompUnit::Repository
using this path. This is a
trick to get the files to appear in the right directory for Portage, to
eventually merge them in the system-wide site
module repo used by Raku.
Additionally, I can use the CompUnit::Repository
’s install
method to handle
all the Raku specific parts that I don’t want to handle myself.
This leaves one last issue. By creating this new repo, I also get a couple
files that already exist in the system wide site
repo. Portage will complain
about possible file collisions and refuse to install the package if these
remain. However, this can be solved rather easily by calling rm
on these files.
rm -- "${D}/usr/share/perl6/site/version"
rm -- "${D}/usr/share/perl6/site/repo.lock"
rm -- "${D}/usr/share/perl6/site/precomp/.lock"
And with this, my test module, IO::Path::XDG
, installs cleanly through the
power of Portage, and is usable by all users using the system-wide Raku
installation.
To make this work for other distributions, the module-installer.raku
program
should be modified slightly. Most notably, the $prefix
must be altered to
point towards the right directory, so the files will be installed into whatever
directory will end up being packaged. Other than that, the standard means of
packaging can be followed.
For the Gentoo users, this overlay is available at
SourceHut. It currently holds only
IO::Path::XDG
(dev-raku/io-path-xdg
), but you are invited to try it out and
report any issues you may encounter.