proclib 0.2.1 → 0.2.2
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 +4 -4
- data/lib/proclib.rb +9 -1
- data/lib/proclib/commands/base.rb +38 -0
- data/lib/proclib/commands/local.rb +30 -0
- data/lib/proclib/commands/ssh.rb +69 -0
- data/lib/proclib/invocation.rb +9 -4
- data/lib/proclib/ssh_session.rb +48 -0
- data/lib/proclib/version.rb +1 -1
- metadata +7 -5
- data/lib/proclib/command.rb +0 -129
- data/lib/proclib/process_group.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6212650eff9983728f4fb27e15da5f0d1ecd0b9
|
4
|
+
data.tar.gz: da2f686f9549288c78a92f8a0c9797006398e00d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec307361563e72615dff68ff55ebd5ad12a160331e08ff54d5a612541f943fedcf2d0ed32c9395f93bdb0474ad2a720d281038a02892f56aed901b72dea082f5
|
7
|
+
data.tar.gz: 5441bea3cc830c74e9ee62eaf7201c59b7114a46f66d1440b32142264a9a81f4e54024b7e9fed8c7d937a52b1ea5497162c56ef5c1f2e11e906eea2690cd56ed
|
data/lib/proclib.rb
CHANGED
@@ -12,7 +12,6 @@ module Proclib
|
|
12
12
|
cwd: nil,
|
13
13
|
ssh: nil
|
14
14
|
)
|
15
|
-
|
16
15
|
inv = Invocation.new(cmd,
|
17
16
|
tag: tag,
|
18
17
|
env: env,
|
@@ -30,4 +29,13 @@ module Proclib
|
|
30
29
|
rescue Invocation::Invalid => e
|
31
30
|
raise ArgumentError, e.message
|
32
31
|
end
|
32
|
+
|
33
|
+
def self.ssh_session(user:, host:, password: nil, port: nil, paranoid: nil)
|
34
|
+
ssh_opts = { user: user, host: host }
|
35
|
+
ssh_opts[:port] = port unless port.nil?
|
36
|
+
ssh_opts[:paranoid] = paranoid unless paranoid.nil?
|
37
|
+
ssh_opts[:password] = password unless password.nil?
|
38
|
+
|
39
|
+
SshSession.new(ssh_opts)
|
40
|
+
end
|
33
41
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
require 'proclib/errors'
|
4
|
+
|
5
|
+
module Proclib
|
6
|
+
module Commands
|
7
|
+
class Base
|
8
|
+
NotYetRunning = Class.new(Error)
|
9
|
+
NotYetTerminated = Class.new(Error)
|
10
|
+
|
11
|
+
attr_reader :tag, :cmdline, :env, :run_dir
|
12
|
+
|
13
|
+
def initialize(tag: nil, cmdline:, env: {} , run_dir: nil)
|
14
|
+
@env = env.map {|k,v| [k.to_s, v.to_s]}.to_h
|
15
|
+
@cmdline = cmdline
|
16
|
+
@tag = tag || cmdline[0..20]
|
17
|
+
@run_dir = run_dir
|
18
|
+
end
|
19
|
+
|
20
|
+
def pipes
|
21
|
+
@pipes ||= OpenStruct.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def spawn
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
|
28
|
+
def wait
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
|
32
|
+
def result
|
33
|
+
@result || raise(NotYetTerminated)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
private_constant :Base
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'proclib/commands/base'
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
module Proclib
|
5
|
+
module Commands
|
6
|
+
class Local < Base
|
7
|
+
def spawn
|
8
|
+
spawn = -> do
|
9
|
+
pipes.stdin, pipes.stdout, pipes.stderr, @wait_thread = Open3.popen3(env, cmdline)
|
10
|
+
end
|
11
|
+
|
12
|
+
if run_dir
|
13
|
+
Dir.chdir(run_dir) { spawn.call }
|
14
|
+
else
|
15
|
+
spawn.call
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def wait
|
20
|
+
@result ||= wait_thread.value.to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def wait_thread
|
26
|
+
@wait_thread || raise(NotYetRunning)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
require 'proclib/ssh_session'
|
3
|
+
require 'proclib/commands/base'
|
4
|
+
|
5
|
+
module Proclib
|
6
|
+
module Commands
|
7
|
+
class Ssh < Base
|
8
|
+
SSHError = Class.new(Error)
|
9
|
+
|
10
|
+
def initialize(ssh_session:, **args)
|
11
|
+
@ssh_session = ssh_session
|
12
|
+
super(**args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def spawn
|
16
|
+
write_pipes
|
17
|
+
|
18
|
+
open_channel do |ch|
|
19
|
+
ch.exec(cmdline) do |_, success|
|
20
|
+
raise SSHError, "Command Failed" unless success
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def wait
|
26
|
+
ssh_session.loop
|
27
|
+
end
|
28
|
+
|
29
|
+
def cmdline
|
30
|
+
if !run_dir.nil?
|
31
|
+
"cd #{run_dir}; #{super}"
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :ssh_session
|
40
|
+
|
41
|
+
def open_channel
|
42
|
+
ssh_session.open_channel do |channel|
|
43
|
+
channel.on_open_failed do |ch, code, desc, lang|
|
44
|
+
raise SSHError, desc
|
45
|
+
end
|
46
|
+
|
47
|
+
channel.on_data {|_, data| write_pipes[:stdout].write(data) }
|
48
|
+
|
49
|
+
channel.on_extended_data {|_, data| write_pipes[:stderr].write(data) }
|
50
|
+
|
51
|
+
channel.on_request("exit-status") do |_, data|
|
52
|
+
write_pipes.each {|k,v| v.close }
|
53
|
+
@result = data.read_long
|
54
|
+
end
|
55
|
+
|
56
|
+
yield channel
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def write_pipes
|
61
|
+
@write_pipes ||= %i(stdout stderr).map do |type|
|
62
|
+
read, write = IO.pipe
|
63
|
+
pipes[type] = read
|
64
|
+
[type, write]
|
65
|
+
end.to_h
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/proclib/invocation.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
|
3
3
|
require 'proclib/errors'
|
4
|
-
|
4
|
+
|
5
|
+
require 'proclib/commands/local'
|
6
|
+
require 'proclib/commands/ssh'
|
7
|
+
|
8
|
+
require 'net/ssh'
|
5
9
|
|
6
10
|
module Proclib
|
7
11
|
class Invocation
|
@@ -43,15 +47,15 @@ module Proclib
|
|
43
47
|
run_dir: validated_cwd,
|
44
48
|
cmdline: validated_cmd
|
45
49
|
}.tap do |args|
|
46
|
-
args[:
|
50
|
+
args[:ssh_session] = validated_ssh if !validated_ssh.nil?
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
50
54
|
def command_class
|
51
55
|
if validated_ssh.nil?
|
52
|
-
Commands::
|
56
|
+
Commands::Local
|
53
57
|
else
|
54
|
-
Commands::
|
58
|
+
Commands::Ssh
|
55
59
|
end
|
56
60
|
end
|
57
61
|
|
@@ -82,6 +86,7 @@ module Proclib
|
|
82
86
|
|
83
87
|
def validated_ssh
|
84
88
|
return if @ssh.nil?
|
89
|
+
return @ssh if @ssh.kind_of?(Net::SSH::Connection::Session)
|
85
90
|
|
86
91
|
@validated_ssh ||= begin
|
87
92
|
%i(host user).each do |k|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Proclib
|
2
|
+
class SshSession
|
3
|
+
attr_reader :ssh_opts
|
4
|
+
|
5
|
+
def initialize(ssh_opts)
|
6
|
+
@ssh_opts = ssh_opts.clone
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(cmd,
|
10
|
+
tag: nil,
|
11
|
+
log_to_console: false,
|
12
|
+
capture_output: true,
|
13
|
+
env: {},
|
14
|
+
on_output: nil,
|
15
|
+
cwd: nil,
|
16
|
+
ssh: nil
|
17
|
+
)
|
18
|
+
|
19
|
+
inv = Invocation.new(cmd,
|
20
|
+
tag: tag,
|
21
|
+
env: env,
|
22
|
+
ssh: session,
|
23
|
+
cwd: cwd)
|
24
|
+
|
25
|
+
executor = Executor.new(inv.commands,
|
26
|
+
log_to_console: log_to_console,
|
27
|
+
cache_output: capture_output
|
28
|
+
).tap do |ex|
|
29
|
+
ex.on_output(&on_output) unless on_output.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
executor.run_sync
|
33
|
+
rescue Invocation::Invalid => e
|
34
|
+
raise ArgumentError, e.message
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def ssh_params
|
40
|
+
%i(host user).map {|i| ssh_opts.delete(i)}.compact
|
41
|
+
end
|
42
|
+
|
43
|
+
def session
|
44
|
+
@session ||= Net::SSH.start(*ssh_params, ssh_opts)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
private_constant :SshSession
|
48
|
+
end
|
data/lib/proclib/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: proclib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jack Forrest
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-02-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-ssh
|
@@ -115,8 +115,10 @@ files:
|
|
115
115
|
- bin/setup
|
116
116
|
- lib/proclib.rb
|
117
117
|
- lib/proclib/channel.rb
|
118
|
-
- lib/proclib/command.rb
|
119
118
|
- lib/proclib/command_monitor.rb
|
119
|
+
- lib/proclib/commands/base.rb
|
120
|
+
- lib/proclib/commands/local.rb
|
121
|
+
- lib/proclib/commands/ssh.rb
|
120
122
|
- lib/proclib/errors.rb
|
121
123
|
- lib/proclib/executor.rb
|
122
124
|
- lib/proclib/invocation.rb
|
@@ -124,8 +126,8 @@ files:
|
|
124
126
|
- lib/proclib/output_cache.rb
|
125
127
|
- lib/proclib/output_handler.rb
|
126
128
|
- lib/proclib/process.rb
|
127
|
-
- lib/proclib/process_group.rb
|
128
129
|
- lib/proclib/result.rb
|
130
|
+
- lib/proclib/ssh_session.rb
|
129
131
|
- lib/proclib/string_formatting.rb
|
130
132
|
- lib/proclib/version.rb
|
131
133
|
- proclib.gemspec
|
@@ -149,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
149
151
|
version: '0'
|
150
152
|
requirements: []
|
151
153
|
rubyforge_project:
|
152
|
-
rubygems_version: 2.5.2
|
154
|
+
rubygems_version: 2.5.2.1
|
153
155
|
signing_key:
|
154
156
|
specification_version: 4
|
155
157
|
summary: Provides tools for subprocess management
|
data/lib/proclib/command.rb
DELETED
@@ -1,129 +0,0 @@
|
|
1
|
-
require 'open3'
|
2
|
-
require 'ostruct'
|
3
|
-
|
4
|
-
require 'proclib/errors'
|
5
|
-
|
6
|
-
require 'net/ssh'
|
7
|
-
|
8
|
-
module Proclib
|
9
|
-
module Commands
|
10
|
-
class Command
|
11
|
-
NotYetRunning = Class.new(Error)
|
12
|
-
NotYetTerminated = Class.new(Error)
|
13
|
-
|
14
|
-
attr_reader :tag, :cmdline, :env, :run_dir
|
15
|
-
|
16
|
-
def initialize(tag: nil, cmdline:, env: {} , run_dir: nil)
|
17
|
-
@env = env.map {|k,v| [k.to_s, v.to_s]}.to_h
|
18
|
-
@cmdline = cmdline
|
19
|
-
@tag = tag || cmdline[0..20]
|
20
|
-
@run_dir = run_dir
|
21
|
-
end
|
22
|
-
|
23
|
-
def pipes
|
24
|
-
@pipes ||= OpenStruct.new
|
25
|
-
end
|
26
|
-
|
27
|
-
def spawn
|
28
|
-
raise NotImplementedError
|
29
|
-
end
|
30
|
-
|
31
|
-
def wait
|
32
|
-
raise NotImplementedError
|
33
|
-
end
|
34
|
-
|
35
|
-
def result
|
36
|
-
@result || raise(NotYetTerminated)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
private_constant :Command
|
40
|
-
|
41
|
-
class LocalCommand < Command
|
42
|
-
def spawn
|
43
|
-
spawn = -> do
|
44
|
-
pipes.stdin, pipes.stdout, pipes.stderr, @wait_thread = Open3.popen3(env, cmdline)
|
45
|
-
end
|
46
|
-
|
47
|
-
if run_dir
|
48
|
-
Dir.chdir(run_dir) { spawn.call }
|
49
|
-
else
|
50
|
-
spawn.call
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def wait
|
55
|
-
@result ||= wait_thread.value.to_i
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def wait_thread
|
61
|
-
@wait_thread || raise(NotYetRunning)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
class SshCommand < Command
|
66
|
-
attr_reader :ssh_opts
|
67
|
-
|
68
|
-
SSHError = Class.new(Error)
|
69
|
-
|
70
|
-
def initialize(ssh:, **args)
|
71
|
-
@ssh_opts = ssh.clone
|
72
|
-
super(**args)
|
73
|
-
end
|
74
|
-
|
75
|
-
def spawn
|
76
|
-
write_pipes
|
77
|
-
|
78
|
-
open_channel do |ch|
|
79
|
-
ch.exec(cmdline) do |_, success|
|
80
|
-
raise SSHError, "Command Failed" unless success
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def wait
|
86
|
-
ssh_session.loop
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
def open_channel
|
92
|
-
ssh_session.open_channel do |channel|
|
93
|
-
channel.on_open_failed do |ch, code, desc, lang|
|
94
|
-
raise SSHError, desc
|
95
|
-
end
|
96
|
-
|
97
|
-
channel.on_data {|_, data| write_pipes[:stdout].write(data) }
|
98
|
-
|
99
|
-
channel.on_extended_data {|_, data| write_pipes[:stderr].write(data) }
|
100
|
-
|
101
|
-
channel.on_request("exit-status") do |_, data|
|
102
|
-
write_pipes.each {|k,v| v.close }
|
103
|
-
@result = data.read_long
|
104
|
-
end
|
105
|
-
|
106
|
-
yield channel
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def write_pipes
|
111
|
-
@write_pipes ||= %i(stdout stderr).map do |type|
|
112
|
-
read, write = IO.pipe
|
113
|
-
pipes[type] = read
|
114
|
-
[type, write]
|
115
|
-
end.to_h
|
116
|
-
end
|
117
|
-
|
118
|
-
def ssh_session
|
119
|
-
@ssh_session ||= Net::SSH.start(*ssh_params, ssh_opts).tap do |session|
|
120
|
-
session.chdir(run_dir) unless run_dir.nil?
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def ssh_params
|
125
|
-
%i(host user).map {|i| ssh_opts.delete(i)}.compact
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require 'proclib/event_emitter'
|
2
|
-
|
3
|
-
module Proclib
|
4
|
-
class ProcessGroup
|
5
|
-
include EventEmitter::Producer
|
6
|
-
|
7
|
-
def initialize(processes)
|
8
|
-
@processes = processes
|
9
|
-
end
|
10
|
-
|
11
|
-
def spawn
|
12
|
-
processes.each do |process|
|
13
|
-
process.bind_to(channel)
|
14
|
-
process.spawn
|
15
|
-
end
|
16
|
-
|
17
|
-
start_watch_thread
|
18
|
-
end
|
19
|
-
|
20
|
-
def kill
|
21
|
-
processes.each(&:kill)
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
attr_reader :processes
|
26
|
-
|
27
|
-
def start_watch_thread
|
28
|
-
Thread.new { channel.watch }
|
29
|
-
end
|
30
|
-
|
31
|
-
def channel
|
32
|
-
@channel ||= EventEmitter::Channel.new.tap do |channel|
|
33
|
-
channel.on(:output) {|ev| push(ev) }
|
34
|
-
channel.on(:exit) do |ev|
|
35
|
-
emit(:complete) if processes.all?(&:complete?)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
private_constant :ProcessGroup
|
41
|
-
end
|