pretty_multitask 0.1.6 → 0.1.11

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
  SHA256:
3
- metadata.gz: f89845bbcbcee9e9914a0a3107ea41866183f4276dc2aaf0f2ebab16c166b7b6
4
- data.tar.gz: f154a0b734e97ce7ca92ffa81a33ac3391cbe39529c7e713127fbe2b447a789a
3
+ metadata.gz: e01812677f6e3b459a2202d578e1de026078513dca7cbe335b4916160a84c5e7
4
+ data.tar.gz: '0311972bb6ec45cb360e253a55cc70a756d626d19e370564827219bd8bceefe4'
5
5
  SHA512:
6
- metadata.gz: fdc1274cadfce484efde26c43cf6735f856273fc10c5d1ae9f0aed90427e191702613b5ab5d2344f183b7862229a2ac8490b09284e12730634b83c9305e5e90a
7
- data.tar.gz: 29f8a24249f62371c325fe9bc9c4e7397c7c38487891fbcbeda59be6ac8efeba3d150f2189afc147fab99fd6e85c817762a472e634148241a8fb80ec4c80e833
6
+ metadata.gz: 7db22eaa39c4efcd3f29d6a683c20af6184a9c15306e5c7c4af50e24a2d00c6e7b35dd57eeab7f3c5f6d2df7ba58657a2e94d8b2bc41e4afb9059bfa1fc8920b
7
+ data.tar.gz: 6d0001b6c098af0a0ba330d85afdec788d2ccec897b9c811735a3b70004218f3b8921079d589177171c47ca4e7043f37b52e6ff250948f8f9b77caffbd94b715
@@ -0,0 +1,35 @@
1
+ Style/SpecialGlobalVars:
2
+ Enabled: false
3
+
4
+ Style/ConditionalAssignment:
5
+ Enabled: false
6
+
7
+ Style/GuardClause:
8
+ Enabled: false
9
+
10
+ Layout/FirstArrayElementIndentation:
11
+ Enabled: false
12
+
13
+ Metrics/MethodLength:
14
+ Max: 35
15
+
16
+ Metrics/LineLength:
17
+ Max: 120
18
+ Exclude:
19
+ - test/**/*
20
+
21
+ Metrics/CyclomaticComplexity:
22
+ Max: 10
23
+
24
+ Metrics/AbcSize:
25
+ Max: 30
26
+
27
+ Security/MarshalLoad:
28
+ Exclude:
29
+ - lib/pretty_multitask/run_callable.rb
30
+
31
+ Layout/ElseAlignment:
32
+ Enabled: false
33
+ Metrics/BlockLength:
34
+ Exclude:
35
+ - '*.gemspec'
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
6
 
5
7
  # Specify your gem's dependencies in pretty_multitask.gemspec
6
8
  gemspec
data/Rakefile CHANGED
@@ -1,10 +1,12 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
3
5
 
4
6
  Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList["test/**/*_test.rb"]
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
8
10
  end
9
11
 
10
- task :default => :test
12
+ task default: :test
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "pretty_multitask"
4
+ require 'bundler/setup'
5
+ require 'pretty_multitask'
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +11,5 @@ require "pretty_multitask"
10
11
  # require "pry"
11
12
  # Pry.start
12
13
 
13
- require "irb"
14
+ require 'irb'
14
15
  IRB.start(__FILE__)
@@ -1,4 +1,6 @@
1
- require "pretty_multitask/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'pretty_multitask/version'
2
4
  require 'tlopo/executor'
3
5
  require 'logger'
4
6
  require 'pty'
@@ -7,23 +9,28 @@ require 'io/wait'
7
9
  require 'socket'
8
10
  require 'timeout'
9
11
  require 'yaml'
12
+ require 'fileutils'
13
+ require 'set'
10
14
 
15
+ # Main module
11
16
  module PrettyMultitask
17
+ require "#{__dir__}/pretty_multitask/trapper"
12
18
  require "#{__dir__}/pretty_multitask/color"
13
19
  require "#{__dir__}/pretty_multitask/runner"
14
20
  require "#{__dir__}/pretty_multitask/run_callable"
15
21
  end
16
22
 
17
23
  def pretty_multitask(hash)
18
- name, tasks = hash.keys.first, hash.values.first
24
+ name = hash.keys.first
25
+ tasks = hash.values.first
19
26
  task name do
20
27
  jobs = []
21
28
  tasks.each do |t|
22
- job = Proc.new do
29
+ job = proc do
23
30
  Rake::Task[t].invoke
24
31
  nil
25
32
  end
