childprocess 0.9.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.document +6 -6
  3. data/.gitignore +28 -28
  4. data/.rspec +1 -1
  5. data/.travis.yml +51 -44
  6. data/CHANGELOG.md +61 -49
  7. data/Gemfile +18 -15
  8. data/LICENSE +20 -20
  9. data/README.md +212 -196
  10. data/Rakefile +61 -61
  11. data/appveyor.yml +54 -60
  12. data/childprocess.gemspec +30 -30
  13. data/ext/mkrf_conf.rb +24 -0
  14. data/lib/childprocess.rb +210 -205
  15. data/lib/childprocess/abstract_io.rb +36 -36
  16. data/lib/childprocess/abstract_process.rb +192 -192
  17. data/lib/childprocess/errors.rb +37 -26
  18. data/lib/childprocess/jruby.rb +56 -56
  19. data/lib/childprocess/jruby/io.rb +16 -16
  20. data/lib/childprocess/jruby/process.rb +184 -159
  21. data/lib/childprocess/jruby/pump.rb +53 -53
  22. data/lib/childprocess/tools/generator.rb +145 -145
  23. data/lib/childprocess/unix.rb +9 -9
  24. data/lib/childprocess/unix/fork_exec_process.rb +70 -70
  25. data/lib/childprocess/unix/io.rb +21 -21
  26. data/lib/childprocess/unix/lib.rb +186 -186
  27. data/lib/childprocess/unix/platform/i386-linux.rb +12 -12
  28. data/lib/childprocess/unix/platform/i386-solaris.rb +11 -11
  29. data/lib/childprocess/unix/platform/x86_64-linux.rb +12 -12
  30. data/lib/childprocess/unix/platform/x86_64-macosx.rb +11 -11
  31. data/lib/childprocess/unix/posix_spawn_process.rb +134 -134
  32. data/lib/childprocess/unix/process.rb +89 -89
  33. data/lib/childprocess/version.rb +3 -3
  34. data/lib/childprocess/windows.rb +33 -33
  35. data/lib/childprocess/windows/handle.rb +91 -91
  36. data/lib/childprocess/windows/io.rb +25 -25
  37. data/lib/childprocess/windows/lib.rb +416 -416
  38. data/lib/childprocess/windows/process.rb +130 -130
  39. data/lib/childprocess/windows/process_builder.rb +178 -175
  40. data/lib/childprocess/windows/structs.rb +148 -148
  41. data/spec/abstract_io_spec.rb +12 -12
  42. data/spec/childprocess_spec.rb +447 -422
  43. data/spec/get_env.ps1 +13 -0
  44. data/spec/io_spec.rb +228 -228
  45. data/spec/jruby_spec.rb +24 -24
  46. data/spec/pid_behavior.rb +12 -12
  47. data/spec/platform_detection_spec.rb +86 -86
  48. data/spec/spec_helper.rb +270 -261
  49. data/spec/unix_spec.rb +57 -57
  50. data/spec/windows_spec.rb +23 -23
  51. metadata +17 -31
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f7bcd4a74bf8315015b61ff4a5dcf5774fec372
4
- data.tar.gz: ebb386c0ffd4b05121cbc8c3f18ded1d8721552b
3
+ metadata.gz: 44f5b503e0f1a8763a429eac6f2b36a7cea4ac94
4
+ data.tar.gz: f2158bcb16256e0f2179df5ca8a012ffa4ca4a6d
5
5
  SHA512:
