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
std.process: Add workDir parameter #1928
Conversation
@@ -426,6 +435,9 @@ private Pid spawnProcessImpl(in char[][] args, | |||
if (stdoutFD > STDERR_FILENO) close(stdoutFD); | |||
if (stderrFD > STDERR_FILENO) close(stderrFD); | |||
|
|||
// Set the working directory. | |||
if (cwd) chdir(cwd); |
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.
I'm not sure about this change. If the chdir
fails, the exception will be thrown in the forked process. Even if we use the C function, we still need to communicate failure somehow to the original process. Checking for the directory's existence in the main process is out as it would be a race condition.
Just stumbled upon |
// We use open in the parent and fchdir in the child | ||
// so that most errors (directory doesn't exist, not a directory) | ||
// can be propagated as exceptions before forking. | ||
int cwdFD = 0; |
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.
It looks like this file descriptor can leak if some error occurs before the two calls to close
. Maybe refactor it in terms of a transaction, i.e. with scope(exit)
or similar?
Apart from the file descriptor leak that @JakobOvrum discovered, this looks good to me. It kind of sucks that we have to add another parameter when there are already so many, but I think it's worth it in this case. |
Not too happy about the |
Thanks! Addressed all concerns and rebased. |
} | ||
|
||
/// ditto | ||
Pid spawnProcess(in char[][] args, | ||
const string[string] env, | ||
Config config = Config.none) | ||
Config config = Config.none, | ||
string workDir = null) |
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.
Does it need the immutable guarantee? If not, in char[]
.
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.
Fixed! We convert the string to something else anyway, which involves a reallocation, so parameter constness doesn't matter.
LGTM. I like this solution, it looks quite robust. |
Agreed. However, since this is an API change, I'd like to wait a couple of days and see if @schveiguy has any comments before we merge it. |
Ping? @schveiguy ? |
2 things:
|
Looks good to me, not a breaking API change from what I can tell. One thing that is a little concerning, but not enough to cancel the pull request, is the ordering of the parameters is sort of random, and pretty much arbitrary. Wondering if having a variadic template at least for the last 3 arguments (which are independently typed) would be a useful way of allowing one to specify only the things you need. We already forward to an implementation function, this would just be for the wrappers. (not for this pull request, of course, but a different one). |
Auto-merge toggled on |
All right, since we all agree, I've scheduled this for an auto merge.
Maybe not a bad idea. I can't recall seeing this design used anywhere else in Phobos, though. (This is one of the very few times I've wished we had named parameters in D.) |
As already mentioned in this thread, |
Oh, you're right. That's what happens when a conversation stretches out over several weeks – I forget what was said in the beginning. ;-) |
I think it's a decent idea when functions get out of control with parameters and each parameter can be identified by its type. Tango worked around this by creating an object and then using methods to configure it before calling the execute method, but not an option here. |
However, if we go with that design, we're in trouble if we later want to add another I guess we could look at process creation modules in other languages and libraries—Python, Qt, Tango, Win32, etc.—and make an exhaustive list of all possible parameters we might ever want to add to |
Good point. Maybe we should hold off on that idea then. |
std.process: Add workDir parameter
https://d.puremagic.com/issues/show_bug.cgi?id=11363
Sometimes, it is useful to create a new process with a working directory different from the parent process. For example,
git submodule
andgit bisect
insist on being run from the repository root.This currently cannot be done in a nice way when using std.process:
"cd " ~ escapeShellFilename(cwd) ~ " && "
, this requires spawning a shell, which has a non-negligible performance cost on Windows.This change adds yet another default parameter to the overloads of the 6 relevant functions. I don't see a better way without e.g. replacing the overloads with a function that takes a tuple and looking at each argument's types, similar to what
std.socket.getAddressInfo
does.