local docker_to_apptainer(obj) = {
  local dest = std.format('{{ xdg_dir.libexec_dir }}/%s.sif', [obj.name]),

  // Obviously we need the Bazel server daemon to persist
  local common_args =
    ['--ipc', '--no-eval', '--no-privs', '--unsquash', '--userns', '--uts']
    + if obj.name == 'bazel' then [] else ['--pid', '--cleanenv'],

  name: std.format('apptainer | Create %s environment', [obj.name]),
  tags: obj.name + '-apptainer',
  block: [
    {
      name: std.format('apptainer | Clean old %s.sif file', [obj.name]),
      command: {
        cmd: 'rm -rf ' + dest,
        removes: dest,
      },
    },
    {
      name: std.format('apptainer | Pull and build %s.sif file', [obj.name]),
      command: {
        cmd: std.format('/usr/bin/apptainer pull %s docker://%s:%s', [dest, obj.image, obj.tag]),
        creates: dest,
        removes: '/usr/bin/apptainer',
      },
    },
    {
      name: std.format('apptainer | Create %s-apptainer launch script', [obj.name]),
      copy: {
        content: std.format(
          |||
            #!/bin/sh
            TERM=xterm-256color \
              exec apptainer --silent --quiet exec \
                %s %s \
                %s %s "$@"
          |||,
          [
            std.join(' ', common_args),
            if std.objectHas(obj, 'args') && std.isArray(obj.args) then std.join(' ', obj.args) else '',
            dest,
            if std.objectHas(obj, 'command') && std.isString(obj.command) then obj.command else obj.name,
          ]
        ),
        dest: '{{ xdg_dir.bin_home }}/' + obj.name,
        mode: '755',
      },
    },
  ],
};

local docker_images =
  local hashicorp_args =
    local env = {
      CHECKPOINT_DISABLE: true,
      DISABLE_VERSION_CHECK: true,
    };
    [
      std.format('--env %s=%s', [x, std.toString(env[x])])
      for x in std.objectFields(env)
    ];

  [
    {
      name: 'bazel',
      image: 'gcr.io/bazel-public/bazel',
      tag: '7.0.0',
    },
    {
      name: 'asciidoctor',
      image: 'docker.io/asciidoctor/docker-asciidoctor',
      tag: '1.60.0',

      // Other asciidoctor-* executables (extensions) will be symlinked into this one
      command: '"$(basename "$0")"',
    },
    {
      name: 'opam',
      image: 'docker.io/ocaml/opam',
      tag: 'alpine-ocaml-5.2',
      args: ['--env OPAMROOT="${OPAMROOT:-{{ xdg_dir.data_home }}/opam}"'],
    },
    {
      name: 'terraform',
      image: 'docker.io/hashicorp/terraform',
      tag: '1.6.6',
      args: hashicorp_args,
    },
    {
      name: 'vault',
      image: 'docker.io/hashicorp/vault',
      tag: '1.15.4',
      args: hashicorp_args,
    },
    {
      name: 'consul',
      image: 'docker.io/hashicorp/consul',
      tag: '1.17.1',
    },
    {
      name: 'nomad',
      image: 'docker.io/hashicorp/nomad',
      tag: '1.7.2',
    },
  ];

std.manifestYamlDoc([docker_to_apptainer(x) for x in docker_images] + [
  {
    name: 'apptainer | Symlink asciidoctor-* executables',
    tags: 'asciidoctor-apptainer',
    file: {
      src: './asciidoctor',
      dest: '{{ xdg_dir.bin_home }}/asciidoctor-{{ item }}',
      state: 'link',
    },
    loop: [
      'confluence',
      'epub3',
      'fb2',
      'pdf',
      'pdf-optimize',
      'reducer',
      'revealjs',
      'safe',
    ],
  },
], quote_keys=false)
