# Container-based development with toolboxcutter

[Toolbx](https://containertoolbx.org/) is a tool for Linux systems, specifically [Fedora](https://getfedora.org/), that creates and manages development environment containers. Its purpose is to group development dependencies in a mutable container separate from the base operating system both for the benefit of separating concerns and allowing dev. environments to be reused and shared.

> The ***toolbx*** project was originally named ***toolbox*** and the command reflects this.

Typical usage might look like this:

```sh
[user@hostname ~]$ toolbox create
Created container: fedora-toolbox-36
Enter with: toolbox enter
[user@hostname ~]$ toolbox enter
```

While this may provide the foundation of a compelling development workflow, I felt something was missing. From my perspective, a development environment is specific to the project being developed.

So, you could use **toolbox** like this:

```sh
[user@hostname ~]$ cd my-project
[user@hostname my-project]$ toolbox create my-project-toolbox
[user@hostname my-project]$ toolbox enter my-project-toolbox
```

And proceed to install dev. dependencies in your container, but I want a toolbox that can be created and recreated on-demand, from a `Dockerfile`, for example. It then makes sense to commit this dev. environment manifest to your project so that your environment's specifications follow your project's development. Ultimately, what I sought was a means to more easily manage per-project toolboxes, which prompted the creation of [toolboxcutter](https://github.com/jcrd/toolboxcutter).

## toolboxcutter

**toolboxcutter** (invoked as `tb`) is a script that manages the lifecycle of per-project development containers using `Dockerfile`s.

It began life as a [zsh function](https://zsh.sourceforge.io/Intro/intro_4.html), but as its feature set expanded, I realized it had become a project of its own, so I ported it to a standalone [bash](https://www.gnu.org/software/bash/) script.

It's designed to be easy to use. Within a directory containing a **toolbox**\-based `Dockerfile`, simply run `tb` and your toolbox will be entered, creating the container if necessary.

Install it on Fedora with these commands:

```bash
dnf copr enable jcrd/toolboxcutter
dnf install toolboxcutter
```

A complete overview of its functionality is given in its command-line usage message:

```txt
usage: tb [command]

With no command, enter toolbox.

commands:
  init IMAGE      Initialize Dockerfile based on IMAGE
  create [IMAGE]  Create container (from IMAGE if provided)
  recreate        Remove and recreate container
  build           Build image
    options:
      -n NAME       Name of image
      -c            Build without cache
  rebuild         Remove container and rebuild image
    options:
      -n NAME       Name of image
      -c            Build without cache
  stop            Stop container
  rm              Remove container
  rmi             Remove image
  rpkg            Build rpm via rpkg
    options:
      -n NAME       rpkg spec template name
      -e EXT        rpkg spec template extension
  rpkg-install    Build and install rpm via rpkg
    options:
      -n NAME       rpkg spec template name
      -e EXT        rpkg spec template extension
      -r NAME       Name of produced rpm to install
  run COMMAND     Run COMMAND in toolbox
  version         Show version
```

As `tb` is largely a wrapper around **toolbox**, most of its commands translate directly to their **toolbox** equivalents. These are supplemented with image and container management commands that would otherwise require invoking [podman](https://podman.io/).

### Building RPM packages

Unique to **toolboxcutter** is its ability to build [RPM](https://rpm.org/) packages from [rpkg](https://docs.pagure.org/rpkg/) [SPEC](https://rpm-packaging-guide.github.io/#what-is-a-spec-file) template files. This feature has been instrumental in the development, testing, and dogfooding of my own projects while using Fedora. I believe it elevates `tb` to a truly powerful developer tool for these reasons:

* Build dependencies need only exist in your project's container, minimizing pollution of your workstation's environment;
    
* Most importantly, the development-packaging cycle is combined into a single fluid process, providing interactivity benefits similar to that of a [read-eval-print loop](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop).
    

This functionality depends on the availability of **rpkg** in the toolbox container itself, so your project's `Dockerfile` should install it. This is the `Dockerfile` for the base image I use:

```bash
FROM registry.fedoraproject.org/fedora-toolbox:36

RUN dnf install -y git-subtree
RUN dnf install -y make
RUN dnf install -y neovim
RUN dnf install -y rpkg # Install rpkg
RUN dnf install -y rpmdevtools
RUN dnf install -y zsh

CMD /usr/bin/zsh
```

Any images or containers derived from this can be used to build RPM packages provided a SPEC template. By default, `tb` looks for this file at `spec/*.rpkg.spec` in your project's root directory.

Here is **toolboxcutter**'s own SPEC template file:

%[https://gist.github.com/jcrd/5651377a5441a8c74807901ff5e8a197] 

Documentation about the format of these templates is sparse and much of my knowledge was gleaned from existing files. Nevertheless—perhaps with a bit of trial and error—it is possible to run `tb rpkg-install` in your project's directory to produce an installable RPM package with your latest changes!
