local task(obj) =
  local tags = std.get(obj, 'tags');
  {
    name: 'packages | Install ' + obj.name,
    command: {
      cmd: '/usr/bin/go install -ldflags "-s -w" ' + obj.url + '@latest',
      removes: '/usr/bin/go',
    },
  }
  + if std.isArray(tags) then
    { tags: [obj.name] + tags }
  else { tags: obj.name }
;

local packages =
  [
    x { tags: ['linters'] }
    for x in [
      { name: 'impl', url: 'github.com/josharian/impl' },
      { name: 'gofumpt', url: 'mvdan.cc/gofumpt' },
      { name: 'gomodifytags', url: 'github.com/fatih/gomodifytags' },
      { name: 'goimports', url: 'golang.org/x/tools/cmd/goimports' },
      { name: 'dockle', url: 'github.com/goodwithtech/dockle/cmd/dockle' },
      { name: 'yamlfmt', url: 'github.com/google/yamlfmt/cmd/yamlfmt' },
    ]
  ]
  + [
    { name: 'bazelisk', url: 'github.com/bazelbuild/bazelisk', tags: ['bazel'] },
    { name: 'buildifier', url: 'github.com/bazelbuild/buildtools/buildifier', tags: ['bazel', 'buildtools'] },
    { name: 'buildozer', url: 'github.com/bazelbuild/buildtools/buildozer', tags: ['bazel', 'buildtools'] },
    { name: 'gazelle', url: 'github.com/bazelbuild/bazel-gazelle/cmd/gazelle', tags: ['bazel'] },

    { name: 'sqls', url: 'github.com/sqls-server/sqls', tags: ['lspservers'] },
    { name: 'regols', url: 'github.com/kitagry/regols', tags: ['lspservers'] },
    { name: 'air', url: 'github.com/cosmtrek/air' },
    { name: 'ls-lint', url: 'github.com/loeffel-io/ls-lint/v2/cmd/ls_lint' },
    { name: 'isopod', url: 'github.com/cruise-automation/isopod' },
    { name: 'kapp', url: 'github.com/vmware-tanzu/carvel-kapp/cmd/kapp' },
    { name: 'kluctl', url: 'github.com/kluctl/kluctl/v2' },
    { name: 'kubesec', url: 'github.com/controlplaneio/kubesec/v2' },
    { name: 'kubeconform', url: 'github.com/yannh/kubeconform/cmd/kubeconform' },
    { name: 'kube-linter', url: 'golang.stackrox.io/kube-linter/cmd/kube-linter' },
    { name: 'kubectl-trace', url: 'github.com/iovisor/kubectl-trace/cmd/kubectl-trace' },
    { name: 'rakkess', url: 'github.com/corneliusweig/rakkess' },
    { name: 'vertfn', url: 'github.com/nikolaydubina/vertfn' },
    { name: 'tpmk', url: 'github.com/folbricht/tpmk/cmd/tpmk' },
    { name: 'countryfetch', url: 'github.com/CondensedMilk7/countryfetch/cmd/countryfetch' },
    { name: 'jira-cli', url: 'github.com/ankitpokhrel/jira-cli/cmd/jira' },
    { name: 'kroki-cli', url: 'github.com/yuzutech/kroki-cli/cmd/kroki' },
    { name: 'gophie', url: 'github.com/go-phie/gophie' },
    { name: 'koneko', url: 'github.com/irevenko/koneko' },
    { name: 'what-anime-cli', url: 'github.com/irevenko/what-anime-cli' },
    { name: 'wiki', url: 'github.com/betapictoris/wiki' },
    { name: 'lux', url: 'github.com/iawia002/lux' },
    { name: 'muffet', url: 'github.com/raviqqe/muffet/v2' },
    { name: 'primitive', url: 'github.com/fogleman/primitive' },
    { name: 'guerrilla', url: 'github.com/liamg/guerrilla/cmd/guerrilla' },
    { name: 'cshatag', url: 'github.com/rfjakob/cshatag' },
    { name: 'gokey', url: 'github.com/cloudflare/gokey/cmd/gokey' },
    { name: 'gmailctl', url: 'github.com/mbrt/gmailctl/cmd/gmailctl' },
    { name: 'jd', url: 'github.com/josephburnett/jd' },
    { name: 'hcl2json', url: 'github.com/tmccombs/hcl2json' },
    { name: 'ascode', url: 'github.com/mcuadros/ascode' },
    { name: 'dashboard-linter', url: 'github.com/grafana/dashboard-linter' },
    { name: 'oauth2l', url: 'github.com/google/oauth2l' },
    { name: 'oauth2c', url: 'github.com/cloudentity/oauth2c' },
    { name: 'enry', url: 'github.com/go-enry/enry' },
    { name: 'dblab', url: 'github.com/danvergara/dblab' },
    { name: 'terramate', url: 'github.com/mineiros-io/terramate/cmd/terramate' },
    { name: 'zk', url: 'github.com/mickael-menu/zk' },
    { name: 'mods', url: 'github.com/charmbracelet/mods' },
    { name: 'garble', url: 'mvdan.cc/garble' },
    { name: 'konstraint', url: 'github.com/plexsystems/konstraint' },
    { name: 'diffoci', url: 'github.com/reproducible-containers/diffoci/cmd/diffoci' },
    { name: 'buildkit-nix', url: 'github.com/reproducible-containers/buildkit-nix/cmd/buildkit-nix' },
    { name: 'regal', url: 'github.com/styrainc/regal' },
    { name: 'go-licenses', url: 'github.com/google/go-licenses' },

    // Nifty Pulumi stuff
    { name: 'crd2pulumi', url: 'github.com/pulumi/crd2pulumi', tags: ['pulumi-addons'] },
    { name: 'schema-tools', url: 'github.com/pulumi/schema-tools', tags: ['pulumi-addons'] },
    { name: 'kubespy', url: 'github.com/pulumi/kubespy' },
    { name: 'registrygen', url: 'github.com/pulumi/registrygen', tags: ['pulumi-addons'] },
    { name: 'pulumictl', url: 'github.com/pulumi/pulumictl/cmd/pulumictl', tags: ['pulumi-addons'] },
    { name: 'pulumi-trace-tool', url: 'github.com/pulumi/pulumi-trace-tool', tags: ['pulumi-addons'] },

    // TODO: make an Alpine package when stabilized and less feature locked down
    // (e.g. can customize themes, fonts, ...)
    { name: 'd2', url: 'oss.terrastruct.com/d2' },

    // NOTE: Clair server is required
    // - Install with 'go install github.com/quay/clair/v4/cmd/clair@latest' or use docker image
    // - Clair server requires a PostgreSQL instance
    // Default open on localhost:6060
    { name: 'clairctl', url: 'github.com/quay/clair/v4/cmd/clairctl' },

    // Meh BSL license
    { name: 'packer', url: 'github.com/hashicorp/packer' },

    // I might be generous enough to turn it on at some point (or maybe never, Google!)
    { name: 'gotelemetry', url: 'golang.org/x/telemetry/cmd/gotelemetry' },
  ]
