pretty_multitask 0.1.7 → 0.1.8

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: 855e2f7b1a3ddf9492a15002917bad4a6b72fd0bbec804e40adc12d9e9736730
4
- data.tar.gz: fb5d4f8224dd483d1dc6730fd4f9be2145aee5b3f0a560790524fa53a4a0882d
3
+ metadata.gz: a6d5c09df7c6d302bcb593e960369610d59fe42a0a30325138578e72d1cf8f9c
4
+ data.tar.gz: 57162253ef143f8865477141490d0f1839920bdd70d36a95154c3938d79b06d5
5
5
  SHA512:
6
- metadata.gz: 855889a02269799b938d12af331850b8fa1f3e19a9f2ef912f46c04690a26e1160761ee85195538b82e26c383fb1c7a95cd565bf8bc5510d83db056a5e830b9e
7
- data.tar.gz: 4991776fa6b3ab42143f4e627e3c33a519a9fe099f9cf8c51b51931160214fd8f044352dff9cd62421e781ae43c90ade0a7330fa484f4f3d218137ebe16df098
6
+ metadata.gz: 5c6c07f9165c2fa8add57d0647e64d936a915f54c4f09596f5a1160dcb46f1d537677124384d8f71021fb3f64cc0c85e255ffa8c63be7b25463ae83d3c60c4f9
7
+ data.tar.gz: 85526699eaa75ab56932d9de650cc2eb46991a1449ad3e3872bb0f04fc7ef2b725b5ae85d45980cbe51adb773e45d7416352771bd82cc005f24808f8177e82c2
data/.rubocop.yml ADDED
@@ -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
data/bin/console CHANGED
@@ -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,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,72 +1,92 @@
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
- pid = fork do
20
- STDERR.reopen err_write
21
- STDOUT.reopen master
22
- begin
23
- result = cmd.call
24
- obj = { result: result, error: nil }
25
- rescue StandardError => e
26
- new_error = e.class.new(e.message)
27
- new_error.set_backtrace e.backtrace
28
- Logger.new(STDERR).error new_error
29
- 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
32
- end
33
- w.puts Marshal.dump(obj), 0
34
- w.close
35
- end
19
+
20
+ pid = run_on_fork(cmd, err_write, master, w)
36
21
 
37
22
  t_out = consume_and_print slave, out, name, false
38
23
  t_err = consume_and_print err_read, out, name, true
39
24
 
40
25
  chars = []
26
+ t = consume_and_store r, chars
27
+
28
+ Process.wait pid
29
+
30
+ wait_until_streams_are_ready [slave, err_read]
31
+
32
+ join_threads [t_out, t_err, t]
33
+
34
+ close_streams [master, slave, err_read, err_write]
35
+
36
+ result = Marshal.load(chars.join)
37
+ raise result[:error] if result[:error]
38
+
39
+ result[:result]
40
+ end
41
+
42
+ def consume_and_store(reader, store)
41
43
  t = Thread.new do
42
- sleep 0.1 until r.ready?
43
- (1..3).each do
44
- chars << r.getc while r.ready?
44
+ sleep 0.1 until reader.ready?
45
+ 3.times do
46
+ store << reader.getc while reader.ready?
45
47
  end
46
48
  end
49
+ t
50
+ end
47
51
 
48
- Process.wait pid
49
- Timeout.timeout(1) { t.join }
50
-
51
- %i[slave err_read].each do |e|
52
- loop { break unless binding.local_variable_get(e).ready? }
52
+ def wait_until_streams_are_ready(streams)
53
+ streams.each do |s|
54
+ loop { break unless s.ready? }
53
55
  end
54
-
55
- begin
56
- Timeout.timeout(0.1) do
57
- %i[t_out t_err].each { |e| binding.local_variable_get(e).join }
56
+ end
57
+
58
+ def join_threads(threads)
59
+ threads.each do |t|
60
+ begin
61
+ Timeout.timeout(0.1) { t.join }
62
+ rescue Timeout::Error
63
+ nil
58
64
  end
59
- rescue Timeout::Error
60
- nil
61
65
  end
