Skip to content
davidmandle edited this page Nov 15, 2024 · 14 revisions

Usage

The GOPACKAGESDRIVER allows gopls and any package using x/tools/packages to expose package data. Configuring the rules_go's packages driver is simple.

1. gopls

gopls >= v0.6.10 (released on Apr 13th 2021) is required.

Install it in your path. If you have $GOBIN in your PATH, this should do the trick:

$ go install golang.org/x/tools/[email protected]

If you are using Visual Studio Code, it should have been automatically updated by now.

2. Launcher script

Create a launcher script, say tools/gopackagesdriver.sh. If your repo is loading rules_go in its MODULE.bazel, give it these contents:

#!/usr/bin/env bash
# See https://github.com/bazelbuild/rules_go/wiki/Editor-setup#3-editor-setup
exec bazel run -- @rules_go//go/tools/gopackagesdriver "${@}"

If your repo is still loading rules_go in the WORKSPACE file:

#!/usr/bin/env bash
# See https://github.com/bazelbuild/rules_go/wiki/Editor-setup#3-editor-setup
exec bazel run -- @io_bazel_rules_go//go/tools/gopackagesdriver "${@}"

3. Editor Setup

You might want to replace github.com/my/mypkg with your package. When first opening a file in the workspace, give the driver some time to load.

Neovim

nvim_lsp.gopls.setup {
  on_attach = on_attach,
  settings = {
    gopls = {
      env = {
        GOPACKAGESDRIVER = './tools/gopackagesdriver.sh'
      },
      directoryFilters = {
        "-bazel-bin",
        "-bazel-out",
        "-bazel-testlogs",
        "-bazel-mypkg",
      },
      ...
    },
  },
}

Visual Studio Code

In the .vscode/settings.json of your workspace, you'll need to one of the two following JSON blobs, depending on if your repo is using MODULE.bazel or WORKSPACE to load rules_go (the difference is in the go.goroot). Also, for both of these, you'll need to edit some of the lines.

If you're using MODULE.bazel, use a JSON blob like this, after editing the following three lines:

  1. In build.directoryFilters replace mypkg in bazel-mypkg with your repo's workspace name.
  2. In formatting.local replace the import path there with the import path of your repo's code.
  3. In go.goroot, replace mymodule with the name of your root module.
{
  // Settings for go/bazel are based on editor setup instructions at
  // https://github.com/bazelbuild/rules_go/wiki/Editor-setup#visual-studio-code
  "go.goroot": "${workspaceFolder}/bazel-${workspaceFolderBasename}/external/rules_go~~go_sdk~mymodule__download_0/",
  "go.toolsEnvVars": {
    "GOPACKAGESDRIVER": "${workspaceFolder}/tools/gopackagesdriver.sh"
  },
  "go.enableCodeLens": {
    "runtest": false
  },
  "gopls": {
    "build.directoryFilters": [
      "-bazel-bin",
      "-bazel-out",
      "-bazel-testlogs",
      "-bazel-mypkg",
    ],
    "formatting.gofumpt": true,
    "formatting.local": "github.com/my/mypkg",
    "ui.completion.usePlaceholders": true,
    "ui.semanticTokens": true,
    "ui.codelenses": {
      "gc_details": false,
      "regenerate_cgo": false,
      "generate": false,
      "test": false,
      "tidy": false,
      "upgrade_dependency": false,
      "vendor": false
    },
  },
  "go.useLanguageServer": true,
  "go.buildOnSave": "off",
  "go.lintOnSave": "off",
  "go.vetOnSave": "off",
}

