NixOS and mediagoblin: Part I

As I have stated before, I want to write a book. One of the early-stage ideas I have for a book is to write about Nix/NixOS. As I have also stated before, I’m part of NUR, and I have yet to have a package to contribute. That is going to change with this blog series.

What I’m going to attempt to do is write a package and configuration module for mediagoblin, a multimedia publishing web application. The end result is that I want to have a self-hosted photo and video sharing application for my family and friends, hosted on a NixOS machine in the cloud.

But, first things first, I need to package it. It is going to take some time to do this, because I’m inexperienced in writing Nix packages in general, and I’ve had trouble with Python Nix packages in particular.

1. Create New Package in my NUR

This first part is quite simple, since the NUR template I used has an example package to help you get started.

First, I went into the default.nix file at the top of the repo and added the line starting with mediagoblin:

# default.nix
{ pkgs ? import <nixpkgs> { } }:
{
...
  mediagoblin = pkgs.callPackage ./pkgs/mediagoblin {};
}

What this does is evaluates the package defined in the given directory, and assigns it to the variable mediagoblin. This variable is accessible via the NUR collection under my user name, sehqlr.

The second thing I did was create the directory with the package definition within. To do that, I ran this command:

$ cp pkgs/example-package pkgs/mediagoblin

Now, I can run nix build and it will build the package for me. But the package definition is that of example-package, not mediagoblin, so I started to edit the default.nix file that contains that definition.

2. Add Source Git Repo

The first version of the file default.nix looks like this:

{ stdenv }:

stdenv.mkDerivation rec {
  name = "example-package-${version}";
  version = "1.0";
  src = ./.;
  buildPhase = "echo echo Hello World > example";
  installPhase = "install -Dm755 example $out";
}

What this means is this:

  1. We are creating a package named “example-package-1.0”
  2. The source code lives in the same directory as this file
  3. We create a bash script that prints “Hello World” to the screen
  4. And we install that script to the $out directory, which is how you get stuff out of the build environment (stdenv) and into the package

The first thing I did was to change the name to mediagoblin, which means that the package name changed to mediagoblin-1.0. My intention is to change the version of the package to match which version is currently released.

We don’t have the source in the directory, and I don’t want to have a clone of the mediagoblin repo in my NUR, so the next thing I did was to replace the src argument’s value with something else.

Looking at the install documentation for mediagoblin, there is a lot of information about dependencies and other things of that nature. I will need that information later on, but the first thing I wanted to know was where the project lived. After reading for a while I finally found out that mediagoblin is a git repository, located at https://git.savannah.gnu.org/git/mediagoblin.git, and that they want you to use the stable branch.

So, the change to the package definition looks like this:

version = "stable";
src = fetchGit {
  url = "https://git.savannah.gnu.org/git/mediagoblin.git";
  ref = "stable";
};

However, this will not work in Nix’s pure evaluation mode, since the actual git revision can change every time we run this. So, I needed to add a revision, with the rev argument. I did that using the nix-prefetch-git command, copied the revision into my file, and wound up with this:

src = fetchGit {
  url = "https://git.savannah.gnu.org/git/mediagoblin.git";
  rev = "9308959be28da444e6875691fef14a635b79339d";
};

(The 9308… is the actual git revision for stable when I was first writing the package. I will need to update that revision whenever preforming updates.)

3. Start Writing the Build Phase

So, now that I had my package fetching the git repo, I filled out the buildPhase argument with the shell commands. Looking at the documentation, the commands to run are these:

$ ./bootstrap.sh
$ VIRTUALENV_FLAGS='--system-site-packages' ./configure
$ make

Starting out slowly, I changed my file to have the first command:

buildPhase = ''
  cd $src
  ./bootstrap.sh
'';

The $src variable refers to the directory that is defined by the src argument in our package definition, and so in this case, refers to the top level directory for the mediagoblin git repository.

Fixing Build Problems (Next Time)

At this point in the process, once you start packaging something for Nix the first time, you run into troubles building due to a lack of a particular dependency. In our case, when I run this package definition, I get this error:

  ./bootstrap.sh: line 5: aclocal: not found

What this means is that the aclocal binary was not found within the build environment. The default build environment, called stdenv, does not have very much in it. We will have to explicitly include aclocal, and any other dependencies, into our build.

However, I’m going to save that for next time.

Adding Meta Properties

So far I have a broken package that will not build. I will put the “broken” attribute on the package until I get it to work properly, using the meta attribute:

{ lib, stdenv }:

stdenv.mkDerivation rec {
  ...
  meta = with stdenv.lib; {
    description =
      "MediaGoblin is a free software media publishing platform that anyone can run.";
    longDescription = ''
      MediaGoblin is a free software media publishing platform that anyone can run. You can think of it as a decentralized alternative to Flickr, YouTube, SoundCloud, etc.
    '';
    homepage = "https://mediagoblin.org";
    changelog =
      "https://git.savannah.gnu.org/cgit/mediagoblin.git/plain/NEWS?h=v${version}";
    license = licenses.gpl3Plus;
    maintainers = [ maintainers.sehqlr ];
    platforms = platforms.linux;
    broken = true;
  };
}

The broken attribute doesn’t stop the package being added to the NUR collection, but it does prevent users from installing it without enabling broken packages on their end.

End of Part I

If there is any part of this which is not explained well, please let me know in a comment below.

Thanks for reading!

Published by sehqlr

I'm a multipotentialite Millenial from St. Louis, MO. My day job is freelance web development and DevOps, but in a previous life, I was an English major. I'm on the STL Tech Slack, GitHub, Keybase, and Twitter, under the @sehqlr handle. (It's pronounced "secular" like the world-view.) I'm also on Mastodon as @sehqlr@weirder.earth.

One thought on “NixOS and mediagoblin: Part I

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: