Raku Modules in Gentoo Portage

Raku Gentoo — Published on .

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.

There is a CompUnit::Repository::FileSystem which would allow me to just copy over files to the right directory, however, I quite like the ability to have multiple versions of the same module installed. This is actually something Portage is designed with, too!

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,
) {
		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.