spawn_passthrough 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +14 -0
- data/Rakefile +8 -0
- data/appveyor.yml +22 -0
- data/lib/spawn_passthrough.rb +74 -0
- data/lib/spawn_passthrough/version.rb +3 -0
- data/spawn_passthrough.gemspec +29 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6641f177c464baa7135f4ac9236d28e586eb28f3
|
4
|
+
data.tar.gz: 4475773efd3da912635e5c257aea2080af497dd5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 28fe135f8a8d0d9510e0692c88bc2aee5e0d5a93d86f2a3cba4590e1ef8926e73e8cc95601f821284b42d811c401afc40dfa7ae81da04ab41e32b9557cb1db71
|
7
|
+
data.tar.gz: d6cf408e39ead4abd165f1743b16103b7d18805782d13e254b99392d4f36b796363c5f16193d6732f740eccce7094a8c0b6b3d27632fd18f3f805d86060aa3fd
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Aptible, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# SpawnPassthrough
|
2
|
+
|
3
|
+
A gem to spawn processes in a passthrough fashion.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```
|
8
|
+
exit_code = SpawnPassthrough.spawn_passthrough(*command)
|
9
|
+
```
|
10
|
+
|
11
|
+
## License
|
12
|
+
|
13
|
+
The gem is available as open source under the terms of the [MIT
|
14
|
+
License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/appveyor.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
version: 1.0.{build}-{branch}
|
2
|
+
|
3
|
+
environment:
|
4
|
+
matrix:
|
5
|
+
- RUBY_VERSION: 200
|
6
|
+
- RUBY_VERSION: 21
|
7
|
+
- RUBY_VERSION: 22
|
8
|
+
- RUBY_VERSION: 23
|
9
|
+
|
10
|
+
install:
|
11
|
+
- set PATH=C:\Ruby%RUBY_VERSION%-x64\bin;%PATH%
|
12
|
+
- bundle install
|
13
|
+
|
14
|
+
build: off
|
15
|
+
|
16
|
+
before_test:
|
17
|
+
- ruby -v
|
18
|
+
- gem -v
|
19
|
+
- bundle -v
|
20
|
+
|
21
|
+
test_script:
|
22
|
+
- bundle exec rake ci
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spawn_passthrough/version'
|
2
|
+
|
3
|
+
module SpawnPassthrough
|
4
|
+
# There are a few gotchas in spawning processes and passing through the
|
5
|
+
# current FDs and signals:
|
6
|
+
#
|
7
|
+
# First, we cannot use Kernel.exec, because we need to return control to the
|
8
|
+
# caller.
|
9
|
+
#
|
10
|
+
# Second, we need to somehow capture the exit status, because we assume the
|
11
|
+
# caller cares.
|
12
|
+
#
|
13
|
+
# Third, we don't want to use a separate process group, because the caller
|
14
|
+
# might be used non-interactively, and we want to let other processes signal
|
15
|
+
# the caller and let this reach the subprocess we're spawning here.
|
16
|
+
#
|
17
|
+
# To do this, we have to handle interrutps as a signal, as opposed to handle
|
18
|
+
# an Interrupt exception. The reason for this has to do with how Ruby's wait
|
19
|
+
# is implemented (this happens in process.c's rb_waitpid). There are two main
|
20
|
+
# considerations here:
|
21
|
+
#
|
22
|
+
# - It automatically resumes when it receives EINTR, so our control is pretty
|
23
|
+
# high-level here.
|
24
|
+
# - It handles interrupts prior to setting $? (this appears to have changed
|
25
|
+
# between Ruby 2.2 and 2.3, perhaps the newer implementation behaves
|
26
|
+
# differently).
|
27
|
+
#
|
28
|
+
# Unfortunately, this means that if we receive SIGINT while in
|
29
|
+
# Process::wait2, then we never get access to SSH's exitstatus: Ruby throws a
|
30
|
+
# Interrupt so we don't have a return value, and it doesn't set $?, so we
|
31
|
+
# can't read it back there.
|
32
|
+
#
|
33
|
+
# Of course, we can't just call Proces::wait2 again, because at this point,
|
34
|
+
# we've reaped our child.
|
35
|
+
#
|
36
|
+
# To solve this, we add our own signal handler on SIGINT, which simply
|
37
|
+
# proxies SIGINT to SSH if we happen to have a different process group (which
|
38
|
+
# shouldn't be the case), just to be safe and let users exit the CLI.
|
39
|
+
#
|
40
|
+
# This code was originally implemented for the Aptible CLI.
|
41
|
+
def self.spawn_passthrough(command)
|
42
|
+
redirection = { in: :in, out: :out, err: :err, close_others: true }
|
43
|
+
pid = Process.spawn(*command, redirection)
|
44
|
+
|
45
|
+
reset = Signal.trap('SIGINT') do
|
46
|
+
# FIXME: If we're on Windows, we don't really know whether SSH
|
47
|
+
# received SIGINT or not, so for now, we just ignore it.
|
48
|
+
next if Gem.win_platform?
|
49
|
+
|
50
|
+
begin
|
51
|
+
# SSH should be running in our process group, which means that
|
52
|
+
# if the user sends CTRL+C, we'll both receive it. In this
|
53
|
+
# case, just ignore the signal and let SSH handle it.
|
54
|
+
next if Process.getpgid(Process.pid) == Process.getpgid(pid)
|
55
|
+
|
56
|
+
# If we get here, then oddly, SSH is not running in our process
|
57
|
+
# group and yet we got the signal. In this case, let's simply
|
58
|
+
# ignore it.
|
59
|
+
Process.kill(:SIGINT, pid)
|
60
|
+
rescue Errno::ESRCH
|
61
|
+
# This could happen if SSH exited after receiving the SIGINT,
|
62
|
+
# Ruby waited it, then ran our signal handler. In this case, we
|
63
|
+
# don't need to do anything, so we proceed.
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
begin
|
68
|
+
_, status = Process.wait2(pid)
|
69
|
+
return status.exited? ? status.exitstatus : 128 + status.termsig
|
70
|
+
ensure
|
71
|
+
Signal.trap('SIGINT', reset)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'spawn_passthrough/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'spawn_passthrough'
|
8
|
+
spec.version = SpawnPassthrough::VERSION
|
9
|
+
spec.authors = ['Thomas Orozco']
|
10
|
+
spec.email = ['thomas@orozco.fr']
|
11
|
+
|
12
|
+
spec.summary = 'Spawn passthrough processes'
|
13
|
+
spec.description = spec.summary
|
14
|
+
spec.homepage = 'https://github.com/aptible/spawn_passthrough'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
|
21
|
+
spec.bindir = 'bin'
|
22
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.13'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
28
|
+
spec.add_development_dependency 'aptible-tasks', '~> 0.5.3'
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spawn_passthrough
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thomas Orozco
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-09-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: aptible-tasks
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.5.3
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.5.3
|
69
|
+
description: Spawn passthrough processes
|
70
|
+
email:
|
71
|
+
- thomas@orozco.fr
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".rspec"
|
78
|
+
- ".travis.yml"
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- appveyor.yml
|
84
|
+
- lib/spawn_passthrough.rb
|
85
|
+
- lib/spawn_passthrough/version.rb
|
86
|
+
- spawn_passthrough.gemspec
|
87
|
+
homepage: https://github.com/aptible/spawn_passthrough
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.6.13
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Spawn passthrough processes
|
111
|
+
test_files: []
|