26
- jobs.push({ name: t, cmd: job})
33
+ jobs.push({ name: t, cmd: job })
27
34
  end
28
35
  PrettyMultitask::Runner.new(jobs).run
29
36
  end
@@ -1,14 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module PrettyMultitask
4
+ # Class to provide some ANSI colors
2
5
  class Color
3
6
  def self.green(str)
4
7
  "\e[32;1m#{str}\e[0m"
5
8
  end
9
+
6
10
  def self.yellow(str)
7
11
  "\e[33;1m#{str}\e[0m"
8
12
  end
13
+
9
14
  def self.red(str)
10
15
  "\e[31;1m#{str}\e[0m"
11
16
  end
12
17
  end
13
18
  end
14
-
@@ -1,24 +1,79 @@
1
- module PrettyMultitask
1
+ # frozen_string_literal: true
2
2
 
3
+ module PrettyMultitask
4
+ # This class will run a callable, and wrap it's output adding nice format
3
5
  class RunCallable
4
6
  def initialize(opts = {})
5
7
  @opts = opts
6
8
  end
7
-
9
+
8
10
  def run(opts = @opts)
9
11
  cmd = opts[:cmd]
10
12
  name = opts[:name]
11
- out = opts[:out] || STDOUT
12
- err = opts[:err] || STDERR
13
+ out = STDOUT
13
14
  @padding = opts[:padding]
14
15
  master, slave = PTY.open
15
16
  err_read, err_write = IO.pipe
16
-
17
+
17
18
  r, w = UNIXSocket.pair(:STREAM, 0)
18
-
19
+
20
+ pid = run_on_fork(cmd, err_write, master, w)
21
+ Trapper.trap pid
22
+
23
+ t_out = consume_and_print slave, out, name, false
24
+ t_err = consume_and_print err_read, out, name, true
25
+
26
+ chars = []
27
+ t = consume_and_store r, chars
28
+
29
+ Process.wait pid
30
+
31
+ wait_until_streams_are_ready [slave, err_read]
32
+
33
+ join_threads [t_out, t_err, t]
34
+
35
+ close_streams [master, slave, err_read, err_write]
36
+
37
+ result = Marshal.load(chars.join)
38
+ raise result[:error] if result[:error]
39
+
40
+ result[:result]
41
+ end
42
+
43
+ def consume_and_store(reader, store)
44
+ t = Thread.new do
45
+ sleep 0.1 until reader.ready?
46
+ 3.times do
47
+ store << reader.getc while reader.ready?
48
+ end
49
+ end
50
+ t
51
+ end
52
+
53
+ def wait_until_streams_are_ready(streams)
54
+ streams.each do |s|
55
+ loop { break unless s.ready? }
56
+ end
57
+ end
58
+
59
+ def join_threads(threads)
60
+ threads.each do |t|
61
+ begin
62
+ Timeout.timeout(0.1) { t.join }
63
+ rescue Timeout::Error
64
+ nil
65
+ end
66
+ end
67
+ end
68
+
69
+ def close_streams(streams)
70
+ streams.each(&:close)
71
+ end
72
+
73
+ def run_on_fork(cmd, err_w, out_w, socket_w)
19
74
  pid = fork do
20
- STDERR.reopen err_write
21
- STDOUT.reopen master
75
+ STDERR.reopen err_w
76
+ STDOUT.reopen out_w
22
77
  begin
23
78
  result = cmd.call
24
79
  obj = { result: result, error: nil }
@@ -27,43 +82,12 @@ module PrettyMultitask
27
82
  new_error.set_backtrace e.backtrace
28
83
  Logger.new(STDERR).error new_error
29
84
  obj = { result: nil, error: new_error }
30
- File.open('/tmp/error','w+'){|f| f.puts obj.to_yaml}
31
- w.puts Marshal.dump(obj), 0
85
+ socket_w.puts Marshal.dump(obj), 0
32
86
  end
33
- w.puts Marshal.dump(obj), 0
34
- w.close
87
+ socket_w.puts Marshal.dump(obj), 0
88
+ socket_w.close
35
89
  end
36
-
37
- t_out = consume_and_print slave, out, name, false
38
- t_err = consume_and_print err_read, out, name, true
39
-
40
- %i[slave err_read].each do |e|
41
- loop { break unless binding.local_variable_get(e).ready? }
42
- end
43
-
44
- begin
45
- Timeout.timeout(0.1) do
46
- %i[t_out t_err].each { |e| binding.local_variable_get(e).join }
47
- end
48
- rescue Timeout::Error
49
- nil
50
- end
51
-
52
- %i[master slave err_read err_write].each { |e| binding.local_variable_get(e).close }
53
-
54
- chars = []
55
- t = Thread.new do
56
- sleep 0.1 until r.ready?
57
- chars << r.getc while r.ready?
58
- end
59
-
60
- Process.wait pid
61
- Timeout.timeout(1) { t.join }
62
-
63
- result = Marshal.load(chars.join)
64
- raise result[:error] if result[:error]
65
-
66
- result[:result]
90
+ pid
67
91
  end
