Submitting a package to the AUR

Bouteiller < A2N > Alan
10 min readOct 20, 2023
AUR homepage

This is a little story about my research to publish for the first time a package to the AUR.

Summary :

  • Context and some thoughts
  • Research and experimentation
  • Writing bad code
  • Writing good code & connecting the dot
  • Quality check
  • Submitting the package
  • Final thoughts about the errors I made & the tools I used

🧑‍🏭 Context and some thought

This is a little story about my research to publish for the first time a package to the AUR.
I struggle a little to understand some concept but with some time, help, and re-reading the wiki I made my way into it.

You can use this story for a tutorial purpose but keep in mind that it wasn’t written for that.

IMO the wiki is well written, but it also lacks of example in parallel. And sometime a simple tutorial in addition to a more complete documentation is a more powerful tool than having to read other developers’ code (which is not often commented on, by the way) and trying to understand what the wiki says in parallel.

But that’s a discussion for later, so, let’s back to the story.

🕵️ Research and experimentation

Because I use “dracut numlock” on my Arch Linux, and it is not available on the AUR or on the official repo, I wanted to push it myself. I have never done that so let's go for a new adventure !

So, first thing first, I read the documentation available in the Arch Linux wiki (https://wiki.archlinux.org/title/AUR_submission_guidelines) :

  • I have searched in the official repo and in the AUR if a package called “dracut numlock” is found and nothing pop-out
  • I think this may be useful to have this code in the AUR for a more automated installation alongside other project when user setup their Arch Linux

The first step is pretty simple, I create a fork of the actual repository via the GitHub interface and clone it.

Next to that, I read the package guidelines and the “creating packages” page that is a kind of tutorial provided by the wiki.

After some reading, I found interesting to cote a line in the makepkg man page :

The advantage to a script-based build is that the work is only done once. Once you have the build script for a package, _makepkg_ will do the rest: download and validate source files, check dependencies, configure the build-time settings, build the package, install the package into a temporary root, make customizations, generate meta-info, and package the whole thing up for pacman to use.

This is interesting because it seems to say that the build of a package for the AUR is nothing more than a PKGBUILD file.

So I used the default one given by the wiki, example exist too under the /usr/share/pacman file. With the aid of the PKGBUILD man page, I’have written that file :

# Maintainer: Bouteiller a2n Alan <a2n.dev@pm.me>
pkgname=dracut-numlock
pkgver=1.0.0
pkgrel=1
pkgdesc="A dracut module which enables numlock in the early boot"
arch=('any')
url="https://github.com/bouteillerAlan/dracut-numlock/tree/v1.0.0"
license=('MIT')
source=("https://github.com/bouteillerAlan/$pkgname/archive/refs/tags/v$pkgver.tar.gz")

prepare() {
echo "prepare"
}

build() {
echo "build"
}

check() {
echo "check"
}

package() {
echo "package"
}

Next to that I launch the makepkg command for testing the file directly in the folder, this has the effect to download the tar.gz file provided by GitHub. But I also have an error now :

==> ERROR: Integrity checks are missing for: source

With the reading of the PKGBUILD man page in the cksums section, I resolve the problem :

  • we run this next command : makepkg -g >> PKGBUILD

This has the effect of adding a line in our PKGBUILD file that represent the checksum of our tar.gz. If you put another source in the source keyword, the command generates the checksum for that source, in order if multiple source is present, automatically.

I re-run the makepkg command and, voilà, no error message :

󰣇 makepkg               
==> Making package: dracut-numlock 1.0.0-1 (Sat 09 Sep 2023 18:19:12 CEST)
==> Checking runtime dependencies...
==> Checking buildtime dependencies...
==> Retrieving sources...
-> Found v1.0.0.tar.gz
==> Validating source files with sha256sums...
v1.0.0.tar.gz ... Passed
==> Extracting sources...
-> Extracting v1.0.0.tar.gz with bsdtar
==> Starting prepare()...
prepare
==> Starting build()...
build
==> Starting check()...
check
==> Entering fakeroot environment...
==> Starting package()...
package
==> Tidying install...
-> Removing libtool files...
-> Purging unwanted files...
-> Removing static library files...
-> Stripping unneeded symbols from binaries and libraries...
-> Compressing man and info pages...
==> Checking for packaging issues...
==> Creating package "dracut-numlock"...
-> Generating .PKGINFO file...
-> Generating .BUILDINFO file...
-> Generating .MTREE file...
-> Compressing package...
==> Leaving fakeroot environment.
==> Finished making: dracut-numlock 1.0.0-1 (Sat 09 Sep 2023 18:19:14 CEST)

Here we have our 4 commands :

  • prepare()
  • build()
  • check()
  • package()

🥶 Writing bad code

Now I need to implement the right code for each command, only if the command is useful, so I think I just need the mandatory package() function.

I write the next code for this function :

package() {
echo "running package"
cd "$pkgname-$pkgver"
sudo cp -r 50numlock/ /home/a2n/PhpstormProjects/xxxx/
sudo dracut -f
}

I have created the temporary file xxxx for testing purpose.
The 50numlock folder are well copied and the dracut command well launch.

So the final code is the following for this function :

package() {
cd "$pkgname-$pkgver"
sudo cp -r 50numlock/ /usr/lib/dracut/modules.d/
sudo dracut -f
}

But we have another error :

ERROR: ld.so: object 'libfakeroot.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.

After some research, I found a post on Reddit where a user said :

— Use install instead of cp and mkdir

Another research tells me that I don’t have to use sudo or any of post install commands like dracut-rebuild on PKGBUILD.

So I promptly check the man page of install and read on it :

This install program copies files (often just compiled) into destination locations you choose.

Yeah. Right…
So my code is not good at all ^^

👏 Writing good code & connecting the dot

So I edited the code like that :

package() {
cd "$pkgname-$pkgver"
install -Dm 644 50numlock/module-setup.sh "${pkgdir}"/usr/lib/dracut/modules.d/50numlock/module-setup.sh
install -Dm 644 50numlock/numlock.sh "${pkgdir}"/usr/lib/dracut/modules.d/50numlock/numlock.sh
}

Here the -D flag creates all leading components of the destination except the last one, then it copies the source to the destination.

The $pkgdir variable represents a temporary folder where the package put its files during the package or the build process.

Afterward a .MTREE file is generated (among other), this contains all the metadata of the files that are needed to be installed by the package. Then pacman takes care of the installation step.

🧑‍💼 Quality check

Before submitting, we have to ensure that our package and code is bulletproof with “quality assurance step”.

The first one is very simple, just run the makepkg command in your working directory. If this command fails, recheck your code. For me, no problem with this step.

For validating this step, you can check for :

  • a file named pkgname-pkgver.pkg.tar.zst in the folder (this package can be installed with the pacman -U command)
  • a rule of thumbs is to check if this package contains all the file and dependencies you want with pacman -Qlp [package file] and pacman -Qip [package file] commands

For example, my result :

[a2n@a2n-eso dracut-numlock]$ pacman -Qlp dracut-numlock-1.0.0-1-any.pkg.tar.zst 
dracut-numlock /usr/
dracut-numlock /usr/lib/
dracut-numlock /usr/lib/dracut/
dracut-numlock /usr/lib/dracut/modules.d/
dracut-numlock /usr/lib/dracut/modules.d/50numlock/
dracut-numlock /usr/lib/dracut/modules.d/50numlock/module-setup.sh
dracut-numlock /usr/lib/dracut/modules.d/50numlock/numlock.sh

After checking all that we can use the namcap (is it pacman that’s upside down or nampac?) command to check the package sanity.

You can install it via the namcap package : https://archlinux.org/packages/extra/any/namcap/

This command checks the PKGBUILD contents for common errors and package file hierarchy for unnecessary/misplaced files, then check if the depends option is well setup (in short, read the doc here).

So we have to run :

namcap PKGBUILD
namcap _<package file name>_.pkg.tar.zst

In my case, I have the following error / warning :

[a2n@a2n-eso dracut-numlock]$ namcap PKGBUILD 
PKGBUILD (dracut-numlock) W: Non-unique source name (v1.0.0.tar.gz). Use a unique filename.

So for patching that I updated the source to the following :

source=("https://github.com/bouteillerAlan/${pkgname}/releases/download/${pkgname}-v${pkgver}/${pkgname}-v${pkgver}.tar.gz")

With that I have to create a new release on GitHub and re-run the makepkg -g >> PKGBUILD command for the checksum.

And the warning is gone ! :)

