 Welcome everyone. My name is Ricardo and I have been working on Geeks for a couple of years already. This is going to be a gentle introduction to functional package management, which means that I'm not going to define what functional package management is. Instead I'm going to start with a bold claim. Package managers are really useful. Who disagrees with this? No package managers are really useful. This is a meme in computing. It's been around for a while and there are different variations of it, but it has survived so far. But they can be so frustrating. Who has never had a problem with packages before? Installing software and... I actually could skip all those slides, but for the benefit of the people who are watching from afar, these are just off the top of my head a couple of issues that I've personally encountered and that probably have shortened my lifetime. The first thing that you will encounter when things go wrong is version conflicts. You may want to have a particular version of the piece of software and it's not available and you can't really just install that version that you want because that would conflict with what is already there. This leads us directly to the other problem, which is that usually old software is available because harmonizing all these dependencies between different packages takes a while and it's non-trivial. So as the dust settles, actually the software world has already moved on. So there are always a few steps behind. Upgrades can be very suspenseful, which is why in the past I would not touch my computer before giving talks or before deadlines. I would actually really just try not to upgrade because I want to use the computer. Because the only way is forward. You can't really go back. Once you commit it to an upgrade, it's really hard to downgrade in traditional systems or those systems that I've encountered anyway. And it gets worse twice as bad when it's not just you using the machine, but if it's a shared machine. You have a computer at home and it's you and your kids using the machine and they upgrade because they have food. They shouldn't. So they upgrade the machine and then you can't submit your paper because you're a serious person who writes papers. And that's bad because as we established already, the only way is forward. You can arrange yourself with it like switch jobs or become an artist. And trust. Trust is an issue. How can we be sure that the software that we install on our machines is actually the software that we want to have installed? This is a really hard problem and a lot of people are working on this. There's a whole community of people who work on reproducible builds that give us the tools to at least challenge trust issues. So we cannot be sure that we can fully trust things, but at least we gain some confidence in that the software we are running is actually the software that corresponds to the sources that we've read. There are a couple of partial solutions or attempts at solving things. These are just a few that I've encountered so far. The first one is obviously just don't use package management. You have a compiler and you know how to use it. If you don't, then that is a problem. It's not a solution for you. It doesn't only extend to the package itself, but it may extend to packages that are different versions recursively. Dependencies for that package are the different version than the one that's provided by public repositories. So you might just rely on other people doing that work for you by using external repositories that provide pre-built binaries. So in enterprise environments, people often use this Apple repository. On Ubuntu, it's popular to install and enable PPAs, where you can just download packages that other people have built. There's a user repository for Arch, GNU, plus Linux. Usually the solution comes with a host of other problems. You may have not the original conflict that you started with, but you may have additional conflicts in trying to harmonize these different repositories, the official one and the external one. There's even more software that you have to trust, where you may not actually have the tools to establish trust. Another common approach to solve the problem is to use application-specific package managers. It seems like every language has its own package manager, and if you have a non-trivial piece of software that is written in Ruby and Haskell, and maybe a sprinkling of Python, then you may have to use gem, cabal, and pip. This is not just one tool you have to learn, like your system package manager, but gem, cabal, and pip. And they all behave slightly differently. They all have their idiosyncrasies. So it's more packages, but less management. Just devolving this to a language level, which is just a little bit better than doing it on a per-package level. You can also build your own system packages. If you're using apps, you could write a devian package, and who does this on a regular basis? Who enjoys doing this? Or you could use RPM. This is kind of hard to do, because again, you've got the same problems as with using no package management at all. You've got to solve all these issues first, but you're rewarded with a binary that eventually breaks as the rest of the system moves on. You've got to rebuild things again. You can also automate that. You can generate RPMs, and you can generate devian packages with things like FPM, but I don't know, maybe it's just me, but I feel this is really inelegant, because it generates so much boilerplate stuff just so that you can install software. It doesn't adhere to any particular standards. It's weird, right? I used it before because I wanted to distribute software to people who may be using devian and people who use RPM-based systems, so I wrote an FPM package and built all these binary archives that people can install. This helps a little bit for lazy distribution of software, but it doesn't really help users themselves. A very popular solution nowadays is to just give up and say packaging is really hard, so let's not do it. Let's just shrink-wrap the whole environment and distribute that binary blob to other people who can then run that thing. Introducing functional packaging. Functional here does not mean it works. It does work, but that's not the meaning of the term here. Functional means just like a function, like a pure mathematical function. So that's like a metaphor. So this is the function here. I see you can actually not read the top. This doesn't matter, right? So you treat the build process as a function that has inputs and produces some output. Inputs for package build process would be the header files, the sources, all the tools that you need to build something, all the libraries that you would need to link the software with, and outcomes, some binary artifact, a tree of files. In this case it's Emacs, which generates a couple of libraries and a couple of binaries that you can run. Now one thing that I would like to stress here is that with functional packaging the target directory includes a hash of all the inputs, which means that if you change one input, and it doesn't matter which one and how far up the graph it goes, you will get a different output directory, which means that installing or building Emacs with this version of GCC is going to yield one output, whereas building Emacs with that other version of GCC will yield a different output. So you can have different variants of a piece of software and it is not just dependent on the version. It's not just, I want to use Emacs 25.1 and I would also like to have Emacs 24 or something. So you can have different variants of Emacs 25.1 if you wanted to. And all of the inputs are encoded in that hash. So it gives us a unique new namespace to which we can install things. So input means you get the same output, ideally, and with different inputs you get different outputs. The way this is done in Geeks is that we've got this Geeks client, a client-level tool that a user, an unprivileged user can run, that Geeks client talks to a demon, runs as root and performs things on behalf of the user. The things it performs is, the abstraction is that it spawns isolated build processes, isolated environments, fashions, isolated environments that give a new view on the system where only declared inputs are available. That means if I were to tell Geeks to build Emacs and I didn't say that I want to have a compiler available, then that build would obviously fail. So I have to say I want to have a compiler and I want to have this and that, and the demon will comply and create an isolated build environment where that compiler that is specified is available. All the libraries that I want to have are available. All the other packages, things depend on, are available. And eventually the build artifacts are in a store. In the store... Everything eventually ends up in the store in its own name space, in its own prefix directory. But these prefix directories, they are really, really long. They are ugly. There is something like slash new, slash store, a really, really long hash minus the package name, the version number. And then you've got slash bin or slash label, whatever. Nobody in their right mind would like to memorize all these hashes so that it can use Emacs. This doesn't happen. So to simplify all of this, there is the notion of profiles. You can't see this up there, but this is my profile. It reads as slash home, username, dot Geeks profile. And this is really just a link. This is a link that points to the current Geeks profile, somewhere in a state directory, which points to the current version of the profile, which again is linked into the store, to the actual profile, which again contains links. It's a union of all the things that should be in my profile. In this case, we've got a profile with an ugly hash in front of it, and it contains two tools, SEMtools and Botite. But these are just links to the actual tools. In the store, we've previously built SEMtools, so my profile just references SEMtools in the store. It also references Botite, which is in a different output directory. So profiles are unions of all those individual trees with their practices stripped, and the current version is really just a link to the current version. So if I were to remove a piece of software, I'm not going to modify anything in there, because the store is immutable. Instead, what I would do is create a new generation of my profile. Now it's generation 43, which points to a new profile, which no longer contains the package that I removed. But if I wanted to, I could just go back, right? I could just change the Geeks profile link to 42 again. Go back, go forth, and back and forth, and back and forth. Nothing ever changes really, so the store only grows. Until I decide to delete that link, the 42 link, which then shows us that the profile itself is no longer referenced by anything, so I can run the garbage collector and collect that unused profile. So before I move on to something funny, I'd like to demonstrate this. Can you see this? Maybe like this. Okay, I'd like to read you, but I can't, because I don't have the hello command. So as an unprivileged user, I install the hello command. It tells me that it will install hello 2.10. I guess it says hello in a fancier fashion, but I don't know. And it installs that somewhere into the store. So there's a slash news, slash store, a long hash that is highlighted here. Hello, something, something. We can take a look at this. Inside of that, there is a bin directory and a shadow directory. This is a real tree, right? What you would normally have at the root. Now, I can greet you. But this is kind of artificial. I never had to install hello before, except for demos like this. So let's install Python. So it tells me that Python will be installed somewhere into the store. And it also tries to be helpful and tell me what I may have to do in order to use it, but I don't because it's... yeah, so here it is. I realize I'm in the guile dev room, so I shouldn't be using Python. So let's remove this and use guile instead. As you can see, this is a transaction. I'm doing this at once, but I'm removing Python and installing guile in the same transaction. And now Python is gone, right? There's guile. Now, this is what happened. When I installed hello for the first time, that created a profile, generation one. When I then installed Python into my profile, it added Python. That means it created a new generation that included Python. The previous generation is still available, right? It's still there. It's unmodified. I could go back to that. Generation three, where I've removed Python and installed guile. So what's currently installed is this, right? Hello in guile. For some reason, I want to go back and undo a mistake, which it was. It was no mistake here, but this is just for demonstration purposes. I'm going to switch back again. You see that generation two is now the current generation. And now if I want to use Python again for whatever reason, it's there again. And guile is gone. I'm not going to show that though. So rollbacks, the feature of having generations and appending only to the store, gives us rollbacks just by changing assembly. That's beautiful. We can also install software into different separate profiles. So we could use one version of Emacs and compare it with another one if you wanted to. Or in a scientific environment, you could install a whole workflow into one profile. And for a different project, you have a different workflow. You can use both of them. So this is beautiful. This is all completely isolated. My changes here will not affect any other user. They won't have to use Python if I made the decision to use Python. If I install it into my profile, it really only affects me. So the way that this works is by using scheme. The geeks is written in guile, which is an implementation of scheme. This may look confusing at first, but let me show you first a couple of things about scheme. So these nail clippings, they are important. Everything is a parenthetical expression. And the first thing in there is special. Everything that follows is just an argument to the first thing. This is a simplification. But in general, this rule applies. Whatever is first is kind of special. It may be a function. It may be a special syntax. In this case, we have a list, an expression, an S expression that has three elements. The first one is the function plus. The other two are arguments to that function. Now what I can do is I can quote expressions. That evaluates to the list that contains three elements. You can think of this as a toggle switch. Right now it points upwards, which means data mode. All of this, what follows is now data. It's not going to be evaluated. But you can flip the switch down and enter code mode where things are evaluated. And now this no longer looks that scary, I think. Maybe that was too optimistic. So we are defining a name. I say that this name GLPK is whatever follows evaluates to. This is a package that has a name, obviously, and it has a version. And it has sources. We don't care so much about this right now. Let's get to the build system. The build system is the GNU build system. Configure, make, install. Oh, there's two back. And here you see the toggle switch, right? So we've got inputs. And that is an actual package. Just like that. Okay, we have time for questions. Can we ask the next people to set up? Yeah, questions. If you want to learn more about GLPK, come to me afterwards. I'm quite familiar with the name. What's the link with the case of 4 or no link? I was waiting for this question. So the question is, what's the difference between Nix and Geeks? Okay. I'm quite aware you have to see what the link is. Both Nix and Geeks are implementations of the same principles, right? Both of them are functional package managers. Nix is older than Geeks. Both Geeks is a different implementation that uses skin throughout, which has wide implications on a lot of things, actually. This would deserve another talk. So there's a lot of differences that come from that initial design decision to use skin. So Geeks uses the Nix demon underneath. And the derivations they use are the same, the same format. So I think in principle they are compatible. But everything above that, everything that's not low level like this is very much different. Okay, do we have time for another one? Sure. We have similar as Nix OS, where you have the integration. Is there something similar like Nix OS? People may not know what Nix OS is. A distribution, a new distribution that builds on Nix. And yeah, for Geeks we have this too. It's running on this machine actually. It's called Geeks SD, and it extends the ideas of Geeks to the operating system level and has declarative configuration of the whole operating system. Also in schemes. Same kind of thing. Is there a way to delete generations on your own out of this space? Is there a way to delete generations? Yes. You delete the link. So there's a command line thing for deleting older, profile generations. And then you're on the garbage collector. Yes. How do you deal with security updates? Security updates are handled by what's called graphs, which is an optimization. But to actually explain how this works in detail, I'd rather not do it right now because they would take a little too long. It's documented, and you can find it in the manual, which is really extensive. Or we can chat later. Yeah, I would like to chat. Okay, cool. That's it. Thank you.