68
92
 
69
93
  def consume_and_print(reader, writer, name, error = false)
@@ -74,10 +98,12 @@ module PrettyMultitask
74
98
  colored = Color.green format(fmt, name) unless error
75
99
  reader.each_line do |line|
76
100
  writer.write "#{colored} #{line}"
77
- File.open(@opts[:out_file],'a+') do |f|
101
+ next unless @opts[:out_file]
102
+
103
+ File.open(@opts[:out_file], 'a+') do |f|
78
104
  f.puts "#{colored} #{line}" if error
79
105
  f.puts "#{colored} #{line}" unless error
80
- end if @opts[:out_file]
106
+ end
81
107
  end
82
108
  rescue Errno::EIO
83
109
  nil
@@ -1,46 +1,54 @@
1
- module PrettyMultitask
1
+ # frozen_string_literal: true
2
2
 
3
- LOGGER ||= Logger.new STDOUT
3
+ module PrettyMultitask
4
+ # This class will run multiple callables in parallel using RunCallable which add a nice format
4
5
  class Runner
6
+ LOGGER ||= Logger.new STDOUT
5
7
  def initialize(jobs)
6
8
  @jobs = jobs
7
9
  @jobs.each do |j|
8
- [:name, :cmd ].each {|o| raise "#{o} must be specified for job #{j}" unless j[o] }
10
+ %i[name cmd].each { |o| raise "#{o} must be specified for job #{j}" unless j[o] }
9
11
  j[:out_file] = "/tmp/#{j[:name]}-#{Time.now.strftime('%s.%N')}"
12
+ FileUtils.touch j[:out_file]
10
13
  end
11
14
  end
12
-
15
+
13
16
  def run
14
17
  exec = Tlopo::Executor.new 10
15
-
16
- longest= 0
17
- @jobs.each {|job| longest = job[:name].length if job[:name].length > longest }
18
- @jobs.each {|job| job[:padding] = longest }
19
-
18
+
19
+ @jobs.each { |job| job[:padding] = longest_jobname }
20
20
  @jobs.each do |j|
21
21
  task = proc { j[:exit_status] = RunCallable.new(j).run }
22
22
  exec.schedule task
23
23
  end
24
24
  errors = exec.run.errors
25
-
25
+
26
+ print_out
27
+
28
+ unless errors.empty?
29
+ errors.each { |e| LOGGER.error e }
30
+ raise 'Found errors'
31
+ end
32
+ end
33
+
34
+ def print_out
26
35
  @jobs.each do |j|
27
36
  label = "[ #{j[:name]} ]"
28
37
  width = IO.console.winsize[-1]
29
- left = '='*((width - label.length)/2)
38
+ left = '=' * ((width - label.length) / 2)
30
39
  right = j[:name].length.even? ? left : left + '='
31
40
  puts "\n"
32
- puts Color.yellow left + label + right
41
+ puts Color.yellow left + label + right
33
42
  puts File.read j[:out_file]
34
- puts Color.yellow "="*width
43
+ puts Color.yellow '=' * width
35
44
  File.delete j[:out_file]
36
45
  end
37
-
38
- unless errors.empty?
39
- errors.each {|e| LOGGER.error e}
40
- raise 'Found errors'
41
- end
42
46
  end
43
-
44
- end
45
47
 
48
+ def longest_jobname
49
+ longest = 0
50
+ @jobs.each { |job| longest = job[:name].length if job[:name].length > longest }
51
+ longest
52
+ end
53
+ end
46
54
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrettyMultitask
4
+ module Trapper
5
+ module_function
6
+
7
+ PIDS ||= Set.new
8
+ def trap(pid)
9
+ PIDS << pid
10
+ %w[SIGINT SIGTERM SIGHUP].each do |sig|
11
+ Signal.trap(sig) do
12
+ begin
13
+ PIDS.each { |pid| Process.kill sig, pid }
14
+ rescue Errno::ESRCH
15
+ nil
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module PrettyMultitask
2
- VERSION = "0.1.6"
4
+ VERSION = '0.1.11'
3
5
  end