Now the final check is namcap _<package file name>_.pkg.tar.zst :

[a2n@a2n-eso dracut-numlock]$ namcap dracut-numlock-1.0.1-1-any.pkg.tar.zst 
dracut-numlock E: Missing custom license directory (usr/share/licenses/dracut-numlock)
dracut-numlock E: Dependency bash detected and not included (programs ['sh'] needed in scripts ['usr/lib/dracut/modules.d/50numlock/module-setup.sh', 'usr/lib/dracut/modules.d/50numlock/numlock.sh'])

For the first one, we have to add the license of our package to the /usr/share/licenses folder. For that we have to add the following line to our package function :

install -D LICENSE "${pkgdir}"/usr/share/licenses/"${pkgname}"/LICENSE

The second error is fixed by updating the depends key like so :

depends=("sh")

And voilà, no error or warning :

[a2n@a2n-eso dracut-numlock]$ makepkg -f
==> Making package: dracut-numlock 1.0.1-1 (Sun 15 Oct 2023 05:10:54 PM CEST)
# ....
==> Finished making: dracut-numlock 1.0.1-1 (Sun 15 Oct 2023 05:10:55 PM CEST)
[a2n@a2n-eso dracut-numlock]$ namcap PKGBUILD
[a2n@a2n-eso dracut-numlock]$ namcap dracut-numlock-1.0.1-1-any.pkg.tar.zst
[a2n@a2n-eso dracut-numlock]$