If your repo is using WORKSPACE to load rules_go, use a JSON blob like this, after editing the following two lines:

  1. In build.directoryFilters replace mypkg in bazel-mypkg with your repo's workspace name.
  2. In formatting.local replace the import path there with the import path of your repo's code.
{
  // Settings for go/bazel are based on editor setup instructions at
  // https://github.com/bazelbuild/rules_go/wiki/Editor-setup#visual-studio-code
  "go.goroot": "${workspaceFolder}/bazel-${workspaceFolderBasename}/external/go_sdk",
  "go.toolsEnvVars": {
    "GOPACKAGESDRIVER": "${workspaceFolder}/tools/gopackagesdriver.sh"
  },
  "go.enableCodeLens": {
    "runtest": false
  },
  "gopls": {
    "build.directoryFilters": [
      "-bazel-bin",
      "-bazel-out",
      "-bazel-testlogs",
      "-bazel-mypkg",
    ],
    "formatting.gofumpt": true,
    "formatting.local": "github.com/my/mypkg",
    "ui.completion.usePlaceholders": true,
    "ui.semanticTokens": true,
    "ui.codelenses": {
      "gc_details": false,
      "regenerate_cgo": false,
      "generate": false,
      "test": false,
      "tidy": false,
      "upgrade_dependency": false,
      "vendor": false
    },
  },
  "go.useLanguageServer": true,
  "go.buildOnSave": "off",
  "go.lintOnSave": "off",
  "go.vetOnSave": "off",
}

Sublime Text

Here is a sample .sublime-project:

{
  "folders": [
    {
      "path": ".",
      "folder_exclude_patterns": ["bazel-*"]
    }
  ],
  "settings": {
    "lsp_format_on_save": true,
    "LSP": {
      "gopls": {
        "enabled": true,
        "command": ["~/go/bin/gopls"],
        "selector": "source.go",
        "settings": {
          "gopls.directoryFilters": [
            "-bazel-bin",
            "-bazel-out",
            "-bazel-testlogs",
            "-bazel-mypkg",
          ],
          "gopls.allowImplicitNetworkAccess": false,
          "gopls.usePlaceholders": true,
          "gopls.gofumpt": true,
          "gopls.local": "github.com/my/mypkg",
          "gopls.semanticTokens": true,
          "gopls.codelenses": {
            "gc_details": false,
            "regenerate_cgo": false,
            "generate": false,
            "test": false,
            "tidy": false,
            "upgrade_dependency": false,
            "vendor": false
          }
        },
        "env": {
          "GOPACKAGESDRIVER": "./tools/gopackagesdriver.sh"
        }
      }
    }
  }
}

Helix Editor

Here is a sample .helix/languages.toml:

[language-server.gopls.config]
env = { GOPACKAGESDRIVER = './tools/gopackagesdriver.sh' }
gofumpt     = true
staticcheck = true
local = "github.com/my/mypkg"
directoryFilters = ["-bazel-bin","-bazel-out","-bazel-testlogs","-bazel-mypkg"]
usePlaceholders = true
semanticTokens = true
codelenses = {gc_details=false, generate=false, regenerate_cgo=false, tidy=false, upgrade_dependency=false, vendor=false}

Environment variables

The package driver has a few environment configuration variables, although most won't need to configure them:

  • GOPACKAGESDRIVER_BAZEL: bazel binary, defaults to bazel
  • BUILD_WORKSPACE_DIRECTORY: directory of the bazel workspace (auto detected when using a launcher script because it invokes bazel run)
  • GOPACKAGESDRIVER_BAZEL_FLAGS which will be passed to bazel invocations
  • GOPACKAGESDRIVER_BAZEL_QUERY_FLAGS which will be passed to bazel query invocations
  • GOPACKAGESDRIVER_BAZEL_QUERY_SCOPE which specifies the scope for importpath queries (since gopls only issues file= queries, so use if you know what you're doing!)
  • GOPACKAGESDRIVER_BAZEL_BUILD_FLAGS which will be passed to bazel build invocations

Debugging

It is possible to debug driver issues by calling it directly and looking at the errors in the outputs:

$ echo {} | ./tools/gopackagesdriver.sh file=relative/path.go

Limitations

  • CGo completion may not work, but at least it's not explicitly supported.
  • Errors are not handled