summaryrefslogtreecommitdiff
path: root/src/_posts/2020-12-14-raku-modules-in-gentoo-portage.md
blob: 2d268d1b12d14c01fb186c9aec75948930e4e03d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
---
layout: post
tags: Raku Gentoo
social:
  email: mailto:~tyil/public-inbox@lists.sr.ht&subject=Raku modules in Gentoo's Portage
description: >
  Updates are important. This article aims to help you to learn from my
  mistakes, so your updates will go smooth.
---

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.

{% admonition_md note %}
There *is* a
[CompUnit::Repository::FileSystem](https://docs.raku.org/type/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!
{% endadmonition_md %}

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`](https://git.sr.ht/~tyil/raku-overlay/tree/7494c81524ec1845c77dabfbb3303a34eb4b89f4/item/dev-lang/raku/files/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`](https://github.com/ugexe/zef/)) for the user.

{% highlight raku %}
#| 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);
}
{% endhighlight %}

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.

{% highlight sh %}
rm -- "${D}/usr/share/perl6/site/version"
rm -- "${D}/usr/share/perl6/site/repo.lock"
rm -- "${D}/usr/share/perl6/site/precomp/.lock"
{% endhighlight %}

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](https://git.sr.ht/~tyil/raku-overlay). 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.