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

chdir support #16

Closed
mitchellh opened this issue Nov 6, 2011 · 6 comments
Closed

chdir support #16

mitchellh opened this issue Nov 6, 2011 · 6 comments

Comments

@mitchellh
Copy link
Contributor

Hello,

I realize this is possible to build on top of childprocess but is something so common when creating child processes that I think childprocess itself should build in support for chdir.

I haven't used childprocess very long so I'm not entirely sure what the API would look like, but this is very important for me. If I begin to use childprocess more heavily I'll investigate adding this myself, but that may not be for some time.

Thanks,
Mitchell

@jarib
Copy link
Collaborator

jarib commented Nov 6, 2011

Can you explain the use case a bit better? I'd like to not bloat the API by adding stuff that can easily be done cross-platform through other means, which is what Dir.chdir provides.

@mitchellh
Copy link
Contributor Author

Certainly. I agree and can empathize with you on avoiding API bloat of a good library. Dir.chdir is cross-platform, but forking a child process isn't, and doing both at once cross-platform gets very difficult quickly.

First, a general use case: You want to execute some program that creates/uses files based on the current working directory, which is not the same as the CWD you invoked your application from. This requires a Dir.chdir at some point.

A more specific use case, in my case: I am writing a suite of acceptance tests for a command-line application (Vagrant), which by default uses the CWD for many things. Of course, I can use environmental variables to tell Vagrant to look in other places, but I'd also like to test that when it does use the CWD, it does it correctly. I'm currently using posix-spawn because it makes specifying chdir easy as well as working with child processes. Unfortunately, I'd love to be able to run these acceptance tests on Windows machines as well, so posix-spawn isn't a long term solution.

Now, let's look at how we would do this using childprocess in its current form: Since childprocess doesn't support chdir, I would actually need to execute another application which does a chdir, which then executes ANOTHER child process (via whatever means) to get that chdir. The end-developer complexity gets very high for such a simple thing. The easiest thing to do obviously would be for the first Ruby process to call fork then Dir.chdir but of course, fork doesn't work on Windows.

Let's see how childprocess would do it if it were built in. Note I am not familiar with Windows APIs so I'm not sure how it would work there. But on Unix: The childprocess module would simply do a fork, Dir.chdir, then an exec. Easy. On Windows, where fork doesn't exist, it would do whatever is necessary to set the Dir.chdir prior to creating the subprocess. May not be easy for the childprocess dev (sorry!) but it makes it easy for the end user.

So, in conclusion:

Yes, Dir.chdir is cross platform. Doing this as a one-time go within your app is easy.

But, Dir.chdir for only a child process is a nightmare, and I think something like childprocess can make this easy.

Thanks for your time, as always, and I hope this makes sense. Please let me know if it doesn't.

Best,
Mitchell

@jarib
Copy link
Collaborator

jarib commented Nov 6, 2011

Thanks for the explanation. I still don't quite get this part:

Since childprocess doesn't support chdir, I would actually need to execute another application which does a chdir, which then executes ANOTHER child process (via whatever means) to get that chdir. The end-developer complexity gets very high for such a simple thing.

This appears to work well (on both *nix and Windows) and doesn't seem overly complex to me:

process = Dir.chdir(Dir.tmpdir) do
  ChildProcess.build(
    "ruby", "-rfileutils", "-e", "FileUtils.touch 'hello'"
  ).start
end

process.poll_for_exit(1)

p File.exists?(File.join(Dir.tmpdir, 'hello')) #=> true

That is, no launching of two separate processes just to do a chdir. Have you considered this option? Is the problem that you want to call #start from code that shouldn't know about what directory the child should execute in? That's the only reason I can think of where doing the above would be inconvenient.

This would be a pretty simple change, regardless of platform - it's basically just moving a piece of state (the directory name) out of the user's hands and into childprocess, then executing Dir.chdir right before we launch the process (instead of having the user do the same). Since it's so simple to do, I just want to make sure you haven't considered this option :)

PS. You might want to check out Aruba which is built on childprocess and makes CLI acceptance testing pretty simple (though perhaps too simple for Vagrant).

@mitchellh
Copy link
Contributor Author

Jarib,

Ah hah, I wasn't aware of block passing to Dir.chdir.

This indeed solves all problems I'm aware of. Closing this issue!

As for Aruba, that is where I found out about childprocess :) I still need to investigate aruba more, although I have a distinct opinion against anything related to cucumber (I hate cucumber), so that is tarnishing my view of it right now. ;)

Mitchell

@jarib
Copy link
Collaborator

jarib commented Nov 6, 2011

Glad to have helped :) And thanks for Vagrant!

@mitchellh
Copy link
Contributor Author

Thanks :)

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

No branches or pull requests

2 participants