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

ChildProcess::LaunchError when running bundle <anything> #59

Closed
Ajedi32 opened this issue Aug 14, 2013 · 12 comments
Closed

ChildProcess::LaunchError when running bundle <anything> #59

Ajedi32 opened this issue Aug 14, 2013 · 12 comments

Comments

@Ajedi32
Copy link

Ajedi32 commented Aug 14, 2013

For some reason, I'm getting the following error whenever I try to run bundle with ChildProcess:

irb(main):001:0> require 'childprocess'
=> true
irb(main):002:0> ChildProcess.build(*%w[bundle --help]).tap{|ps| ps.io.inherit! }.start
ChildProcess::LaunchError: Unknown error (Windows says "The operation completed successfully.", but it did not.)
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/childprocess-0.3.9/lib/childprocess/windows/process_builder.rb:87:in `create_process'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/childprocess-0.3.9/lib/childprocess/windows/process_builder.rb:34:in `start'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/childprocess-0.3.9/lib/childprocess/windows/process.rb:63:in `launch_process'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/childprocess-0.3.9/lib/childprocess/abstract_process.rb:72:in `start'
        from (irb):2
        from c:/RailsInstaller/Ruby1.9.3/bin/irb:12:in `<main>'

That error message isn't very helpful. So Windows is saying that everything's fine but you say Windows is lying because... why?

Open3 has no problem running the bundle command:

irb(main):001:0> require 'open3'
=> true
irb(main):002:0> sin, sout, serr, thread = Open3.popen3(*%w[bundle --help])
=> [#<IO:fd 4>, #<IO:fd 5>, #<IO:fd 7>, #<Thread:0x14bff98 run>]
irb(main):003:0> puts sout.read
<output of bundle --help is displayed here>
=> nil
@jarib
Copy link
Collaborator

jarib commented Aug 14, 2013

The error message isn't helpful because Windows is giving us conflicting information.

From the docs for CreateProcess:

If the function fails, the return value is zero. To get extended error information, call GetLastError.

In your case, CreateProcess returns zero, but GetLastError thinks "the operation completed successfully". I have not been able to track down what could cause this to happen.

@Ajedi32
Copy link
Author

Ajedi32 commented Aug 15, 2013

Yeah, I figured it was something weird like that.

In my case though I'm curious about why the command is failing at all. As I said, Open3 has no problem spawning the exact same process, so why is ChildProcess failing? Odd...

@AcidWeb
Copy link

AcidWeb commented Oct 1, 2013

Same issue. Windows 8.1 and Ruby 2.0.0-p247. Any workaround is available?

@rarenerd
Copy link

rarenerd commented Dec 4, 2013

What seems to work for me is adding "cmd.exe /c" in front of it. I'm guessing this is because you are actually calling a .bat file and according to the docs:

To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following arguments: /c plus the name of the batch file.

Now lpApplicationName is set to NULL here: https://github.com/jarib/childprocess/blob/master/lib/childprocess/windows/process_builder.rb#L75

However it seems that just adding it to lpCommandLine does the same trick.

@jarib
Copy link
Collaborator

jarib commented Jan 6, 2014

@rarenerd Indeed - CreateProcess won't execute batch files directly. Both of these seem to solve the problem:

ChildProcess.build("ruby", "-S", "bundle")
ChildProcess.build("cmd.exe", "/c", "bundle")

@jarib jarib closed this as completed Jan 6, 2014
@Ajedi32
Copy link
Author

Ajedi32 commented Jan 6, 2014

So is there any way that ChildProcess could be made to detect batch files and automatically run them using an interpreter? Would that be desirable behavior? If not, ChildProcess's inability to run batch files directly on Windows is probably something that should be documented. Either way, I'm not sure this issue should be closed just yet.

@jarib
Copy link
Collaborator

jarib commented Jan 6, 2014

I'm very reluctant to customize behaviour depending on what type of file is being executed. This is also consistent with what we already do on Unix - if you want to have your command interpreted, you need to explicitly run the shell yourself

ChildProcess.build("bash", "-c", "echo *")
# vs.
ChildProcess.build("echo", "*")

This is deliberately in contrast to Kernel#exec's default behaviour.

I'd be happy to accept a pull requests that documents the Windows workaround though.

@Ajedi32
Copy link
Author

Ajedi32 commented Jan 6, 2014

I'm confused. If this is consistent with how Unix does things, then why is the exact same command that works on Unix failing on Windows? Is it just because Windows ignores the hash bang at the start of the file whereas Unix uses that information?

If that's the case, couldn't ChildProcess somehow emulate that behavior to bring Windows more in line with the way Unix does things? I'd really prefer to avoid having to write a special case Windows if I can help it.

@jarib
Copy link
Collaborator

jarib commented Jan 7, 2014

I didn't claim it is consistent with "how Unix does things", but that ChildProcess is consistent in the decision not to execute commands through a command-line interpreter on either platform.

Even if you consider that moot, I can't imagine what a satisfactory heuristic to detect when to execute in cmd.exe would look like – which I think indicates it's better to leave the decision to the user.

If you know you always want cmd.exe on Windows, it's fairly simple to do:

def create_process(*cmd)
  cmd.unshift("cmd.exe", "/c") if ChildProcess.windows?
  ChildProcess.build(*cmd)
end

@Ajedi32
Copy link
Author

Ajedi32 commented Jan 7, 2014

Hmm, yeah I think I see what you're saying. Obviously you don't want to interpret any shell commands passed to ChildProcess.build, you just want to execute the batch file using the desired arguments.

Is there a reason though that we can't just use the hash-bang in the first line of a file to determine whether or not to invoke an interpreter? That's what Unix does, right? Although, usually the paths to the interpreters used in hash-bang lines are very Unix-specific, so maybe that wouldn't work...

@Ajedi32
Copy link
Author

Ajedi32 commented Jan 7, 2014

Hold on a second! How does Open3 resolve this problem? As shown in the example in my original post, Open3.popen3 works fine, and I'm pretty sure Open3 doesn't invoke cmd.exe for every command I run with it. Open3 also has the same behavior as ChildProcess in that it passes the arguments listed in the method call directly to the spawned process without interpreting them as shell commands. So what are they doing that we've missed?

@jarib
Copy link
Collaborator

jarib commented Jan 7, 2014

Open3 uses Process.spawn under the hood. You'll have to dig through the C source to figure out how it decides to invoke the shell.

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

No branches or pull requests

4 participants