62
-
63
- %i[master slave err_read err_write].each { |e| binding.local_variable_get(e).close }
64
-
65
-
66
- result = Marshal.load(chars.join)
67
- raise result[:error] if result[:error]
68
-
69
- result[:result]
66
+ end
67
+
68
+ def close_streams(streams)
69
+ streams.each(&:close)
70
+ end
71
+
72
+ def run_on_fork(cmd, err_w, out_w, socket_w)
73
+ pid = fork do
74
+ STDERR.reopen err_w
75
+ STDOUT.reopen out_w
76
+ begin
77
+ result = cmd.call
78
+ obj = { result: result, error: nil }
79
+ rescue StandardError => e
80
+ new_error = e.class.new(e.message)
81
+ new_error.set_backtrace e.backtrace
82
+ Logger.new(STDERR).error new_error
83
+ obj = { result: nil, error: new_error }
84
+ socket_w.puts Marshal.dump(obj), 0
85
+ end
86
+ socket_w.puts Marshal.dump(obj), 0
87
+ socket_w.close
88
+ end
89
+ pid
70
90
  end
71
91
 
72
92
  def consume_and_print(reader, writer, name, error = false)
@@ -77,10 +97,12 @@ module PrettyMultitask
77
97
  colored = Color.green format(fmt, name) unless error
78
98
  reader.each_line do |line|
79
99
  writer.write "#{colored} #{line}"
80
- File.open(@opts[:out_file],'a+') do |f|
100
+ next unless @opts[:out_file]
101
+
102
+ File.open(@opts[:out_file], 'a+') do |f|
81
103
  f.puts "#{colored} #{line}" if error
82
104
  f.puts "#{colored} #{line}" unless error
83
- end if @opts[:out_file]
105
+ end
84
106
  end
85
107
  rescue Errno::EIO
86
108
  nil
@@ -1,47 +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')}"
10
12
  FileUtils.touch j[:out_file]
11
13
  end
12
14
  end
13
-
15
+
14
16
  def run
15
17
  exec = Tlopo::Executor.new 10
16
-
17
- longest= 0
18
- @jobs.each {|job| longest = job[:name].length if job[:name].length > longest }
19
- @jobs.each {|job| job[:padding] = longest }
20
-
18
+
19
+ @jobs.each { |job| job[:padding] = longest_jobname }
21
20
  @jobs.each do |j|
22
21
  task = proc { j[:exit_status] = RunCallable.new(j).run }
23
22
  exec.schedule task
24
23
  end
25
24
  errors = exec.run.errors
26
-
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
27
35
  @jobs.each do |j|
28
36
  label = "[ #{j[:name]} ]"
29
37
  width = IO.console.winsize[-1]
30
- left = '='*((width - label.length)/2)
38
+ left = '=' * ((width - label.length) / 2)
31
39
  right = j[:name].length.even? ? left : left + '='
32
40
  puts "\n"
33
- puts Color.yellow left + label + right
41
+ puts Color.yellow left + label + right
34
42
  puts File.read j[:out_file]
35
- puts Color.yellow "="*width
43
+ puts Color.yellow '=' * width
36
44
  File.delete j[:out_file]
37
45
  end
38
-
39
- unless errors.empty?
40
- errors.each {|e| LOGGER.error e}
41
- raise 'Found errors'
42
- end
43
46
  end
44
-
45
- end
46
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
47
54
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module PrettyMultitask
2
- VERSION = "0.1.7"
4
+ VERSION = '0.1.8'
3
5
  end
@@ -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'
@@ -9,6 +11,7 @@ require 'timeout'
9
11
  require 'yaml'
10
12
  require 'fileutils'
11
13
 
14
+ # Main module
12
15
  module PrettyMultitask
13
16
  require "#{__dir__}/pretty_multitask/color"
14
17
  require "#{__dir__}/pretty_multitask/runner"
@@ -16,15 +19,16 @@ module PrettyMultitask
16
19
  end
17
20
 
18
21
  def pretty_multitask(hash)
19
- name, tasks = hash.keys.first, hash.values.first
22
+ name = hash.keys.first
23
+ tasks = hash.values.first
20
24
  task name do
21
25
  jobs = []
22
26
  tasks.each do |t|
23
- job = Proc.new do
27
+ job = proc do
24
28
  Rake::Task[t].invoke
25
29
  nil
26
30
  end
27
- jobs.push({ name: t, cmd: job})
31
+ jobs.push({ name: t, cmd: job })
28
32
  end
29
33
  PrettyMultitask::Runner.new(jobs).run
30
34
  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,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pretty_multitask
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Lopo Da Silva
@@ -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