Do It - Subcommands and Single Binary CLI
Tags: elixir, cli
Published: 2023-10-27 20:00:55

In the last [article](https://dev.to/rzcastilho/doit-elixir-command-line-interface-library-8i4), I introduced you to [Do It](https://github.com/rzcastilho/do_it), a library to create CLI tools in Elixir. Now, I'll show you the subcommands feature and how to generate a single binary using [burrito-elixir](https://github.com/burrito-elixir/burrito).

## Subcommands

[Do It](https://github.com/rzcastilho/do_it) now supports subcommands; in this way, you can logically group other commands at any level using the `subcomand` macro.

For example:

```elixir
defmodule HelloWorld.Template do
  use DoIt.Command,
    description: "Manage HelloWorld Template"

  subcommand(HelloWorld.Template.Set)
  subcommand(HelloWorld.Template.Unset)
  subcommand(HelloWorld.Template.Show)
end
```

When a command has subcommands, you cannot define arguments or options and don't need to implement the `run` callback function.

As I said before, it's just a way to group other commands logically but cleverly when implementing CLIs with many commands.

Calling parent command with the `--help` option shows all subcommands.

```shell
./hello_world template --help 

Usage: hello_world template SUBCOMMAND

Manage HelloWorld Template

Subcommands:
  show      Show default message template
  unset     Remove default message  template
  set       Set default message template

Run 'hello_world template SUBCOMMAND --help' for more information on a subcommand.
```

## Single Binary

[Do It](https://github.com/rzcastilho/do_it) supports single binary CLI distribution through [burrito-elixir](https://github.com/burrito-elixir/burrito).

To configure the application, add the `burrito-elixir` dependency in your project, the `:mod` property in the application function, and the `:releases` key with the releases configuration to your project properties in your `mix.exs` file.

```elixir
defmodule HelloWorld.MixProject do
  use Mix.Project

  def project do
    [
      app: :hello_world,
      version: "0.1.0",
      elixir: "~> 1.14",
      start_permanent: Mix.env() == :prod,
      deps: deps(),
      releases: releases()
    ]
  end

  # Run "mix help compile.app" to learn about applications.
  def application do
    [
      extra_applications: [:logger],
      mod: {HelloWorld, []}
    ]
  end

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      {:do_it, path: "../../"},
      {:burrito, github: "burrito-elixir/burrito"}
    ]
  end

  defp releases do
    [
      hello_world: [
        steps: [:assemble, &Burrito.wrap/1],
        burrito: [
          targets: [
            macos: [os: :darwin, cpu: :x86_64],
            linux: [os: :linux, cpu: :x86_64],
            windows: [os: :windows, cpu: :x86_64]
          ]
        ]
      ]
    ]
  end
end
```

After configurations, you can build using the mix release command, the binaries will be generated in `burrito_out` folder.

```shell
$ MIX_ENV=prod mix release
...
ls -l burrito_out
total 77208
-rwxr--r--  1 castilho  staff  16729320 Oct 27 16:23 hello_world_linux
-rwxr--r--  1 castilho  staff   6572904 Oct 27 16:22 hello_world_macos
-rwxr--r--  1 castilho  staff  16222208 Oct 27 16:24 hello_world_windows.exe
```

See the build process and CLI execution in the video below.

{% embed https://asciinema.org/a/617488?speed=4 %}