6
- metadata.gz: 264821e0ea3147f6d19f63d76f5e290462e0ae8991d6858839b949a470f8ef173b716f5000f24fdfe9b86446eab1da593e7ad81e7cac83880fa7af81e7441563
7
- data.tar.gz: 26f5534f0cb73ad3482e513706ca7a53d87c7f610efeaf09f64f0c4205b293db565548c097290d27a4b49a2b831f9593edbfc4cf7c0da73903d05c1c3fd98b23
6
+ metadata.gz: 04b3c2c4cd1ba2e1915f655ecc516b8c73ca9757373717174fbe7fd963e2bd19ac90ff4cffd9993e07db1b0165428e6bcbf4e23c4d46d147f33bf7d2add80955
7
+ data.tar.gz: 96bdbc109a5314f299eb1daf2064fb585b24224a91969e70bec1f9bd5d4460a88b95533121c45bddf989fbd13ac4d0109967b4afc55b88156cd72e447bf49f11
data/.document CHANGED
@@ -1,6 +1,6 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- -
6
- LICENSE
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ -
6
+ LICENSE
data/.gitignore CHANGED
@@ -1,28 +1,28 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## RubyMine
17
- .idea/*
18
-
19
- ## PROJECT::GENERAL
20
- coverage
21
- rdoc
22
- pkg
23
- .rbx
24
- Gemfile.lock
25
- .ruby-version
26
- .bundle
27
-
28
- ## PROJECT::SPECIFIC
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## RubyMine
17
+ .idea/*
18
+
19
+ ## PROJECT::GENERAL
20
+ coverage
21
+ rdoc
22
+ pkg
23
+ .rbx
24
+ Gemfile.lock
25
+ .ruby-version
26
+ .bundle
27
+
28
+ ## PROJECT::SPECIFIC
data/.rspec CHANGED
@@ -1 +1 @@
1
- --color
1
+ --color
@@ -1,44 +1,51 @@
1
- os:
2
- - linux
3
- - osx
4
-
5
- rvm:
6
- - 1.9.3
7
- - jruby-9.1.9.0
8
- - rbx-3
9
- - 2.0.0
10
- - 2.1
11
- - 2.2
12
- - 2.3
13
- - 2.4
14
- - 2.5
15
- - ruby-head
16
-
17
- sudo: true # Necessary to fix JRuby
18
-
19
- cache: bundler
20
-
21
- before_install:
22
- - "echo 'gem: --no-document' > ~/.gemrc"
23
- - gem update --system
24
- - gem install bundler # Necessary to fix 1.9.3
25
-
26
- env:
27
- global:
28
- matrix:
29
- - CHILDPROCESS_POSIX_SPAWN=true CHILDPROCESS_UNSET=should-be-unset
30
- - CHILDPROCESS_POSIX_SPAWN=false CHILDPROCESS_UNSET=should-be-unset
31
-
32
- matrix:
33
- allow_failures:
34
- - rvm: rbx-3
35
- - rvm: jruby-9.1.9.0
36
- - rvm: ruby-head
37
- - env: "CHILDPROCESS_POSIX_SPAWN=true"
38
- exclude:
39
- # Travis does not provide 1.9.3 on OSX
40
- - rvm: 1.9.3
41
- os: osx
42
- # Travis does not provide 2.0.0 on it latest version of OSX
43
- - rvm: 2.0.0
44
- os: osx
1
+ os:
2
+ - linux
3
+ - osx
4
+
5
+ rvm:
6
+ - jruby-9.1.9.0
7
+ - rbx-3
8
+ - 2.0.0
9
+ - 2.1
10
+ - 2.2
11
+ - 2.3
12
+ - 2.4
13
+ - 2.5
14
+ - ruby-head
15
+
16
+ sudo: false
17
+
18
+ cache: bundler
19
+
20
+ before_install:
21
+ - "echo 'gem: --no-document' > ~/.gemrc"
22
+ # RubyGems update is supported for Ruby 2.3 and later
23
+ - ruby -e "system('gem update --system') if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3')"
24
+ - gem install bundler --version '~> 1.17'
25
+
26
+ before_script:
27
+ - 'export JAVA_OPTS="${JAVA_OPTS_FOR_SPECS}"'
28
+
29
+ env:
30
+ global:
31
+ matrix:
32
+ - CHILDPROCESS_POSIX_SPAWN=true CHILDPROCESS_UNSET=should-be-unset
33
+ - CHILDPROCESS_POSIX_SPAWN=false CHILDPROCESS_UNSET=should-be-unset
34
+
35
+ matrix:
36
+ allow_failures:
37
+ - rvm: rbx-3
38
+ - rvm: jruby-9.1.9.0
39
+ - rvm: ruby-head
40
+ - env: "CHILDPROCESS_POSIX_SPAWN=true"
41
+ include:
42
+ - rvm: jruby-9.2.5.0
43
+ jdk: openjdk11
44
+ env: "JAVA_OPTS_FOR_SPECS='--add-opens java.base/java.io=org.jruby.dist --add-opens java.base/sun.nio.ch=org.jruby.dist'"
45
+ exclude:
46
+ # Travis does not provide 1.9.3 on OSX
47
+ - rvm: 1.9.3
48
+ os: osx
49
+ # Travis does not provide 2.0.0 on it latest version of OSX
50
+ - rvm: 2.0.0
51
+ os: osx
@@ -1,49 +1,61 @@
1
- ### Version 0.9.0 / 2018-03-10
2
-
3
- * Added support for DragonFly BSD.
4
-
5
-
6
- ### Version 0.8.0 / 2017-09-23
7
-
8
- * Added a method for determining whether or not a process had been started.
9
-
10
-
11
- ### Version 0.7.1 / 2017-06-26
12
-
13
- * Fixed a noisy uninitialized variable warning
14
-
15
-
16
- ### Version 0.7.0 / 2017-05-07
17
-
18
- * Debugging information now uses a Logger, which can be configured.
19
-
20
-
21
- ### Version 0.6.3 / 2017-03-24
22
-
23
- See beta release notes.
24
-
25
-
26
- ### Version 0.6.3.beta.1 / 2017-03-10
27
-
28
- * Bug fix: Fixed child process creation problems on Windows 7 when a child was declared as a leader.
29
-
30
-
31
- ### Version 0.6.2 / 2017-02-25
32
-
33
- * Bug fix: Fixed a potentially broken edge case that could occur on older 32-bit OSX systems.
34
-
35
-
36
- ### Version 0.6.1 / 2017-01-22
37
-
38
- * Bug fix: Fixed a dependency that was accidentally declared as a runtime
39
- dependency instead of a development dependency.
40
-
41
-
42
- ### Version 0.6.0 / 2017-01-22
43
-
44
- * Support for Ruby 2.4 added
45
-
46
-
47
- ### Version 0.5.9 / 2016-01-06
48
-
49
- * The Great Before Times...
1
+ ### Version 1.0.1 / 2019-02-03
2
+
3
+ * [#143](https://github.com/enkessler/childprocess/pull/144): Fix installs by adding `rake` gem as runtime dependency
4
+ * [#147](https://github.com/enkessler/childprocess/pull/147): Relax `rake` gem constraint from `< 12` to `< 13`
5
+
6
+ ### Version 1.0.0 / 2019-01-28
7
+
8
+ * [#134](https://github.com/enkessler/childprocess/pull/134): Add support for non-ASCII characters on Windows
9
+ * [#132](https://github.com/enkessler/childprocess/pull/132): Install `ffi` gem requirement on Windows only
10
+ * [#128](https://github.com/enkessler/childprocess/issues/128): Convert environment variable values to strings when `posix_spawn` enabled
11
+ * [#141](https://github.com/enkessler/childprocess/pull/141): Support JRuby on Java >= 9
12
+
13
+ ### Version 0.9.0 / 2018-03-10
14
+
15
+ * Added support for DragonFly BSD.
16
+
17
+
18
+ ### Version 0.8.0 / 2017-09-23
19
+
20
+ * Added a method for determining whether or not a process had been started.
21
+
22
+
23
+ ### Version 0.7.1 / 2017-06-26
24
+
25
+ * Fixed a noisy uninitialized variable warning
26
+
27
+
28
+ ### Version 0.7.0 / 2017-05-07
29
+
30
+ * Debugging information now uses a Logger, which can be configured.
31
+
32
+
33
+ ### Version 0.6.3 / 2017-03-24
34
+
35
+ See beta release notes.
36
+
37
+
38
+ ### Version 0.6.3.beta.1 / 2017-03-10
39
+
40
+ * Bug fix: Fixed child process creation problems on Windows 7 when a child was declared as a leader.
41
+
42
+
43
+ ### Version 0.6.2 / 2017-02-25
44
+
45
+ * Bug fix: Fixed a potentially broken edge case that could occur on older 32-bit OSX systems.
46
+
47
+
48
+ ### Version 0.6.1 / 2017-01-22
49
+
50
+ * Bug fix: Fixed a dependency that was accidentally declared as a runtime
51
+ dependency instead of a development dependency.
52
+
53
+
54
+ ### Version 0.6.0 / 2017-01-22
55
+
56
+ * Support for Ruby 2.4 added
57
+
58
+
59
+ ### Version 0.5.9 / 2016-01-06
60
+
61
+ * The Great Before Times...
data/Gemfile CHANGED
@@ -1,15 +1,18 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in child_process.gemspec
4
- gemspec
5
-
6
-
7
- if RUBY_VERSION =~ /^1\./
8
- gem 'tins', '< 1.7' # The 'tins' gem requires Ruby 2.x on/after this version
9
- gem 'json', '< 2.0' # The 'json' gem drops pre-Ruby 2.x support on/after this version
10
- gem 'term-ansicolor', '< 1.4' # The 'term-ansicolor' gem requires Ruby 2.x on/after this version
11
-
12
- if RbConfig::CONFIG['host_os'].downcase =~ /mswin|msys|mingw32/
13
- gem 'ffi', '< 1.9.15' # The 'ffi' gem, for Windows, requires Ruby 2.x on/after this version
14
- end
15
- end
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in child_process.gemspec
4
+ gemspec
5
+
6
+ if RUBY_VERSION =~ /^1\./
7
+ gem 'tins', '< 1.7' # The 'tins' gem requires Ruby 2.x on/after this version
8
+ gem 'json', '< 2.0' # The 'json' gem drops pre-Ruby 2.x support on/after this version
9
+ gem 'term-ansicolor', '< 1.4' # The 'term-ansicolor' gem requires Ruby 2.x on/after this version
10
+
11
+ # ffi gem for Windows requires Ruby 2.x on/after this version
12
+ gem 'ffi', '< 1.9.15' if ENV['CHILDPROCESS_POSIX_SPAWN'] == 'true' || Gem.win_platform?
13
+ elsif Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2')
14
+ # Ruby 2.0/2.1 support only ffi before 1.10
15
+ gem 'ffi', '~> 1.9.0' if ENV['CHILDPROCESS_POSIX_SPAWN'] == 'true' || Gem.win_platform?
16
+ else
17
+ gem 'ffi' if ENV['CHILDPROCESS_POSIX_SPAWN'] == 'true' || Gem.win_platform?
18
+ end
data/LICENSE CHANGED
@@ -1,20 +1,20 @@
1
- Copyright (c) 2010-2015 Jari Bakken
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2010-2015 Jari Bakken
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,196 +1,212 @@
1
- # childprocess
2
-
3
- This gem aims at being a simple and reliable solution for controlling
4
- external programs running in the background on any Ruby / OS combination.
5
-
6
- The code originated in the [selenium-webdriver](https://rubygems.org/gems/selenium-webdriver) gem, but should prove useful as
7
- a standalone library.
8
-
9
- [![Build Status](https://secure.travis-ci.org/enkessler/childprocess.svg)](http://travis-ci.org/enkessler/childprocess)
10
- [![Build status](https://ci.appveyor.com/api/projects/status/fn2snbcd7kku5myk/branch/dev?svg=true)](https://ci.appveyor.com/project/enkessler/childprocess/branch/dev)
11
- [![Gem Version](https://badge.fury.io/rb/childprocess.svg)](http://badge.fury.io/rb/childprocess)
12
- [![Code Climate](https://codeclimate.com/github/enkessler/childprocess.svg)](https://codeclimate.com/github/enkessler/childprocess)
13
- [![Coverage Status](https://coveralls.io/repos/enkessler/childprocess/badge.svg?branch=master)](https://coveralls.io/r/enkessler/childprocess?branch=master)
14
-
15
- ***
16
- **This project currently needs a new maintainer. If anyone is interested, please contact me, [enkessler](https://github.com/enkessler).**
17
- ***
18
-
19
- # Usage
20
-
21
- The object returned from `ChildProcess.build` will implement `ChildProcess::AbstractProcess`.
22
-
23
- ### Basic examples
24
-
25
- ```ruby
26
- process = ChildProcess.build("ruby", "-e", "sleep")
27
-
28
- # inherit stdout/stderr from parent...
29
- process.io.inherit!
30
-
31
- # ...or pass an IO
32
- process.io.stdout = Tempfile.new("child-output")
33
-
34
- # modify the environment for the child
35
- process.environment["a"] = "b"
36
- process.environment["c"] = nil
37
-
38
- # set the child's working directory
39
- process.cwd = '/some/path'
40
-
41
- # start the process
42
- process.start
43
-
44
- # check process status
45
- process.alive? #=> true
46
- process.exited? #=> false
47
-
48
- # wait indefinitely for process to exit...
49
- process.wait
50
- process.exited? #=> true
51
-
52
- # get the exit code
53
- process.exit_code #=> 0
54
-
55
- # ...or poll for exit + force quit
56
- begin
57
- process.poll_for_exit(10)
58
- rescue ChildProcess::TimeoutError
59
- process.stop # tries increasingly harsher methods to kill the process.
60
- end
61
- ```
62
-
63
- ### Advanced examples
64
-
65
- #### Output to pipe
66
-
67
- ```ruby
68
- r, w = IO.pipe
69
-
70
- proc = ChildProcess.build("echo", "foo")
71
- proc.io.stdout = proc.io.stderr = w
72
- proc.start
73
- w.close
74
-
75
- begin
76
- loop { print r.readpartial(8192) }
77
- rescue EOFError
78
- end
79
-
80
- proc.wait
81
- ```
82
-
83
- Note that if you just want to get the output of a command, the backtick method on Kernel may be a better fit.
84
-
85
- #### Write to stdin
86
-
87
- ```ruby
88
- process = ChildProcess.build("cat")
89
-
90
- out = Tempfile.new("duplex")
91
- out.sync = true
92
-
93
- process.io.stdout = process.io.stderr = out
94
- process.duplex = true # sets up pipe so process.io.stdin will be available after .start
95
-
96
- process.start
97
- process.io.stdin.puts "hello world"
98
- process.io.stdin.close
99
-
100
- process.poll_for_exit(exit_timeout_in_seconds)
101
-
102
- out.rewind
103
- out.read #=> "hello world\n"
104
- ```
105
-
106
- #### Pipe output to another ChildProcess
107
-
108
- ```ruby
109
- search = ChildProcess.build("grep", '-E', %w(redis memcached).join('|'))
110
- search.duplex = true # sets up pipe so search.io.stdin will be available after .start
111
- search.io.stdout = $stdout
112
- search.start
113
-
114
- listing = ChildProcess.build("ps", "aux")
115
- listing.io.stdout = search.io.stdin
116
- listing.start
117
- listing.wait
118
-
119
- search.io.stdin.close
120
- search.wait
121
- ```
122
-
123
- #### Prefer posix_spawn on *nix
124
-
125
- If the parent process is using a lot of memory, `fork+exec` can be very expensive. The `posix_spawn()` API removes this overhead.
126
-
127
- ```ruby
128
- ChildProcess.posix_spawn = true
129
- process = ChildProcess.build(*args)
130
- ```
131
-
132
- ### Ensure entire process tree dies
133
-
134
- By default, the child process does not create a new process group. This means there's no guarantee that the entire process tree will die when the child process is killed. To solve this:
135
-
136
- ```ruby
137
- process = ChildProcess.build(*args)
138
- process.leader = true
139
- process.start
140
- ```
141
-
142
- #### Detach from parent
143
-
144
- ```ruby
145
- process = ChildProcess.build("sleep", "10")
146
- process.detach = true
147
- process.start
148
- ```
149
-
150
- #### Invoking a shell
151
-
152
- As opposed to `Kernel#system`, `Kernel#exec` et al., ChildProcess will not automatically execute your command in a shell (like `/bin/sh` or `cmd.exe`) depending on the arguments.
153
- This means that if you try to execute e.g. gem executables (like `bundle` or `gem`) or Windows executables (with `.com` or `.bat` extensions) you may see a `ChildProcess::LaunchError`.
154
- You can work around this by being explicit about what interpreter to invoke:
155
-
156
- ```ruby
157
- ChildProcess.build("cmd.exe", "/c", "bundle")
158
- ChildProcess.build("ruby", "-S", "bundle")
159
- ```
160
-
161
- #### Log to file
162
-
163
- Errors and debugging information are logged to `$stderr` by default but a custom logger can be used instead.
164
-
165
- ```ruby
166
- logger = Logger.new('logfile.log')
167
- logger.level = Logger::DEBUG
168
- ChildProcess.logger = logger
169
- ```
170
-
171
- ## Caveats
172
-
173
- * With JRuby on Unix, modifying `ENV["PATH"]` before using childprocess could lead to 'Command not found' errors, since JRuby is unable to modify the environment used for PATH searches in `java.lang.ProcessBuilder`. This can be avoided by setting `ChildProcess.posix_spawn = true`.
174
-
175
- # Implementation
176
-
177
- How the process is launched and killed depends on the platform:
178
-
179
- * Unix : `fork + exec` (or `posix_spawn` if enabled)
180
- * Windows : `CreateProcess()` and friends
181
- * JRuby : `java.lang.{Process,ProcessBuilder}`
182
-
183
- # Note on Patches/Pull Requests
184
-
185
- 1. Fork it
186
- 2. Create your feature branch (off of the development branch)
187
- `git checkout -b my-new-feature dev`
188
- 3. Commit your changes
189
- `git commit -am 'Add some feature'`
190
- 4. Push to the branch
191
- `git push origin my-new-feature`
192
- 5. Create new Pull Request
193
-
194
- # Copyright
195
-
196
- Copyright (c) 2010-2015 Jari Bakken. See LICENSE for details.
1
+ # childprocess
2
+
3
+ This gem aims at being a simple and reliable solution for controlling
4
+ external programs running in the background on any Ruby / OS combination.
5
+
6
+ The code originated in the [selenium-webdriver](https://rubygems.org/gems/selenium-webdriver) gem, but should prove useful as
7
+ a standalone library.
8
+
9
+ [![Build Status](https://secure.travis-ci.org/enkessler/childprocess.svg)](http://travis-ci.org/enkessler/childprocess)
10
+ [![Build status](https://ci.appveyor.com/api/projects/status/fn2snbcd7kku5myk/branch/dev?svg=true)](https://ci.appveyor.com/project/enkessler/childprocess/branch/dev)
11
+ [![Gem Version](https://badge.fury.io/rb/childprocess.svg)](http://badge.fury.io/rb/childprocess)
12
+ [![Code Climate](https://codeclimate.com/github/enkessler/childprocess.svg)](https://codeclimate.com/github/enkessler/childprocess)
13
+ [![Coverage Status](https://coveralls.io/repos/enkessler/childprocess/badge.svg?branch=master)](https://coveralls.io/r/enkessler/childprocess?branch=master)
14
+
15
+ ***
16
+ **This project currently needs a new maintainer. If anyone is interested, please contact me, [enkessler](https://github.com/enkessler).**
17
+ ***
18
+
19
+ # Usage
20
+
21
+ The object returned from `ChildProcess.build` will implement `ChildProcess::AbstractProcess`.
22
+
23
+ ### Basic examples
24
+
25
+ ```ruby
26
+ process = ChildProcess.build("ruby", "-e", "sleep")
27
+
28
+ # inherit stdout/stderr from parent...
29
+ process.io.inherit!
30
+
31
+ # ...or pass an IO
32
+ process.io.stdout = Tempfile.new("child-output")
33
+
34
+ # modify the environment for the child
35
+ process.environment["a"] = "b"
36
+ process.environment["c"] = nil
37
+
38
+ # set the child's working directory
39
+ process.cwd = '/some/path'
40
+
41
+ # start the process
42
+ process.start
43
+
44
+ # check process status
45
+ process.alive? #=> true
46
+ process.exited? #=> false
47
+
48
+ # wait indefinitely for process to exit...
49
+ process.wait
50
+ process.exited? #=> true
51
+
52
+ # get the exit code
53
+ process.exit_code #=> 0
54
+
55
+ # ...or poll for exit + force quit
56
+ begin
57
+ process.poll_for_exit(10)
58
+ rescue ChildProcess::TimeoutError
59
+ process.stop # tries increasingly harsher methods to kill the process.
60
+ end
61
+ ```
62
+
63
+ ### Advanced examples
64
+
65
+ #### Output to pipe
66
+
67
+ ```ruby
68
+ r, w = IO.pipe
69
+
70
+ proc = ChildProcess.build("echo", "foo")
71
+ proc.io.stdout = proc.io.stderr = w
72
+ proc.start
73
+ w.close
74
+
75
+ begin
76
+ loop { print r.readpartial(8192) }
77
+ rescue EOFError
78
+ end
79
+
80
+ proc.wait
81
+ ```
82
+
83
+ Note that if you just want to get the output of a command, the backtick method on Kernel may be a better fit.
84
+
85
+ #### Write to stdin
86
+
87
+ ```ruby
88
+ process = ChildProcess.build("cat")
89
+
90
+ out = Tempfile.new("duplex")
91
+ out.sync = true
92
+
93
+ process.io.stdout = process.io.stderr = out
94
+ process.duplex = true # sets up pipe so process.io.stdin will be available after .start
95
+
96
+ process.start
97
+ process.io.stdin.puts "hello world"
98
+ process.io.stdin.close
99
+
100
+ process.poll_for_exit(exit_timeout_in_seconds)
101
+
102
+ out.rewind
103
+ out.read #=> "hello world\n"
104
+ ```
105
+
106
+ #### Pipe output to another ChildProcess
107
+
108
+ ```ruby
109
+ search = ChildProcess.build("grep", '-E', %w(redis memcached).join('|'))
110
+ search.duplex = true # sets up pipe so search.io.stdin will be available after .start
111
+ search.io.stdout = $stdout
112
+ search.start
113
+
114
+ listing = ChildProcess.build("ps", "aux")
115
+ listing.io.stdout = search.io.stdin
116
+ listing.start
117
+ listing.wait
118
+
119
+ search.io.stdin.close
120
+ search.wait
121
+ ```
122
+
123
+ #### Prefer posix_spawn on *nix
124
+
125
+ If the parent process is using a lot of memory, `fork+exec` can be very expensive. The `posix_spawn()` API removes this overhead.
126
+
127
+ ```ruby
128
+ ChildProcess.posix_spawn = true
129
+ process = ChildProcess.build(*args)
130
+ ```
131
+
132
+ To be able to use this, please make sure that you have the `ffi` gem installed.
133
+
134
+ ### Ensure entire process tree dies
135
+
136
+ By default, the child process does not create a new process group. This means there's no guarantee that the entire process tree will die when the child process is killed. To solve this:
137
+
138
+ ```ruby
139
+ process = ChildProcess.build(*args)
140
+ process.leader = true
141
+ process.start
142
+ ```
143
+
144
+ #### Detach from parent
145
+
146
+ ```ruby
147
+ process = ChildProcess.build("sleep", "10")
148
+ process.detach = true
149
+ process.start
150
+ ```
151
+
152
+ #### Invoking a shell
153
+
154
+ As opposed to `Kernel#system`, `Kernel#exec` et al., ChildProcess will not automatically execute your command in a shell (like `/bin/sh` or `cmd.exe`) depending on the arguments.
155
+ This means that if you try to execute e.g. gem executables (like `bundle` or `gem`) or Windows executables (with `.com` or `.bat` extensions) you may see a `ChildProcess::LaunchError`.
156
+ You can work around this by being explicit about what interpreter to invoke:
157
+
158
+ ```ruby
159
+ ChildProcess.build("cmd.exe", "/c", "bundle")
160
+ ChildProcess.build("ruby", "-S", "bundle")
161
+ ```
162
+
163
+ #### Log to file
164
+
165
+ Errors and debugging information are logged to `$stderr` by default but a custom logger can be used instead.
166
+
167
+ ```ruby
168
+ logger = Logger.new('logfile.log')
169
+ logger.level = Logger::DEBUG
170
+ ChildProcess.logger = logger
171
+ ```
172
+
173
+ ## Caveats
174
+
175
+ * With JRuby on Unix, modifying `ENV["PATH"]` before using childprocess could lead to 'Command not found' errors, since JRuby is unable to modify the environment used for PATH searches in `java.lang.ProcessBuilder`. This can be avoided by setting `ChildProcess.posix_spawn = true`.
176
+ * With JRuby on Java >= 9, the JVM may need to be configured to allow JRuby to access neccessary implementations; this can be done by adding `--add-opens java.base/java.io=org.jruby.dist` and `--add-opens java.base/sun.nio.ch=org.jruby.dist` to the `JAVA_OPTS` environment variable that is used by JRuby when launching the JVM.
177
+
178
+ # Implementation
179
+
180
+ How the process is launched and killed depends on the platform:
181
+
182
+ * Unix : `fork + exec` (or `posix_spawn` if enabled)
183
+ * Windows : `CreateProcess()` and friends
184
+ * JRuby : `java.lang.{Process,ProcessBuilder}`
185
+
186
+ # Note on Patches/Pull Requests
187
+
188
+ 1. Fork it
189
+ 2. Create your feature branch (off of the development branch)
190
+ `git checkout -b my-new-feature dev`
191
+ 3. Commit your changes
192
+ `git commit -am 'Add some feature'`
193
+ 4. Push to the branch
194
+ `git push origin my-new-feature`
195
+ 5. Create new Pull Request
196
+
197
+ # Publishing a New Release
198
+
199
+ When publishing a new gem release:
200
+
201
+ 1. Ensure [latest build is green on the `dev` branch](https://travis-ci.org/enkessler/childprocess/branches)
202
+ 2. Ensure [CHANGELOG](CHANGELOG.md) is updated
203
+ 3. Ensure [version is bumped](lib/childprocess/version.rb) following [Semantic Versioning](https://semver.org/)
204
+ 4. Merge the `dev` branch into `master`: `git checkout master && git merge dev`
205
+ 5. Ensure [latest build is green on the `master` branch](https://travis-ci.org/enkessler/childprocess/branches)
206
+ 6. Build gem from the green `master` branch: `git checkout master && gem build childprocess.gemspec`
207
+ 7. Push gem to RubyGems: `gem push childprocess-<VERSION>.gem`
208
+ 8. Tag commit with version, annotated with release notes: `git tag -a <VERSION>`
209
+
210
+ # Copyright
211
+
212
+ Copyright (c) 2010-2015 Jari Bakken. See [LICENSE](LICENSE) for details.