@@ -1,38 +1,40 @@
1
- # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "pretty_multitask/version"
5
+ require 'pretty_multitask/version'
5
6
 
6
7
  Gem::Specification.new do |spec|
7
- spec.name = "pretty_multitask"
8
+ spec.name = 'pretty_multitask'
8
9
  spec.version = PrettyMultitask::VERSION
9
- spec.authors = ["Tiago Lopo Da Silva"]
10
- spec.email = ["tiagolopo@yahoo.com.br"]
10
+ spec.authors = ['Tiago Lopo Da Silva']
11
+ spec.email = ['tiagolopo@yahoo.com.br']
11
12
 
12
- spec.summary = %q{Multitask with pretty output for Rake}
13
- spec.description = %q{Multitask with pretty output for Rake}
14
- spec.homepage = "https://github.com/tlopo-ruby/tlopo-executor"
15
- spec.license = "MIT"
13
+ spec.summary = 'Multitask with pretty output for Rake'
14
+ spec.description = 'Multitask with pretty output for Rake'
15
+ spec.homepage = 'https://github.com/tlopo-ruby/tlopo-executor'
16
+ spec.license = 'MIT'
16
17
 
17
18
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
19
  # to allow pushing to a single host or delete this section to allow pushing to any host.
19
20
  if spec.respond_to?(:metadata)
20
- #spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
21
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
21
22
  else
22
- raise "RubyGems 2.0 or newer is required to protect against " \
23
- "public gem pushes."
23
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
24
+ 'public gem pushes.'
24
25
  end
25
26
 
26
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
28
  f.match(%r{^(test|spec|features)/})
28
29
  end
29
- spec.bindir = "exe"
30
+ spec.bindir = 'exe'
30
31
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
- spec.require_paths = ["lib"]
32
+ spec.require_paths = ['lib']
32
33
 
33
- spec.add_dependency "tlopo-executor", "~> 0.1.0"
34
+ spec.add_dependency 'tlopo-executor', '~> 0.1.0'
35
+ spec.add_dependency 'io-console', '~> 0.4'
34
36
 
35
- spec.add_development_dependency "bundler", "~> 1.15"
36
- spec.add_development_dependency "rake", "~> 10.0"
37
- spec.add_development_dependency "minitest", "~> 5.0"
37
+ spec.add_development_dependency 'bundler', '~> 1.15'
38
+ spec.add_development_dependency 'minitest', '~> 5.0'
39
+ spec.add_development_dependency 'rake', '~> 12.3.3'
38
40
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pretty_multitask
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Lopo Da Silva
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-09 00:00:00.000000000 Z
11
+ date: 2020-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tlopo-executor
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: io-console
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.4'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -39,33 +53,33 @@ dependencies:
39
53
  - !ruby/object:Gem::Version
40
54
  version: '1.15'
41
55
  - !ruby/object:Gem::Dependency
42
- name: rake
56
+ name: minitest
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '10.0'
61
+ version: '5.0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '10.0'
68
+ version: '5.0'
55
69
  - !ruby/object:Gem::Dependency
56
- name: minitest
70
+ name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '5.0'
75
+ version: 12.3.3
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '5.0'
82
+ version: 12.3.3
69
83
  description: Multitask with pretty output for Rake
70
84
  email:
71
85
  - tiagolopo@yahoo.com.br
@@ -74,6 +88,7 @@ extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
76
90
  - ".gitignore"
91
+ - ".rubocop.yml"
77
92
  - ".travis.yml"
78
93
  - CODE_OF_CONDUCT.md
79
94
  - Gemfile
@@ -86,13 +101,14 @@ files:
86
101
  - lib/pretty_multitask/color.rb
87
102
  - lib/pretty_multitask/run_callable.rb
88
103
  - lib/pretty_multitask/runner.rb
104
+ - lib/pretty_multitask/trapper.rb
89
105
  - lib/pretty_multitask/version.rb
90
106
  - pretty_multitask.gemspec
91
107
  homepage: https://github.com/tlopo-ruby/tlopo-executor
92
108
  licenses:
93
109
  - MIT
94
110
  metadata: {}
95
- post_install_message:
111
+ post_install_message:
96
112
  rdoc_options: []
97
113
  require_paths:
98
114
  - lib
@@ -107,8 +123,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
123
  - !ruby/object:Gem::Version
108
124
  version: '0'
109
125
  requirements: []
110
- rubygems_version: 3.0.3
111
- signing_key:
126
+ rubygems_version: 3.1.2
127
+ signing_key:
112
128
  specification_version: 4
113
129
  summary: Multitask with pretty output for Rake
114
130
  test_files: []