Skip to content

csmith/contempt

Repository files navigation

Contempt

Note: this repository currently contains the released version of contempt under cmd/contempt, and new work-in-progress commands under cmd/contempt-generator, cmd/contempt-writer and cmd/contempt-builder. These new commands are not yet finished, and all the documentation below refers to the old, single command.


Contempt is a tool to generate Dockerfiles (or Containerfiles) from templates.

It comes with support for various useful functions for getting the latest versions of software, expanding out the dependency trees of package managers, and so on.

The most basic invocation of contempt takes a source directory and a destination directory (these can be the same). Within these directories, it is expected that each container image is defined in its own subdir, e.g.:

input
↳ image1
  ↳ Dockerfile.gotpl
  ↳ something-or-other.patch
↳ image2
  ↳ Dockerfile.gotpl
  
output
↳ image1
  ↳ Dockerfile
↳ image2
  ↳ Dockerfile

Contempt's job is to take those template files and generate the plain version in the output directory:

go install github.com/csmith/contempt/cmd/contempt@latest
contempt input_dir output_dir

Contempt also has options to make a git commit every time an output file, build the corresponding image using buildah, and push it to a registry:

contempt -commit -build -push . .

You can also limit contempt to a single project:

contempt -project=image1 . .

Other miscellaneous options are available:

Usage of contempt:
-alpine-mirror string
    [ALPINE_MIRROR] Base URL of the Alpine mirror to use to query version and package info (default "https://dl-cdn.alpinelinux.org/alpine/")
-build
    [BUILD] Whether to automatically build on successful commit
-commit
    [COMMIT] Whether to automatically git commit each changed file
-force-build
    [FORCE_BUILD] Whether to build projects regardless of changes
-output string
    [OUTPUT] The name of the output files (default "Dockerfile")
-project string
    [PROJECT] The name of a single project to generate, instead of all detected ones
-push
    [PUSH] Whether to automatically push on successful commit
-push-retries int
    [PUSH_RETRIES] How many times to retry pushing an image if it fails (default 2)
-registry string
    [REGISTRY] Registry to use for pushes and pulls (default "reg.c5h.io")
-registry-pass string
    [REGISTRY_PASS] Password to use when querying the container registry
-registry-user string
    [REGISTRY_USER] Username to use when querying the container registry
-source-link string
    [SOURCE_LINK] Link to a browsable version of the source repo (default "https://github.com/example/repo/blob/master/")
-template string
    [TEMPLATE] The name of the template files (default "Dockerfile.gotpl")
-workflow-commands
    [WORKFLOW_COMMANDS] Whether to output GitHub Actions workflow commands to format logs (default true)

In practice, you will probably want to set the -registry and -source-link parameters to point at the correct place along with the commit/build/push options as required.

Template functions

Contempt uses Go's built-in text/template package, and provides the following functions:

Image

{{image "alpine"}}

Fetches the latest digest for the given image from the configured registry, and returns the fully-qualified name with the digest (e.g. reg.c5h.io/alpine@sha256:abcd...........).

If the image name includes a registry, then it is used as-is regardless of the registry flag value:

{{image "docker.io/library/hello-world"}}

Note: see below for information on passing credentials when using more than one registry.

Registry

{{registry}}

Returns the registry configured with the -registry flag.

Alpine release

{{alpine_url}}
{{alpine_checksum}}

Returns the URL and checksum for the latest release of Alpine.

Golang release

{{golang_url}}
{{golang_checksum}}

Returns the URL and checksum for the latest release of Golang.

Postgres release

{{postgres13_url}}
{{postgres13_checksum}}

{{postgres14_url}}
{{postgres14_checksum}}

{{postgres15_url}}
{{postgres15_checksum}}

Returns the URL and checksum for the latest release of Postgres 13, 14 or 15.

Alpine packages

RUN apk add --no-cache \
        {{range $key, $value := alpine_packages "ca-certificates" "musl" "tzdata" "rsync" -}}
        {{$key}}={{$value}} \
        {{end}};

Given one or more Alpine packages, resolves all of their dependencies and returns a flattened list of all packages pinned to their current versions.

GitHub tag

{{github_tag "csmith/contempt"}}
{{prefixed_github_tag "csmith/contempt" "release-"}}

Returns the latest semver tag of the given repository. The "prefixed" variant will discard the given prefix from tag names before comparing them using semver.

Git tag

{{git_tag "https://git.sr.ht/~csmith/example"}}
{{prefixed_git_tag "https://git.sr.ht/~csmith/example" "release-"}}

Returns the latest semver tag of the given repository. The "prefixed" variant will discard the given prefix from tag names before comparing them using semver.

Regex URL content

{{regex_url_content "google_button" "https://www.google.com/" "I'm feeling (L[a-z]+)"}}

Requests the given URL over HTTP and attempts to match the regular expression. Returns the text captured by the first capturing group in the regex. The first argument is a friendly name used for logging and BOM tracking.

Increment int

{{increment_int 3}}

Returns the given integer incremented by one.

Dealing with registry credentials

There are two cases in which contempt requires credentials: checking the latest digest for an image in a non-public registry (when the {{image}} template function is used), and pushing built images (when the -push flag is used).

Checking digests

You can supply a single set of credentials to use for checking digests using the -registry-user and -registry-pass flags (or associated environment variables). If these options aren't passed and the registry is not public, then credentials will be read from ~/.docker/config.json if it exists, else ${XDG_RUNTIME_DIR}/containers/auth.json.

Pushing

For pushes, contempt expects buildah to handle authentication for it. To that end, you will probably want to call buildah login before running contempt. Buildah will also read from ~/.docker/config.json so a docker login will also suffice.

GitHub Actions

If you are running contempt using GitHub Actions (or possibly other CI tooling) and need to supply multiple sets of credentials for the {{image}} function, you may encounter a number of inconvenient issues:

  • The XDG_RUNTIME_DIR env var is not set, and the /run/user directory is not writable, meaning buildah login stores its credentials in /var/tmp/containers-user-1001/containers/containers/auth.json. Contempt will not read from this location when trying to find credentials for the {{image}} function.
  • The default actions image comes pre-supplied with a ~/.docker/config.json with credentials for Docker Hub. Because this file exists contempt won't even attempt to read ${XDG_RUNTIME_DIR}/containers/auth.json, even if you've set the environment variable to a sensible value.

The simplest way to deal with this situation is to use docker login to write credentials to Docker's config file.

Example

Check out csmith/dockerfiles for a collection of templates and outputs generated using contempt.

About

Container file templating

Resources

License

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published

Languages