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 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