🛫 Submitting the package

Firstly, you need to add an ssh key to your account right there : https://aur.archlinux.org/account/[your-username]/edit.

You have to add a new line for this key in your ssh config file too :

Host aur.archlinux.org
IdentityFile ~/.ssh/aur
User aur

The IdentityFile should correspond to your private key.

Next, we have to add the remote repository to our existing project :

git remote add aur ssh://aur@aur.archlinux.org/dracut-numlock.git

and then :

git fetch aur

Note that the AUR works only with main branch that has been called master.

Now we need to generate the .SRCINFO file, commit it and then push it to the new remote aur.
We can do that with the following command :

makepkg --printsrcinfo > .SRCINFO
git add .SRCINFO PKGBUILD
git commit -m "generate SRCINFO"
git push

You have to make sure that the last commit have both file in it. If it’s not the case, the push is rejected by the aur repository.

Here I encounter another problem, the aur repository keeps checking on the first commit of the branch if a PKGBUILD is included.

remote: error: The following error occurred when parsing commit
remote: error: 653df83092b3079a445c6fce3dc19b97a56e7014:
remote: error: missing PKGBUILD

For me that is not the case because the first commit have been made by the author of the module.

commit 653df83092b3079a445c6fce3dc19b97a56e7014
Author: FivEawE <fiveawe@gmail.com>
Date: Mon Dec 27 14:41:03 2021 +0100

Initial commit

So I need to find a way around that.

For that I have created another branch called historical-master, just for keeping all the commit history. Next, I have change is remote and push that to my repository :

[a2n@a2n-eso dracut-numlock]$ git branch --move historical-master

[a2n@a2n-eso dracut-numlock]$ git branch -vv
* historical-master 5a05247 [origin/master] push to the aur
main 8b99fd9 [origin/main] add usefull doc files

[a2n@a2n-eso dracut-numlock]$ git push -u origin historical-master
## .......
branch 'historical-master' set up to track 'origin/historical-master'.

[a2n@a2n-eso dracut-numlock]$ git branch -vv
* historical-master 5a05247 [origin/historical-master] push to the aur
main 8b99fd9 [origin/main] add usefull doc files

Finally, I checkout to the master branch and re-set the upstream branch :

git push --set-upstream origin master

And then made a squash with all the commit : git rebase -i HEAD~9.

At this step, I’m left with my last commit and the root commit.

For squashing them, you need to use this command : git rebase -i — root master (source).

That give me a master branch with only one commit containing all the other change :

[a2n@a2n-eso dracut-numlock]$ git log
commit bde54a4e4999b5e52568accd75b1e7445c003e7b (HEAD -> master, origin/master, origin/HEAD, aur/master)
Author: FivEawE <fiveawe@gmail.com>
Date: Mon Dec 27 14:41:03 2021 +0100

push to the aur

And now, after a force push, everything work fine !

My package is on the AUR !

And after a yay -S dracut-numlock I have the right folder installed at the right place :

The package is installed successfully

🤔 Final thoughts about the errors I made & the tools I used

Obviously, at the beginning, I didn’t immediately understand the concept of the PKGBUILD file and how it is used in addition with pacman.

I’d be lying if I said I have read all the sentences in the wiki, but I think the fact that there’s so much specific documentation on one subject and no tutorials didn’t help either.

It’s a personal opinion, which others won’t share, but if you want other people to participate in a community, you have to think about that too when documenting things. This is also a problem found in KDE plasma documentation, for example, which is at best not updated and at worst non-existent. At least we can’t blame arch Linux for that ^^ The documentation is top-tier, the example not so much.

So the lessons learned here are pretty simple :

  • read the wiki by taking your time and being relaxed
  • note-taking certainly helps
  • give yourself time to experiment and understand what you’re doing, my mistake here was to believe that all of this would be folded in a day
  • it’s going to sound contrary to what I wrote above, but take the time to read other people’s code
  • it’s not necessarily ideal for everyone, but you have to make do with the tools and skills you have, so trust the process

The trouble with git at the end was rather annoying because I don’t see the point of checking the commits preceding the last one, since the last one is enough to detect version changes and so on. At least that’s what I understand from the wiki.
Anyway, it was a good excuse to brush up on the classic git squash 😉

For the tools, beside the wiki, I use ChatGPT mainly to explain concept and code if needed. The idea is mostly to gain time. I use obsidian for taking note and the arch sub-reddit if I have a question. All my research are made on the arch wiki, the sub-reddit and stackoverflow.

That’s all folks, if you made your way so far, I hope you’ve learned a thing or two, and thanks for taking the time to read all this.

--

--