Metadata-Version: 2.4
Name: egatrop
Version: 0.0.1
Summary: Utilities for carving out root filesystems/filesystem layers from Gentoo Linux systems
Project-URL: Documentation, https://git.sr.ht/~nullenenenen/egatrop/tree/master/item/README.md
Project-URL: Repository, https://git.sr.ht/~nullenenenen/egatrop
Project-URL: Changelog, https://git.sr.ht/~nullenenenen/egatrop/tree/master/item/CHANGELOG.md
License-Expression: MPL-2.0
License-File: LICENSE
Keywords: Gentoo,Portage
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Software Distribution
Classifier: Topic :: Utilities
Requires-Python: >=3.13
Requires-Dist: pkgcore~=0.12.33
Description-Content-Type: text/markdown

# Egatrop

## Installing

Ideally, through use of `uv`, it's a matter of running `uv tool install egatrop`.

## What is it

Utilities for running the [Gentoo Portage](https://gentoo.org/) system, in a sense, "in reverse".
It's something like Nix's [`nix-copy-closure`](https://nix.dev/manual/nix/2.24/command-ref/nix-copy-closure) but for Gentoo.

That is, given an existing Gentoo system, create the dependency tree *as it is for that particular system* for some package or set of packages. Then it can either show you that dependency tree, or export the files installed by those packages to somewhere (some new root filesystem, for instance).

You can use the resulting filesystem tree as a container layer, or for making an initrd, or a rescue disk, or ...

## What good does that do

Suppose you'd want to setup some minimal container root filesystem, with only `postgresql-18`, `bash` and `busybox` installed. And you want to have it be based on Gentoo, with its excellent customization system — say in this instance you want to leave out PostgreSQL's [JIT](https://www.postgresql.org/docs/18/jit-reason.html) so as not to end up shipping `llvm` in your container filesystem, and perhaps you're applying some custom patches on top of it. 

Debian-based distros have `debootstrap`. Arch Linux has `pacstrap`. Gentoo has nothing like that, because there is no canonical setup; customizability is the whole point of Gentoo, so we'll first have to create a Gentoo system that contains PostgreSQL and other things we need, cooked to perfection.

Creating that Gentoo system is not the issue. Create a chroot, do the usual. Let's consider that done. But we don't want to ship that whole system, as it contains way way more than the minimally needed — it'll contain the Gentoo build system itself (including a whole compiler toolchain), some version of Python used for running `emerge`, it'll contain all the package definitions, etc. etc. None of that stuff is needed for running PostgreSQL. In our container we don't want the Gentoo base system, or any build-time dependency. We want something akin to Nix's [`nix-copy-closure`](https://nix.dev/manual/nix/2.24/command-ref/nix-copy-closure), but for Gentoo.

`quickpkg` can't do that, because it doesn't follow dependencies.

Using `emerge --emptytree --buildpkg` and then extracting from the resultant packages won't achieve the goal either, as it will pull in the whole build chain and Gentoo system.

But with the `egreme` utility in this package, we can pull it off!


## Dive right in

If you want to dive right in, just run `egreme --help` and take it from there. But a bit of reading on might save befuddlement later.

## Example usages

### Using the graph: A look at the dependency tree

Here's the dependency tree of the package set `app-shells/bash` + `sys-apps/coreutils` of some minimized Gentoo installation.

We specify the `graph` subcommand, as we just want to see the dependency graph for now.

We specify `app-shells/bash` and `sys-apps/coreutils` as positional arguments. They get resolved to the concrete versions as installed on that system. We could have passed those concrete specifications instead if we'd preferred.

As we're not operating on our root Gentoo system, but rather on a mimimized system created in a chroot, we have to specify where to find the package database for that chroot using `--dbpath`.

```
$ egreme graph app-shells/bash sys-apps/coreutils --dbpath /var/lib/machines/my-gentoo-chroot/var/db/pkg
=app-shells/bash-5.3_p9-r1:0
    =sys-libs/ncurses-6.5_p20250802:0/6
        =sys-libs/glibc-2.42-r5:2.2
            =net-dns/libidn2-2.3.8:0/2
                =dev-libs/libunistring-1.3:0/5
    =virtual/libintl-0-r2:0
    =sys-libs/readline-8.3_p3:0/8
=sys-apps/coreutils-9.9-r12:0
    =sys-apps/acl-2.3.2-r3:0
        =sys-apps/attr-2.5.2-r1:0
    =dev-libs/openssl-3.5.5-r2:0/3
```

One thing to note is that the dependency tree is not exhaustive: in this example, on this system, both `bash` and `coreutils` depend on `ncurses`, but with the above incantation `ncurses` is not repeated under `coreutils`. To see a dependency tree expanded like that, with full attribution, there are other tools (eg `emerge --tree --pretend`). Here we do incremental dependency attribution only.


### Exporting the closure

We were promised something akin to Nix's [`nix-copy-closure`](https://nix.dev/manual/nix/2.24/command-ref/nix-copy-closure), but for Gentoo. So how do we copy out the dependency tree? As follows, with the `clone` subcommand:

```
$ mkdir /dev/shm/outfs
$ egreme.py clone app-shells/bash --infs /var/lib/machines/my-gentoo-chroot --dbpath /var/lib/machines/my-gentoo-chroot/var/db/pkg --outfs /dev/shm/outfs
Cloning =app-shells/bash-5.3_p9-r1:0
Cloning =sys-libs/ncurses-6.5_p20250802:0/6
Cloning =sys-libs/glibc-2.42-r5:2.2
Cloning =net-dns/libidn2-2.3.8:0/2
Cloning =dev-libs/libunistring-1.3:0/5
Cloning =virtual/libintl-0-r2:0
Cloning =sys-libs/readline-8.3_p3:0/8
```

The directory `/dev/shm/outfs` now contains the bare minimum for running bash. Obviously this can be a varying amount of software, depending on the choices made when setting up the mother filesystem (at `/var/lib/machines/my-gentoo-chroot`).

Look into `egreme --help` to see some options one might want to use for the `clone` operation.

### Working with "cuts"

Let's look at a deptree for just `dev-db/postgresql:18` on some system, of which the first part happens to look like this:

```
$ egreme graph dev-db/postgresql:18
=dev-db/postgresql-18.3:18
    =app-eselect/eselect-postgresql-2.4-r1:0
        =app-admin/eselect-1.4.31:0
            =sys-apps/coreutils-9.9-r12:0
                =sys-apps/acl-2.3.2-r3:0
                    =sys-apps/attr-2.5.2-r1:0
                        =sys-libs/glibc-2.42-r5:2.2
                            =net-dns/libidn2-2.3.8:0/2
                                =dev-libs/libunistring-1.3:0/5
(following 73 lines omitted for brevity)
```

While Gentoo has `app-eselect/eselect-postgresql` as a runtime dependency of PostgreSQL, seasoned users may know that actually, that's just a utility for setting some symlinks. In some cases one might not need it, but it does come with a bit of baggage here. Can we leave it out? Yes. For that we can supply a "cut" positional argument to specify that we don't want that package (nor any of its exclusive dependencies). The incantation will become some variant of:

```
egreme graph dev-db/postgresql:18 --cut app-eselect/eselect-postgresql
```

Specify as many cuts as you wish as positional arguments.

### Working with "furcations"

Sometimes, a dependency can be fulfilled in several ways. Suppose we want to create a container that runs `net-misc/mosh`. Mosh requires an `ssh`, but that requirement can be fulfilled with either `net-misc/openssh` or `net-misc/dropbear`. Installation of either of those fullfills the `virtual/ssh` package on which `net-misc/mosh` concretely depends. Here's an (abbreviated) depgraph, for `net-misc/mosh`, of a system that has it plus the two SSH implementations installed:

```
$ egreme graph net-misc/mosh
=net-misc/mosh-1.4.0-r1:0
    [...]
    =virtual/ssh-0-r2:0
        AtomFurcation@299628531972363860: net-misc/dropbear | virtual/openssh
            =net-misc/dropbear-2025.89:0
                [...]
            =virtual/openssh-0-r1:0
                =net-misc/openssh-10.2_p1:0
                    [...]
```

The deptree includes both paths. Isn't that a problem? Yes, as we'll find out when we ask to export the packages:

```
$ egreme clone net-misc/mosh --outfs /dev/shm/my-container-layer
Furcation 299628531972363860: via =net-misc/mosh-1.4.0-r1:0
	furcates: False	deps: 66	pkg: =net-misc/dropbear-2025.89:0
	furcates: False	deps: 65	pkg: =virtual/openssh-0-r1:0

Unresolved furcations present. Please supply furcdirs.
```

Egreme will exit nonzero and tells you to direct which way you want to go at this fork (furcation) in the road.

The output lists furcations, with a stable unique ID for each, together with some info about whether a specific path furcates further onward, and the total dependencies for each path.
Of course, for choosing which path to take it's important to look at each dependency tree by itself to judge which one has the smallest installed size, if that is the criterion. Here openssh may have 1 fewer dependency, yet perhaps the dependencies are much larger than dropbear's. The dependency count is thus just an indication.

Expliciting the choice is easy. Here we'll go with dropbear, and use the furcation ID from the above output together with that choice as a positional argument after `--furcdirs`. This works for all subcommands (be it `clone`, `graph`, or `furcations`).

We can check whether we resolved all furcations by trying to list any remaining using the `furcations` command:

```
$ egreme furcations net-misc/mosh --furcdirs 299628531972363860:net-misc/dropbear
```

No output — no news is good news, we've resolved all furcations and should be able to use the `clone` command now (supplying this furcation directive, of course).
