Skip to content

feat(golangci): use gnopls as GOPACKAGESDRIVER when available#190

Open
notJoon wants to merge 1 commit intomainfrom
feat/gnopls-driver
Open

feat(golangci): use gnopls as GOPACKAGESDRIVER when available#190
notJoon wants to merge 1 commit intomainfrom
feat/gnopls-driver

Conversation

@notJoon
Copy link
Copy Markdown
Member

@notJoon notJoon commented Apr 27, 2026

Summary

  • Auto-wire gnopls as the go/packages external driver (GOPACKAGESDRIVER) when both gnopls is on PATH and GNOROOT is set, so golangci-lint can analyze .gno packages whose imports include gno.land/....
  • Without this wiring the stock Go loader fails to resolve those imports and golangci-lint exits with empty stdout. The previous fix absorbs that as a silent fallback, so environments lacking gnopls or GNOROOT see no behavioral change.
  • GOPACKAGESDRIVER accepts a single executable path; write a per-pid shim (#!/bin/sh\nexec <gnopls> resolve "$@" on unix, .cmd variant on Windows) into the OS temp dir on first use and let the OS reclaim it.
  • Cache PATH lookup, shim creation, and the os.Environ() snapshot once per process so the addition is a single atomic load on the per-file hot path.

Background

gnopls implements the go/packages external-driver protocol: its gnopls resolve subcommand walks $GNOROOT/gnovm/stdlibs and $GNOROOT/examples/, parses each directory's gnomod.toml, and serves a fully populated package graph back to any go/packages.Load caller (which golangci-lint uses internally). Setting GOPACKAGESDRIVER to the gnopls shim is enough — no golangci-lint fork needed.

Test plan

  • go build ./...
  • make test — race + shuffle clean
  • Bench: go test -bench=BenchmarkRun -benchmem -run=^$ -benchtime=10x -count=3 ./internal/ matches main to within ±0.1% on B/op and allocs/op
  • TestGnoDriverEnv — five subtests covering all detection branches via injected lookPath/getenv/ensureShim
  • TestWriteGnoplsShim_{Unix,Windows,FailsOnUnwritableDir} — script body, mode bits, error path
  • Manual: with gnopls on PATH and GNOROOT exported, run tlin . against a .gno package and confirm golangci-lint issues now surface
  • Manual: without gnopls, confirm fallback (no errors, no per-file warnings)

Notes

  • Shim is left in os.TempDir() after the process exits — relies on OS-level temp cleanup. Per-pid filename avoids collisions.
  • Fallback is silent: callers see nil env from cachedDriverEnv and golangci-lint runs without a custom driver, which the prior fix already handles.

Detect gnopls on PATH and require GNOROOT in the environment, then
point golangci-lint at gnopls via a once-written shim script so
go/packages can resolve gno.land/... imports. Without this wiring
the standard Go loader fails for pure-gno packages and golangci-lint
exits with empty stdout — the previous commit absorbs that as a
silent fallback, so an environment lacking either gnopls or GNOROOT
keeps the same behavior as before.

GOPACKAGESDRIVER takes a single executable path, which means
"gnopls resolve" needs a wrapper. Write a per-pid shim into the OS
temp dir on first use and let the OS reclaim it; ship a Windows
.cmd variant alongside the unix sh script. Cache the resulting
subprocess env so PATH lookup, shim creation, and the os.Environ()
snapshot run once per process instead of per CheckPackage call.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant