fix(tool): forward -C flag directory to package loading#518
Conversation
|
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #518 +/- ##
=========================================
+ Coverage 0 63.28% +63.28%
=========================================
Files 0 62 +62
Lines 0 4827 +4827
=========================================
+ Hits 0 3055 +3055
- Misses 0 1519 +1519
- Partials 0 253 +253
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
y1yang0
left a comment
There was a problem hiding this comment.
LGTM, this is surprisingly clean and elegant. Please also add an integration test
There was a problem hiding this comment.
This currently does not work:
otelc go build -C ./somedirbecause we pass -C after -a -x -n inside listBuildPlan.
From the debug log:
new="[go build -a -x -n -C ./somedir]"
But go requires -C to appear before build flags/packages, so this becomes invalid.
Would it be simpler to consume the -C flag early and just chdir into it at command start (with a deferred restore of the original cwd)?
@Pulkit7070 concerns of @amazingakai needs to be addressed here. |
|
Thanks for the thorough reviews. Both points are well-taken and I've addressed them in the latest push. @amazingakai - you're right that the @y1yang0 - Let me know if anything looks off - happy to iterate. |
|
I merged #468 (first come, first served). This needs another rebase. And let's wait for @amazingakai's review. |
c08fc9e to
45e23f1
Compare
|
Rebased on main. Also squashed the messy history (reverts, CLA retriggers, merge commit) down to a single clean commit. |
081cf15 to
d941a94
Compare
|
But why not fix listBuildPlan by inserting -C after go build to solve this problem? |
|
Good question. Fixing listBuildPlan alone is not sufficient because the -C flag affects two independent layers:
To cover both with the cfg.Dir approach, we would need to thread the extracted dir value into every packages.Config construction, not just listBuildPlan. os.Chdir handles both layers with a single change: the process working directory shifts, so go/packages resolves correctly and the dry-run subprocess inherits the same cwd. consumeCFlag strips -C from args so listBuildPlan never sees it and the subprocess flag ordering stays valid. Also, amazingakai explicitly suggested the os.Chdir approach in their CHANGES_REQUESTED review, which is still open. Happy to switch if you and amazingakai align on the listBuildPlan approach instead. |
|
But if we are to use os.chdir directly, we would essentially need to mirror the behavior of the Go toolchain as implemented here: https://github.com/golang/go/blob/03d1f8efc82678bba84d5e50d9144cfc6847a1f9/src/cmd/go/main.go#L383 |
|
You are right. Go's handleChdirFlag is strictly positional - it only looks for -C at the argument immediately after the subcommand, and removes it from os.Args so a reinvoked child toolchain does not process it again. Our consumeCFlag scans the full arg list, which does not match those semantics. Given this, I think the cleaner fix is the one you originally suggested: fix listBuildPlan to insert -C dir right after go build, and set cfg.Dir on the packages.Config. No process-global chdir, no positional constraint to enforce, and the behavior is explicit at each call site. Would you and @amazingakai prefer we switch to that approach? Happy to implement it - just want both reviewers to align before we push another redesign. |
|
Apologies for any confusion. I'd like to clarify my thought process. Initially, it seemed to me that both potential fixes were reasonable:
However, after reviewing the Go toolchain's source code, I see its logic is essentially to consume the -C flag and then call os.Chdir. This strongly suggests that the first approach is indeed the more correct and idiomatic one. I'm leaning this way now. Do other reviewers have any further thoughts on this? |
|
Thanks for the clarification. Agreed - Go's own toolchain doing os.Chdir is a strong signal that it is the right approach. The one remaining gap in our current implementation: our consumeCFlag scans the entire args list for -C, but Go's handleChdirFlag only looks for it at the specific position right after the subcommand. We should tighten that to match Go's positional semantics before merging. Waiting on @amazingakai to weigh in, then we will implement with that correction. |
|
@Pulkit7070 I think it completely makes sense to match go's behavior here. We should consume -C only if it appears as the first argument after otelc go build/install or otelc setup. Also, after looking at the go toolchain's code I realized we don't need to restore to the original directory with defer, changing the process' dir doesn't change the shell's dir, so restoring to the original dir would do nothing here. Also, something probably went wrong with the rebase here, this PR is undoing some changes I did in #468 and also removing some unrelated comments. Please fix those. |
Extract -C only when it appears as the first argument after the subcommand (consumeCFlagPositional), matching Go toolchain semantics from handleChdirFlag. Call os.Chdir to shift the process working directory so both go/packages resolution and the listBuildPlan dry-run operate from the target directory. No defer restore needed: os.Chdir does not affect the parent shell.
d941a94 to
2b31701
Compare
|
Done. Three things addressed in the latest push:
|
amazingakai
left a comment
There was a problem hiding this comment.
We also require consumeCFlagPositional in GoBuild, otherwise the build fails, but this could be a little tricky.
We have to handle the following cases:
otelc setup -C ...-- already handledotelc go build -C ...-- after consuming the -C flag we also have to trim it from the args. We might need to change the signature of Setup a little here and accept args + flags instead of cmd. @y1yang0, would appreciate your opinion here as well.go buildalso supports bothgo -C ./dir buildandgo build -C ./dir,so we have to check both cases and allow -C to appear immediately before or after the build/install arg.
| if strings.HasPrefix(args[0], "-C=") { | ||
| return strings.TrimPrefix(args[0], "-C="), args[1:] | ||
| } | ||
| if args[0] == "-C" && len(args) > 1 { | ||
| return args[1], args[2:] | ||
| } |
There was a problem hiding this comment.
|
Good catch. Tracing through the two cases: go build -C dir ./...: cmd.Args().Tail() = [-C, dir, ./...], consumeCFlagPositional picks it up at position 0 - already handled. go -C dir build ./...: GoBuild fails immediately at the cmd.Args().First() != "build" check before Setup is even called. And even if we fixed that, Setup does cmd.Args().Tail() which gives ["dir", "build", "./..."] - the -C is gone. The fix needs to happen in GoBuild before any arg inspection. Since cmd cannot be mutated, the cleanest path is the one you suggested: change Setup to accept an explicit args slice instead of cmd, so GoBuild can pre-process -C in both positions, chdir, strip it, then pass the cleaned args down. Rough shape: consumeCFlagFromArgs would check position 0 for -C (before subcommand) and also position 1 for the go build -C case after subcommand trimming. Does this match what you had in mind? Happy to implement once you and @y1yang0 agree on the shape. |
…uences Literal newlines inside double-quoted Go strings are a syntax error. Replace them with \n escape sequences in TestGetPackagesWithCFlag. Signed-off-by: Pulkit Saraf <prateeksaraf9@gmail.com>
Problem
otelc go build -C <dir>does not respect the-Cflag. Package patterns like.or./...are resolved against the process working directory instead of<dir>becausepackages.Config.Dirwas never set.Steps to reproduce:
/some/dirotelc go build -C /some/dir ./...from a different directoryFixes #507
Solution
Add
LoadPackagesInDirto thepkgloadpackage. It accepts an explicitdirstring and setspackages.Config.Dir, sogo/packagesresolves patterns relative to that directory.In
getBuildPackages, extract the-Cflag value from the build args using the newextractFlagValuehelper and forward it to everyLoadPackagesInDircall.Existing callers (
ResolvePackageName,ResolveExportFiles) continue to useLoadPackages, which delegates toLoadPackagesInDirwith an empty dir.Changes
tool/internal/pkgload/pkgload.go: addLoadPackagesInDir(ctx, dir, mode, buildFlags, patterns...).LoadPackagesis a thin wrapper passing empty dir.tool/internal/setup/setup.go: addextractFlagValuehelper; updategetBuildPackagesto extract-Cand pass it toLoadPackagesInDir.