modfetch: select the requested module among multiple go: downloading lines - #167
Conversation
…` lines When `go get <mod>@<ver>` targets a module that lives in a multi-module repository, `go` downloads the parent module as well and prints one `go: downloading ...` line per module. Their order is not deterministic. `getResult` previously returned the first line unconditionally, so it could return the parent module path (e.g. `github.com/llarhub/libcxx`) instead of the requested submodule (`github.com/llarhub/libcxx/c`). Downstream callers such as llcppg then resolved the wrong module cache directory, which failed intermittently depending on the download order and cache state. Scan all `go: downloading` lines and prefer the one whose module path matches the requested module, falling back to the first line to preserve the existing single-module behavior. Fixes goplus/llcppg#867
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #167 +/- ##
==========================================
- Coverage 81.34% 81.23% -0.12%
==========================================
Files 10 10
Lines 906 906
==========================================
- Hits 737 736 -1
- Misses 150 151 +1
Partials 19 19 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Review: fix modfetch multi-module Get
The change is a correct, well-targeted fix. It replaces "parse the first go: downloading line" with "prefer the line whose module path exactly matches the requested one, else fall back to the first line" — the right fix for go get's non-deterministic ordering of downloading lines in multi-module repositories. The exact-match comparison avoids the substring/prefix pitfall, and the fallback preserves the prior single-module behavior. Tests cover both orderings, the fallback, empty reqPath, and the not-found path; they pass locally.
A few minor, non-blocking notes below. Nothing here needs to block merge.
- Silent fallback on path-format mismatch.
getResultselects only on exact equalitym.Path == reqPath, wherereqPathcomes from stripping@versionoff the caller'smodPath. Ifgoever prints the path in a form that isn't byte-identical toreqPath(e.g. a/vNmajor-version subdir), the match fails and the code silently falls back to the first line — i.e. the parent-module bug this PR fixes, in a narrower case. The eventualgetFromCache(modPath)re-validates against the original path, so blast radius is limited, but worth confirmingreqPathis guaranteed identical to whatgo getprints. - Dead
nextparameter ongetMod. After this change the sole caller always passesnil, so theif next != nilbranch is now unreachable. Consider dropping the parameter (separate cleanup) sincegetModis only called here.
| } | ||
| if found { | ||
| mod = first | ||
| fmt.Fprintln(os.Stderr, "xgo: downloading", mod.Path, mod.Version) |
There was a problem hiding this comment.
The success fmt.Fprintln(os.Stderr, "xgo: downloading", ...) is duplicated on both the exact-match path (line 234) and this fallback path. Since both set mod and return, you could set mod in the loop/fallback and emit a single Fprintln after the branch, removing the duplication.
There was a problem hiding this comment.
Done
Hoisted the fmt.Fprintln call out of both the exact-match and fallback branches into a single call after the if/fallback block.
Changes:
- Removed the duplicate
fmt.Fprintlnfrom line 234 (exact-match path) and line 240 (fallback path) - Both paths now set
modand break/fall-through to a singlefmt.Fprintlnat line 244
Verified:
go test ./modfetch/passes (all 4 test cases)go build ./...passes
Commit: 8c7bdf5
Remove duplication by setting mod in both the exact-match and fallback paths, then emitting a single fmt.Fprintln after the branch.
Problem
modfetch.Get(modPath)intermittently returns the wrong module for a submodule of a multi-module repository.When
go get <mod>@<ver>targets a module that lives in a multi-module repository,goalso downloads the parent module and prints onego: downloading ...line per module. The order of these lines is not deterministic.getResultpreviously took the first line unconditionally.Reproduction for
github.com/llarhub/libcxx/c@v0.1.1(bothgithub.com/llarhub/libcxxandgithub.com/llarhub/libcxx/care separate modules):When the parent line comes first,
getResultreturnsgithub.com/llarhub/libcxx(the/csuffix is dropped). Downstream callers such as llcppg then resolve the wrong module-cache include directory, which causes an intermittent failure (panic: todo: toType int64_tin goplus/llcppg#867).The order was confirmed non-deterministic across repeated clean-cache runs (parent-first on some runs, child-first on others).
Fix
Scan all
go: downloadinglines and prefer the one whose module path exactly matches the requested module. Fall back to the first line when there is no exact match, preserving the existing single-module behavior.Getpasses the version-stripped requested path down togetResult.Verification
getResult) cover both download orderings, the fallback path, and the not-found case.modfetch.Get("github.com/llarhub/libcxx/c@v0.1.1")now returnsgithub.com/llarhub/libcxx/cin both a fresh cache and a parent-already-cached cache.go build ./...andgo test ./modfetch/pass.Fixes goplus/llcppg#867