Skip to content
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

Issue 15276: Allow users to specify shell for executeShell, pipeShell, spawnShell #3900

Merged
merged 1 commit into from Jan 12, 2016
Merged

Conversation

markisaa
Copy link
Contributor

@markisaa markisaa commented Jan 4, 2016

This diff: This diff makes it possible to specify your preferred shell for the various *shell functions in std.process. By default it uses the new nativeShell function. nativeShell to always returns the native system shell (see the "some history" section for why this is the default value). I chose to create nativeShell rather than changeing userShell because I think it is still valuable to have something like userShell around in Phobos.

The one part of this diff I'm not super thrilled by is the use of variadic arguments (easier to see than to explain); if you have a suggestion for something better I'd love to hear it :).

Note: The default shell is a breaking change for Windows, which probably should have been broken same as posix in the diffs listed in the history section below, but I suspect was overlooked. Find rationale behind making a breaking change at all here: https://issues.dlang.org/show_bug.cgi?id=15000.

Some history:
a524a35
and
f537cb5

Tried to move us from a world where we preferred the shell specified in the SHELL environment variable to a world where we always went with the native system shell, /bin/sh for posix. The former of those revisions was reverted in:
5b2b1fb
Because the documentation was not updated to reflect the change.

Presently: we are in a state of schism, whereby userShell has behavior that does not align with what is actually used in executeShell, pipeShell, and spawnShell. This is something we must resolve.

Personal pain: This bit me when one of my scripts at work stopped working because it dependend on features that don't exist in sh (but do in bash, zsh, etc). It was really frustrating that there was no simple way to work around this and specify my preferred shell; it is, of course, possible to leverage the various escape* functions from std.process and spawnProcess to use whichever shell I prefer, but this seems like something warranting first class support. I was sad to not have something like this after a breaking change.

@dlang-bot
Copy link
Contributor

Fix Bugzilla Description
15276 Allow specification of shell for spawnShell/executeShell/pipeShell

Cmd commandLine,
const string[string] env = null,
Config config = Config.none,
size_t maxOutput = size_t.max,
in char[] workDir = null)
in char[] workDir = null,
TList values = TList.init)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default argument here is meaningless AFAICS.

I think the use of variadics makes sense since it's just forwarding a number of arguments to the generic pipeFunc. It would probably have taken me less time to understand if it was named something proper like ExtraArgs extraArgs though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default argument is unfortunately necessary because:

  1. This must be the very last argument in the function because it is an unknown quantity of optional arguments
  2. There are arguments before it that have default arguments; anything after an argument with a default value must also have a default value.

@JakobOvrum
Copy link
Member

Overall looks good to me.

…, spawnShell

This diff: This diff makes it possible to specify your preferred shell for the various `*shell` functions in `std.process`. By default it uses the new `nativeShell` function. `nativeShell` to always returns the native system shell (see the "some history" section for why this is the default value). I chose to create `nativeShell` rather than changeing `userShell` because I think it is still valuable to have something like `userShell` around in Phobos.

The one part of this diff I'm not super thrilled by is the use of variadic arguments (easier to see than to explain); if you have a suggestion for something better I'd love to hear it :).

Note: The default shell is a breaking change for Windows, which probably *should have* been broken same as posix in the diffs listed in the history section below, but I suspect was overlooked. Find rationale behind making a breaking change at all here: https://issues.dlang.org/show_bug.cgi?id=15000.

Some history:
a524a35
and
f537cb5

Tried to move us from a world where we preferred the shell specified in the SHELL environment variable to a world where we always went with the native system shell, /bin/sh for posix. The former of those revisions was reverted in:
5b2b1fb
Because the documentation was not updated to reflect the change.

Presently: we are in a state of schism, whereby `userShell` has behavior that does not align with what is actually used in `executeShell`, `pipeShell`, and `spawnShell`. This is something we *must* resolve.

Personal pain: This bit me when one of my scripts at work stopped working because it dependend on features that don't exist in `sh` (but do in `bash`, `zsh`, etc). It was really frustrating that there was no simple way to work around this and specify my preferred shell; it is, of course, possible to leverage the various `escape*` functions from `std.process` and `spawnProcess` to use whichever shell I prefer, but this seems like something warranting first class support. I was sad to not have something like this after a breaking change.
@markisaa
Copy link
Contributor Author

markisaa commented Jan 6, 2016

Thanks for the review @JakobOvrum :). Updated the diff to reflect your suggestions.

@andralex
Copy link
Member

Auto-merge toggled on

@andralex
Copy link
Member

thx!

andralex added a commit that referenced this pull request Jan 12, 2016
Issue 15276: Allow users to specify shell for executeShell, pipeShell, spawnShell
@andralex andralex merged commit 9284ee8 into dlang:master Jan 12, 2016
variable, if it exists and is non-empty. Otherwise, it returns
$(D "/bin/sh").
variable, if it exists and is non-empty. Otherwise, it returns the result of
$(LREF nativeShell).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment says "it returns the result of nativeShell," but the various shells are actually hard-coded in: any reason why? I'm preparing a PR for Android, any reason not to have the code below actually do what the comment says? If not, I'll make userShell call nativeShell, so we don't have the same list of shells duplicated in two methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to change.

@CyberShadow
Copy link
Member

I know I'm late with this, but I think this pull request should not have been merged. I kept thinking back on it since I learned about it, and just now formulated my thoughts on it.

Standard library modules which interface with the OS, such as std.process, attempt to fulfill the following needs:

  • Smooth out platform differences by providing a unified API that works reasonably similar on all platforms
  • Wrap system primitives into D ones, such as converting between C and D strings
  • Encapsulate common operations which would otherwise be cumbersome to do by hand

This PR doesn't fix any of the above problems.

Tried to move us from a world where we preferred the shell specified in the SHELL environment variable to a world where we always went with the native system shell, /bin/sh for posix.

Yes, the goal is to do what the C system call does. Anything else was broken. SHELL is for interactive shells, whereas system is specified to run /bin/sh.

Personal pain: This bit me when one of my scripts at work stopped working because it dependend on features that don't exist in sh (but do in bash, zsh, etc).

The breakage is unfortunate, but it also indicates incorrect code. Essentially, it means that your code depended on a user preference of the machine it's running on.

If your code needs to run commands with non-POSIX shell syntax, then you must explicitly specify the interpreter. And yes, this is what this PR is supposed to address. However...

it is, of course, possible to leverage the various escape* functions from std.process and spawnProcess to use whichever shell I prefer,

No escape* functions needed. The correct fix would be to change spawnShell(command) to spawnProcess(["/bin/bash", "-c", command]). This is hardly more complicated than spawnShell(command, "/bin/bash").

but this seems like something warranting first class support.

This is subjective, and I disagree.

I don't feel strongly about this though I would like to see the functionality added in this PR deprecated and removed, barring any mistakes in my understanding of the situation. The functions in this module have too many overloads and parameters already.

BTW, looking forward to automatic notification of when someone submits a PR against your code. I wish I was notified for this one...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
6 participants