side_by_side 0.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.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +50 -0
- data/exe/side_by_side +67 -0
- data/lib/side_by_side/process_to_run.rb +88 -0
- data/lib/side_by_side.rb +5 -0
- metadata +110 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bdf8e83de80358a9e62037120d19a3e28522903138edaee965a0dd7144a02e5d
|
4
|
+
data.tar.gz: 752a8127bc392c07010260965d82dd15a619c7f9d11a5e84abfc99bc00b2ee86
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4d82efa128bcdb98d35055fb5957756298a2f3d5a178c787d10f384df9e9d59d07cbd8db2edc875eed645b36df9dbfc7aaf3ccb03310fe51ab9cfc523cae50fc
|
7
|
+
data.tar.gz: 18682c811e75b84328183752b6cc65ccfaef1b013f4b217fe56ecdc32ace82c22a8c6f1ede13813fedc7e953eefefcf9a1a6ea0062fd0d4eddb9b674263180e6
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
side_by_side (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ast (2.4.2)
|
10
|
+
json (2.6.2)
|
11
|
+
parallel (1.22.1)
|
12
|
+
parser (3.1.2.1)
|
13
|
+
ast (~> 2.4.1)
|
14
|
+
rainbow (3.1.1)
|
15
|
+
regexp_parser (2.6.0)
|
16
|
+
rexml (3.2.5)
|
17
|
+
rubocop (1.37.0)
|
18
|
+
json (~> 2.3)
|
19
|
+
parallel (~> 1.10)
|
20
|
+
parser (>= 3.1.2.1)
|
21
|
+
rainbow (>= 2.2.2, < 4.0)
|
22
|
+
regexp_parser (>= 1.8, < 3.0)
|
23
|
+
rexml (>= 3.2.5, < 4.0)
|
24
|
+
rubocop-ast (>= 1.22.0, < 2.0)
|
25
|
+
ruby-progressbar (~> 1.7)
|
26
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
27
|
+
rubocop-ast (1.22.0)
|
28
|
+
parser (>= 3.1.1.0)
|
29
|
+
rubocop-performance (1.15.0)
|
30
|
+
rubocop (>= 1.7.0, < 2.0)
|
31
|
+
rubocop-ast (>= 0.4.0)
|
32
|
+
rubocop-rake (0.6.0)
|
33
|
+
rubocop (~> 1.0)
|
34
|
+
rubocop-rspec (2.13.2)
|
35
|
+
rubocop (~> 1.33)
|
36
|
+
ruby-progressbar (1.11.0)
|
37
|
+
unicode-display_width (2.3.0)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
x86_64-linux
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
rubocop
|
44
|
+
rubocop-performance
|
45
|
+
rubocop-rake
|
46
|
+
rubocop-rspec
|
47
|
+
side_by_side!
|
48
|
+
|
49
|
+
BUNDLED WITH
|
50
|
+
2.3.15
|
data/exe/side_by_side
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative "../lib/side_by_side"
|
4
|
+
|
5
|
+
time_total_start = Time.new
|
6
|
+
processes_to_run = []
|
7
|
+
|
8
|
+
ARGV.each do |arg|
|
9
|
+
process_to_run = SideBySide::ProcessToRun.new(command: arg)
|
10
|
+
process_to_run.run_async
|
11
|
+
|
12
|
+
processes_to_run << process_to_run
|
13
|
+
end
|
14
|
+
|
15
|
+
puts "Started processes: #{processes_to_run.length}"
|
16
|
+
|
17
|
+
def output!(type:, output:)
|
18
|
+
if type == :stdout
|
19
|
+
$stdout.print output
|
20
|
+
elsif type == :stderr
|
21
|
+
$stderr.print output
|
22
|
+
else
|
23
|
+
raise "Unknown type: #{type}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
processes_to_run.each do |process_to_run|
|
28
|
+
time_start = Time.new
|
29
|
+
|
30
|
+
puts "Process: #{process_to_run.command}"
|
31
|
+
|
32
|
+
process_to_run.monitor.synchronize do
|
33
|
+
# Print output generated so far
|
34
|
+
process_to_run.output.each do |out|
|
35
|
+
output!(**out)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Print output to come
|
39
|
+
process_to_run.on_output do |out|
|
40
|
+
output!(**out)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Wait for process to finish
|
45
|
+
process_to_run.join
|
46
|
+
end
|
47
|
+
|
48
|
+
time_total_stop = Time.new
|
49
|
+
|
50
|
+
# Return failed exit status if any of the processes failed
|
51
|
+
puts "Status for #{processes_to_run.length} processes"
|
52
|
+
puts
|
53
|
+
result_exit_status = 0
|
54
|
+
|
55
|
+
processes_to_run.each do |process_to_run|
|
56
|
+
puts process_to_run.command
|
57
|
+
puts " Exit status: #{process_to_run.exit_status}"
|
58
|
+
puts " Seconds: #{process_to_run.seconds}"
|
59
|
+
puts
|
60
|
+
|
61
|
+
result_exit_status = process_to_run.exit_status if process_to_run.exit_status != 0
|
62
|
+
end
|
63
|
+
|
64
|
+
puts "Seconds total: #{time_total_stop.to_f - time_total_start.to_f}"
|
65
|
+
puts "Result: #{result_exit_status}"
|
66
|
+
|
67
|
+
exit(result_exit_status)
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require "pty"
|
2
|
+
|
3
|
+
class SideBySide::ProcessToRun
|
4
|
+
attr_reader :command, :exit_status, :monitor, :on_output_callback, :output, :pid, :start_time, :stop_time, :thread
|
5
|
+
|
6
|
+
def initialize(command:)
|
7
|
+
@command = command
|
8
|
+
@output = []
|
9
|
+
@monitor = Monitor.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def join
|
13
|
+
while !thread
|
14
|
+
puts "Pass - waiting for thread"
|
15
|
+
Thread.pass
|
16
|
+
end
|
17
|
+
|
18
|
+
thread.join
|
19
|
+
end
|
20
|
+
|
21
|
+
def on_output(&blk)
|
22
|
+
puts "Setting on output for: #{command}"
|
23
|
+
@on_output_callback = blk
|
24
|
+
end
|
25
|
+
|
26
|
+
def output!(out)
|
27
|
+
type = out.fetch(:type)
|
28
|
+
|
29
|
+
if type == :stdout
|
30
|
+
$stdout << out.fetch(:output)
|
31
|
+
elsif type == :stderr
|
32
|
+
$stderr << out.fetch(:output)
|
33
|
+
else
|
34
|
+
raise "Unknown type: #{type}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def run_async
|
39
|
+
@thread = Thread.new do
|
40
|
+
@start_time = Time.new
|
41
|
+
stderr_reader, stderr_writer = IO.pipe
|
42
|
+
|
43
|
+
PTY.spawn(command, err: stderr_writer.fileno) do |stdout, stdin, pid|
|
44
|
+
@pid = pid
|
45
|
+
|
46
|
+
puts "Command running: #{command} - #{stdout.class.name}"
|
47
|
+
|
48
|
+
stdout_reader_thread = Thread.new do
|
49
|
+
begin
|
50
|
+
stdout.each_char do |chunk|
|
51
|
+
monitor.synchronize do
|
52
|
+
out = {type: :stdout, output: chunk}
|
53
|
+
output << out
|
54
|
+
on_output_callback&.call(out)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
rescue Errno::EIO => e
|
58
|
+
# Process done
|
59
|
+
ensure
|
60
|
+
status = Process::Status.wait(@pid, 0)
|
61
|
+
|
62
|
+
@exit_status = status.exitstatus
|
63
|
+
stderr_writer.close
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
stderr_reader_thread = Thread.new do
|
68
|
+
stderr_reader.each_char do |chunk|
|
69
|
+
monitor.synchronize do
|
70
|
+
out = {type: :stderr, output: chunk}
|
71
|
+
output << out
|
72
|
+
on_output_callback&.call(out)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
stdout_reader_thread.join
|
78
|
+
stderr_reader_thread.join
|
79
|
+
|
80
|
+
@stop_time = Time.new
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def seconds
|
86
|
+
@stop_time.to_f - @start_time.to_f
|
87
|
+
end
|
88
|
+
end
|
data/lib/side_by_side.rb
ADDED
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: side_by_side
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- kaspernj
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-11-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rubocop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubocop-performance
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop-rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop-rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Run and control processes.
|
70
|
+
email:
|
71
|
+
- k@spernj.org
|
72
|
+
executables:
|
73
|
+
- side_by_side
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- Gemfile
|
78
|
+
- Gemfile.lock
|
79
|
+
- exe/side_by_side
|
80
|
+
- lib/side_by_side.rb
|
81
|
+
- lib/side_by_side/process_to_run.rb
|
82
|
+
homepage: https://github.com/kaspernj/side_by_side
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata:
|
86
|
+
allowed_push_host: https://rubygems.org
|
87
|
+
homepage_uri: https://github.com/kaspernj/side_by_side
|
88
|
+
source_code_uri: https://github.com/kaspernj/side_by_side
|
89
|
+
changelog_uri: https://github.com/kaspernj/side_by_side/blob/master/CHANGELOG.md
|
90
|
+
rubygems_mfa_required: 'true'
|
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: 2.6.0
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubygems_version: 3.3.7
|
107
|
+
signing_key:
|
108
|
+
specification_version: 4
|
109
|
+
summary: Run and control processes.
|
110
|
+
test_files: []
|