Hello world!

Everything starts from an “Hello!”

This article will guide you to build your first package with Luet! For this purpose, we have picked a real-world example: gogs which is a “painless self-hosted Git service”, an open-source alternative to Github.

Gogs is written in Golang, and we need a working Golang version in order to build it.

Here you can see a live recorded session of this tutorial:

Define a Luet tree

Everything starts from a Luet tree. A Luet tree is just a directory containing one (or more) Luet specfile, here on we assume that you are working in a dedicated folder (e.g. ~/demo) in your system.

Let’s create then a package that will be our base to build other packages from now on, we have picked busybox here - it is really small and enough for our purpose.


mkdir busybox

Let’s now write the build specification, which is just containing the image tag that we are referencing to

cat <<EOF > busybox/build.yaml
image: "busybox:{{.Values.version}}-glibc"

Now, lets write the definition.yaml, which contains the metadata information about our package ( e.g. how we refer to it with luet, the version, and so on )

cat <<EOF > busybox/definition.yaml
category: "distro"
name: "busybox"
version: "1.33.0"


We need now golang in order to build gogs. Let’s declare then a golang package:

mkdir golang

And a build specfile, which is simply fetch golang from https://golang.org and installing it in the busybox container:

cat <<EOF > golang/build.yaml
- category: "distro"
  name: "busybox"
  version: ">=0"

- wget https://golang.org/dl/go{{.Values.version}}.linux-{{.Values.arch}}.tar.gz -O golang.tar.gz
- mkdir /usr/local
- tar -C /usr/local -xzf golang.tar.gz

Note how we require busybox. The Golang container will now be based from busybox, and the prelude and steps fields will be executed in that context.

And finally let’s write the golang metadata files, so we can refer to it from other packages

cat <<EOF > golang/definition.yaml
name: "go"
category: "dev-lang"
version: "1.15.6"
arch: "amd64"


Finally we can write the gogs package definition!

mkdir gogs

The build specfile, will just fetch the gogs sources at a given version (specified in the definition.yaml) and build the sources with go:

cat <<'EOF' > gogs/build.yaml
- category: "dev-lang"
  name: "go"
  version: ">=0"
- GOPATH="/go"
- GOGSPATH="$GOPATH/src/github.com/gogs/gogs"
- PATH=$PATH:/usr/local/go/bin
- mkdir -p $GOPATH/src/github.com/gogs
- wget https://github.com/gogs/gogs/archive/v{{.Values.version}}.tar.gz -O - | tar -xzf - -C ./  && mv gogs-{{.Values.version}} $GOGSPATH
- mkdir /usr/bin
- cd $GOGSPATH && go build && mv gogs /usr/bin/gogs
# Cache generated by Golang
- ^/root

And the metadata, in this way we can refer to gogs in a Luet tree:

cat <<EOF > gogs/definition.yaml
category: "dev-vcs"
name: "gogs"
version: "0.11.91"

Build packages

The simplest and mostly immediate way to build packages, is running luet build <packagename> in the same folder you have your Luet tree.

In this case, to build gogs and its deps, we can do:

luet build dev-vcs/gogs

And that’s it! you will find the package archives in build/ in the same folder where you started the command.

You will see that Luet generates not only archives with the file resulting to your builds, but it will also generate metadata files (ending with .metadata.yaml) that contains additional metadata information about your build and the package itself (e.g. checksums).

You can use tools like yq to inspect those:

yq r build/gogs-dev-vcs-0.11.91.metadata.yaml checksums

Now if you want to consume the artifacts just built with luet install, you can create a repository with luet create-repo.

Last modified June 24, 2024: Update goreleaser command (1712988)