pretty_multitask 0.1.4 → 0.1.9

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: 6892e4801fcb0acf2573634a7a60351721529a14059005a0ba1c4628351622b6
4
- data.tar.gz: 3f1e010533490768951b4badcd44869398c640f16722c3020aa595733d76ca77
3
+ metadata.gz: 3925750f68500c7985c8b7232c197d09b42eabf80d1d16f45cce3d8c7e99626b
4
+ data.tar.gz: 4bea26717393ed203c85d9116fe0e56e5d31e86bef474ea72940349ea028aaef
5
5
  SHA512:
6
- metadata.gz: 99c9ce3d7c641820f5e84530cb1c9f9ce111c38bcd1da7cd9239dc77a59c4c5b6b76a910a9f4ac0ceb26f68629bf9ac3ab38808cd12030a5cf7544cac09edaf1
7
- data.tar.gz: '015947fdd16c4a74fab04378cd7ac3aded372ef1c9e7c9948f9a17a5247eb34e4f99fbeda49696f5b35c251f8b9206ad5969a600baacd2dc49b266530b8023de'
6
+ metadata.gz: b956e25b5c4d0c493da585214be1d56fe2f3da5691057c6a0955fb50a4ac8a4cf81764afabef786e8c326d6dbc6273235da027b4d46f480f62d94a6ed3e09973
7
+ data.tar.gz: 05e93b9eee198a1ec2a816fcbaac69bcdbf8ebbb9e402324d8cba26e0faf4a949afa8ee96e596c2e1b50ddf308f6978e0330ed31c095452adbc0b84962bca3ce
@@ -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,27 @@ require 'io/wait'
7
9
  require 'socket'
8
10
  require 'timeout'
9
11
  require 'yaml'
12
+ require 'fileutils'
10
13
 
14
+ # Main module
11
15
  module PrettyMultitask
16
+ require "#{__dir__}/pretty_multitask/trapper"
12
17
  require "#{__dir__}/pretty_multitask/color"
13
18
  require "#{__dir__}/pretty_multitask/runner"
14
19
  require "#{__dir__}/pretty_multitask/run_callable"
15
20
  end
16
21
 
17
22
  def pretty_multitask(hash)
18
- name, tasks = hash.keys.first, hash.values.first
23
+ name = hash.keys.first
24
+ tasks = hash.values.first
19
25
  task name do
20
26
  jobs = []
21
27
  tasks.each do |t|
22
- job = Proc.new do
28
+ job = proc do
23
29
  Rake::Task[t].invoke
24
30
  nil
25
31
  end
26
- jobs.push({ name: t, cmd: job})
32
+ jobs.push({ name: t, cmd: job })
27
33
  end
28
34
  PrettyMultitask::Runner.new(jobs).run
29
35
  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,40 +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
- Process.wait pid
41
-
42
- %i[slave err_read].each do |e|
43
- loop { break unless binding.local_variable_get(e).ready? }
44
- end
45
-
46
- begin
47
- Timeout.timeout(0.1) do
48
- %i[t_out t_err].each { |e| binding.local_variable_get(e).join }
49
- end
50
- rescue Timeout::Error
51
- nil
52
- end
53
-
54
- %i[master slave err_read err_write].each { |e| binding.local_variable_get(e).close }
55
-
56
- chars = []
57
- chars << r.getc while r.ready?
58
- r.close
59
-
60
- result = Marshal.load(chars.join)
61
- raise result[:error] if result[:error]
62
-
63
- result[:result]
90
+ pid
64
91
  end
65
92
 
66
93
  def consume_and_print(reader, writer, name, error = false)
@@ -71,10 +98,12 @@ module PrettyMultitask
71
98
  colored = Color.green format(fmt, name) unless error
72
99
  reader.each_line do |line|
73
100
  writer.write "#{colored} #{line}"
74
- File.open(@opts[:out_file],'a+') do |f|
101
+ next unless @opts[:out_file]
102
+
103
+ File.open(@opts[:out_file], 'a+') do |f|
75
104
  f.puts "#{colored} #{line}" if error
76
105
  f.puts "#{colored} #{line}" unless error
77
- end if @opts[:out_file]
106
+ end
78
107
  end
79
108
  rescue Errno::EIO
80
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.4"
4
+ VERSION = '0.1.9'
3
5
  end
@@ -1,38 +1,39 @@
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'
34
35
 
35
- spec.add_development_dependency "bundler", "~> 1.15"
36
- spec.add_development_dependency "rake", "~> 10.0"
37
- spec.add_development_dependency "minitest", "~> 5.0"
36
+ spec.add_development_dependency 'bundler', '~> 1.15'
37
+ spec.add_development_dependency 'minitest', '~> 5.0'
38
+ spec.add_development_dependency 'rake', '~> 12.3.3'
38
39
  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.4
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Lopo Da Silva
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-30 00:00:00.000000000 Z
11
+ date: 2020-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tlopo-executor
@@ -39,33 +39,33 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.15'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rake
42
+ name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '5.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: '5.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: minitest
56
+ name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '5.0'
61
+ version: 12.3.3
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '5.0'
68
+ version: 12.3.3
69
69
  description: Multitask with pretty output for Rake
70
70
  email:
71
71
  - tiagolopo@yahoo.com.br
@@ -74,6 +74,7 @@ extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
76
  - ".gitignore"
77
+ - ".rubocop.yml"
77
78
  - ".travis.yml"
78
79
  - CODE_OF_CONDUCT.md
79
80
  - Gemfile
@@ -86,6 +87,7 @@ files:
86
87
  - lib/pretty_multitask/color.rb
87
88
  - lib/pretty_multitask/run_callable.rb
88
89
  - lib/pretty_multitask/runner.rb
90
+ - lib/pretty_multitask/trapper.rb
89
91
  - lib/pretty_multitask/version.rb
90
92
  - pretty_multitask.gemspec
91
93
  homepage: https://github.com/tlopo-ruby/tlopo-executor