Published on 2025-05-02.
Building a package manager for my new distribution.
First, a recap. In my last post, I had come up with a suitable package layout for our package manager (a ‘simple’ version of which I have developed in the time between publishing these two posts; it can be found at https://github.com/SilverHairOrTwo/based). Since then, however, I have made some changes to the format, which I will gloss over before proceeding to explain how the inner-workings of this package manager.
The layout for a binary package remains the same:
$ tree
.
├── contents
│ └── usr
│ └── bin
│ └── example-program
├── hooks
│ ├── install
│ └── remove
└── pkg
└── manifest.yml
6 directories, 4 files
However, the format of the pkg.yml
file (in a source package) has changed. Underneath is the pkg.yml
file for GNU Hello (repository: https://github.com/SilverHairOrTwo/hello-package):
For one, the version
variable now contains a constant, instead of a script that would return the version. The value of this variable is accessible in each script via the ${pkgver}
environment variable.
Secondly, I have split the build
script into two: a build
script like earlier and a new install
script. This is so that we can implement support for split packages in future (wherein each produced binary package would have different contents).
Lastly, there is a new description
variable; this can come in handy when one wants to view a package’s metadata.
Now, onto the package manager. I chose to name it based
(based on the name of this distribution, Project Based: Build A Suckless unEssential Distribution). It can be found here. It is quite similar to distrobox
in that each utility is its own script, all of which can be called using the based
script (so based install package1 package2
would be equivalent to running based-install package1 package2
, for instance). In this section, I’ll delve into each of its functions and how they are implemented.
I’ll begin with based-build
, the package building utility.
As you have probably noticed, I’m not using python
but rather a bash
script for these utilities. This is so that we can have a functional self-hosting system (a system that can build itself) without packaging python3
(although we will have to at some point, of course). Aside from bash
and coreutils
, this script only requires two other packages: jq
and goyq
(for parsing YAML files).
This function parses the pkg.yml
file to read the values of each of the following (using yq
):
This function validates the package name, version and revision, while also checking to ensure the package supports the host’s architecture.
This function runs the pull
, build
and install
functions in the pkg.yml
file, while making the following variables available to each function:
This function generates the manifest.yml file for the binary package in the format underneath:
name: ${name}
arch: ${arch}
version: ${version}-${revision}
description: ${description}
depends: ${depends}
recommends: ${recommends}
conflicts: ${conflicts}
This function compresses the built package into a file with the extension .based.tgz
, indicating that is a package file to be installed with based
.
This function iterates through the list of packages to be installed and splits them into the list of packages that are to be downloaded, and those that already exist locally.
It is here that I plan to implement dependency resolution in future.
This function downloads each package that was added to the list of packages to be downloaded in the previous function; or well, it is supposed to be. I am yet to implement remote repository support, meaning this is simply a placeholder function at the moment.
This functions iterate through each package to be installed, making sure they each have a valid manifest.yml
file. It then calls install_local_package
for each package.
This function is executed for each package to be installed and does most of the work to copy the contents of each package to the host system, while ensuring there are no overlapping/conflicting files (as any sane package manager would).
This function runs the install hook shipped with each package.
Now that we have a somewhat-functional package manager, we can proceed onto packaging glibc
, bash
, coreutils
, gcc
, jq
, goyq
and all their various dependencies.
You can reach me at my email, as listed on my homepage.