proclib 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1fd39b5a0365da59054e4d5db583d327d907523a
4
- data.tar.gz: 8300d876216aa45f651c6d10c37fd13574273878
3
+ metadata.gz: d6212650eff9983728f4fb27e15da5f0d1ecd0b9
4
+ data.tar.gz: da2f686f9549288c78a92f8a0c9797006398e00d
5
5
  SHA512:
6
- metadata.gz: 1da481ea3fe20b531cdaefd39a57871fd762fc1ff8b31e45ced4933bcd43f9ef805594096fec262e3729482f0ce5be5966d4608338920a8674a8f1ec9988271d
7
- data.tar.gz: 8a46ef334624bdb0705b4111e5b18f56fa2472b538d9cbcfe2ab242167d8c920f5d10f908286fa31a09e40c9edb482ac4089fe04852a5f7a547ccb8dbcbb4c58
6
+ metadata.gz: ec307361563e72615dff68ff55ebd5ad12a160331e08ff54d5a612541f943fedcf2d0ed32c9395f93bdb0474ad2a720d281038a02892f56aed901b72dea082f5
7
+ data.tar.gz: 5441bea3cc830c74e9ee62eaf7201c59b7114a46f66d1440b32142264a9a81f4e54024b7e9fed8c7d937a52b1ea5497162c56ef5c1f2e11e906eea2690cd56ed
@@ -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
@@ -1,7 +1,11 @@
1
1
  require 'pathname'
2
2
 
3
3
  require 'proclib/errors'
4
- require 'proclib/command'
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[:ssh] = validated_ssh if !validated_ssh.nil?
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::LocalCommand
56
+ Commands::Local
53
57
  else
54
- Commands::SshCommand
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
@@ -1,3 +1,3 @@
1
1
  module Proclib
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
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.1
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-01-28 00:00:00.000000000 Z
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
@@ -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