-
Notifications
You must be signed in to change notification settings - Fork 275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove command package and command.Runner in favor of simpler and stateless execext package #3439
Conversation
The latest Buf updates on your PR. Results from workflow Buf CI / buf (pull_request).
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Went through this, seems reasonable to me! Took a super quick look in core, the impact seems minimal, but will see if others have thoughts on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such a nice cleanup to not have to pass around a Runner everywhere.
// If the user did not specify any stdin, we want to make sure | ||
// the command has access to none, as the default is the default stdin. | ||
if rs.stdin == nil { | ||
cmd.Stdin = discardReader{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason to prefer this over setting cmd.Stdin = nil
(which will have it read from os.DevNull)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No there's not - good catch and we could change this. I am virtually certain there was a reason, given what I did with stdout and stderr, perhaps os/exec changed the behavior of the default stdin at some point in the last couple of years? I don't know, but I'll confirm that this is true back to 1.22 and then change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was the case since at least 2014 it turns out.
I'm actually just going to keep this as-is, mostly because I'm terrified of changing it. I agree that there should be no difference to cmd.Stdin = nil
, but I am somewhat sure I did this for a reason, I can't remember it, and changing it really worries me.
I'm adding a code comment to this effect so that we don't touch this in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment for posterity:
// Note: This *should* be the same as just having cmd.Stdin = nil, given that
// exec.Cmd documents that Stdin has the same behavior as Stdout/Stderr, namely
// that os.DevNull is used. This has been the case for Stdin since at least 2014.
// However, way back when this package was first introduced, we set up the discardReader
// for some reason, and we can't remember why. We're terrified to change it, as there
// *may* have been some reason to do so. os.DevNull is actually just a string such
// as "/dev/null" on Unix systems, so how Golang actually handles this is somewhat
// unknown. Honestly, I might just want to change Stdout/Stderr to use a discardWriter.
This PR does a longstanding cleanup that has been on my local computer for a while and just needed finishing. This removes the
command
package in favor of a much-simplerexecext
package that wrapsos/exec
with the safety checks we care about.This gets rid of the stateful
command.Runner
type, which kept track of the number of running processes it created, and set a hard limit on these, usually based onthread
. This was overkill; in places where we perform parallelism, we already usethread.Parallelize
, and adding an additional semaphore to block withincommand
had no practical use. The downside was that we had to pass thecommand.Runner
type everywhere, which really cluttered our code, including in some important packages (such asdiff
) where the fact that we had to passcommand.Runner
exposed an ugly implementation detail.This also:
execext.WithEnv
(formerlycommand.RunWithEnv
) to take a[]string
instead of amap[string]string
, as[]string
is what the stdlib uses for environment variables. The practical effect for us (usingapp.EnvContainers
) is to useapp.Environ(container)
instead ofapp.EnvironMap(container)
when callingexecext.WithEnv
.RunStdout
, a convenience function that used aapp.EnvStdioContainer
to return the value of stdout as a byte slice. This depended on theapp
package, which is not in the stdlib, and on balance, it's nicer to haveexecext
just be stdlib-only as opposed to it depending on something custom. We only usedRunStdout
in a couple of places.The impact on core should be relatively minimal, as mostly the
command
package was just used to callcommand.NewRunner
for testing. However, the port is usually just this:command.NewRunner
calls.command.Runner
parameters.command.Runner.Run
calls withexecext.Run
.command.RunWith.*
withexecext.With
.[]string
instead ofmap[string]string
forexecext.WithEnv
, usually by replacingapp.EnvironMap(container)
withapp.Environ(container)
.