;

std.manifestYamlDoc(
  [
    {  // https://github.com/Tinder/bazel-diff is preferred, but it can be vendored in WORKSPACE file
      name: 'packages | Install bazel-differ',
      tags: ['bazel-differ', 'bazel'],
      block: [
        std.prune(
          task({ name: 'bazel-differ', url: 'github.com/ewhauser/bazel-differ/cli' })
          + { name: 'bazel-differ | Run go install', tags: null }
        ),
        {
          name: 'bazel-differ | Rename the binary file',
          command: {
            cmd: 'mv "$GOPATH"/bin/cli "$GOPATH"/bin/bazel-differ',
            removes: '{{ ansible_env.GOPATH }}/bin/cli',
          },
        },
      ],
    },
    {
      name: 'packages | Install tflint suites',
      tags: 'tflint',
      block: [
        std.prune(
          task({ name: 'tflint', url: 'github.com/{{ item }}' })
          + {
            name: 'packages | Install tflint and some cloud ruleset plugins',
            tags: null,
            loop: [
              'terraform-linters/tflint',
              'terraform-linters/tflint-ruleset-google',
              'terraform-linters/tflint-ruleset-azurerm',
              'terraform-linters/tflint-ruleset-aws',
              'awslabs/serverless-rules/tflint-ruleset-aws-serverless',
            ],
          }
        ),
        {
          name: 'tflint | Create tflint plugins directory',
          file: {
            path: '~/.tflint.d/plugins',
            state: 'directory',
            mode: '755',
          },
        },
        {
          name: 'tflint | Copy tflint ruleset binaries to plugins directory',
          command: '/bin/mv {{ ansible_env.GOPATH }}/bin/{{ item }} ~/.tflint.d/plugins/',
          args: {
            creates: '~/.tflint.d/plugins/{{ item }}',
            removes: '{{ ansible_env.GOPATH }}/bin/{{ item }}',
          },
          loop: [
            'tflint-ruleset-google',
            'tflint-ruleset-azurerm',
            'tflint-ruleset-aws',
            'tflint-ruleset-aws-serverless',
          ],
        },
      ],
    },
  ] + [task(x) for x in packages],
  quote_keys=false
)
