fasten 0.5.4 → 0.6.0

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
  SHA256:
3
- metadata.gz: e475b26b22ab143005ca207f29ee7036571b71934a7fa2bba0ea2be74ba1aaab
4
- data.tar.gz: 39429fea342cf0c43e1b84cef14e897a1d12f56a5f11e4c555c28176bfa1cdda
3
+ metadata.gz: 8a62e1fda9d93b3a6740a65e81a53bcb4449910e770572df0b6c1a0d908e70cf
4
+ data.tar.gz: 8bacfb093fe45101875b161fd9fb8385df565f60a1c5714b1866bb57a5e7eea6
5
5
  SHA512:
6
- metadata.gz: 7bd2923a0ae1d4cf5f31b36a3999be1bfec058a99acdd381712e91454e2ed9baf7193bb87de835359b300a9317cdd47f2c92e850c54a36e7dcf26dd88776d720
7
- data.tar.gz: b4307bc7ee694ad3740b0c0b361d4c5a4888f5e405d32b6aa91ceee8c0023ee1a6421771a6915a2f3916d0610cdf5136f329f47076e33bb066e7e3eb4fb572e3
6
+ metadata.gz: 5b466b834558bc93de7d1c6cd01829e7930bc266bf8e0a3f34c34d379f5cc8425c0e60595650a1cc03869c1926eaa2993151406b05e51e4bdfd388a432d00394
7
+ data.tar.gz: 1b47208c3c81702f184ac1878af2ac8fdc9d0390ad926feb7a8f7cb8552cb27a74b4171e372f12da5ec3b36305a229c650d139aa88b07314aaeee16a7bf4925b
@@ -14,3 +14,7 @@ Metrics/AbcSize:
14
14
  Max: 17
15
15
  Metrics/MethodLength:
16
16
  Max: 15
17
+ Metrics/ParameterLists:
18
+ Max: 6
19
+ Layout/AlignHash:
20
+ EnforcedHashRocketStyle: table
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fasten (0.5.4)
4
+ fasten (0.6.0)
5
5
  binding_of_caller
6
- curses
7
6
  hirb
7
+ os
8
8
  parallel
9
9
 
10
10
  GEM
@@ -19,12 +19,13 @@ GEM
19
19
  diff-lcs (1.3)
20
20
  hirb (0.7.3)
21
21
  jaro_winkler (1.5.1)
22
- method_source (0.9.0)
22
+ method_source (0.9.1)
23
+ os (1.0.0)
23
24
  parallel (1.12.1)
24
- parser (2.5.1.2)
25
+ parser (2.5.3.0)
25
26
  ast (~> 2.4.0)
26
27
  powerpack (0.1.2)
27
- pry (0.11.3)
28
+ pry (0.12.0)
28
29
  coderay (~> 1.1.0)
29
30
  method_source (~> 0.9.0)
30
31
  rainbow (3.0.0)
@@ -42,14 +43,14 @@ GEM
42
43
  diff-lcs (>= 1.2.0, < 2.0)
43
44
  rspec-support (~> 3.8.0)
44
45
  rspec-support (3.8.0)
45
- rubocop (0.59.2)
46
+ rubocop (0.60.0)
46
47
  jaro_winkler (~> 1.5.1)
47
48
  parallel (~> 1.10)
48
49
  parser (>= 2.5, != 2.5.1.1)
49
50
  powerpack (~> 0.1)
50
51
  rainbow (>= 2.2.2, < 4.0)
51
52
  ruby-progressbar (~> 1.7)
52
- unicode-display_width (~> 1.0, >= 1.0.1)
53
+ unicode-display_width (~> 1.4.0)
53
54
  ruby-progressbar (1.10.0)
54
55
  unicode-display_width (1.4.0)
55
56
 
@@ -57,7 +58,8 @@ PLATFORMS
57
58
  ruby
58
59
 
59
60
  DEPENDENCIES
60
- bundler (~> 1.16)
61
+ bundler (~> 1.17.1)
62
+ curses
61
63
  fasten!
62
64
  pry
63
65
  rake (~> 10.0)
@@ -65,4 +67,4 @@ DEPENDENCIES
65
67
  rubocop
66
68
 
67
69
  BUNDLED WITH
68
- 1.16.6
70
+ 1.17.1
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fasten'
4
+
5
+ Fasten.invoke
@@ -1,6 +1,7 @@
1
1
  lib = File.expand_path('lib', __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require 'fasten/version'
4
+ require 'os'
4
5
 
5
6
  Gem::Specification.new do |spec|
6
7
  spec.name = 'fasten'
@@ -22,15 +23,16 @@ Gem::Specification.new do |spec|
22
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
24
  spec.require_paths = ['lib']
24
25
 
25
- spec.add_development_dependency 'bundler', '~> 1.16'
26
+ spec.add_development_dependency 'bundler', '~> 1.17.1'
27
+ spec.add_development_dependency 'curses' unless OS.windows?
26
28
  spec.add_development_dependency 'pry'
27
29
  spec.add_development_dependency 'rake', '~> 10.0'
28
30
  spec.add_development_dependency 'rspec', '~> 3.0'
29
31
  spec.add_development_dependency 'rubocop'
30
32
 
31
33
  spec.add_runtime_dependency 'binding_of_caller'
32
- spec.add_runtime_dependency 'curses'
33
34
  spec.add_runtime_dependency 'hirb'
35
+ spec.add_runtime_dependency 'os'
34
36
  spec.add_runtime_dependency 'parallel'
35
37
 
36
38
  raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' unless spec.respond_to?(:metadata)
@@ -1,50 +1,105 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'English'
4
- require 'yaml'
5
- require 'binding_of_caller'
6
- require 'logger'
7
- require 'ostruct'
8
- require 'curses'
9
- require 'fileutils'
10
- require 'csv'
11
- require 'hirb'
12
- require 'parallel'
13
-
14
- require 'fasten/state'
15
- require 'fasten/logger'
16
- require 'fasten/stats'
3
+ require 'optparse'
17
4
  require 'fasten/task'
18
- require 'fasten/ui'
19
- require 'fasten/dag'
20
- require 'fasten/yaml'
21
- require 'fasten/executor'
5
+ require 'fasten/runner'
22
6
  require 'fasten/worker'
23
7
  require 'fasten/version'
24
8
 
25
9
  module Fasten
26
10
  class << self
27
- include Fasten::Logger
11
+ def runner_from_yaml(path, **options)
12
+ runner = Fasten::Runner.new(**options)
13
+ runner.load_yaml(path)
28
14
 
29
- def from_yaml(path, **options)
30
- executor = Fasten::Executor.new(**options)
31
- executor.load_yaml(path)
32
-
33
- executor
15
+ runner
34
16
  end
35
17
 
36
18
  def map(list, **options, &block)
37
- executor = Fasten::Executor.new(**options)
38
- executor.block = block
19
+ runner(**options).map(list, &block)
20
+ end
21
+
22
+ def runner(**options)
23
+ @runner ||= Fasten::Runner.new(**options)
24
+ end
25
+
26
+ def cleanup
27
+ @runner = nil
28
+ end
39
29
 
40
- list.each do |item|
41
- executor.add Fasten::Task.new name: item.to_s, request: item
30
+ def reconfigure(**options)
31
+ runner.reconfigure(**options)
32
+ end
33
+
34
+ def register(**options, &block)
35
+ runner(**options).register(&block)
36
+ end
37
+
38
+ def load_fasten(args)
39
+ args.each do |path|
40
+ if File.directory? path
41
+ items = Dir["#{path}/*_fasten.rb"]
42
+ items.each do |item|
43
+ puts "Fasten: loading #{item}"
44
+ load item
45
+ end
46
+ elsif File.file? path
47
+ puts "Fasten: loading #{path}"
48
+ load path
49
+ else
50
+ STDERR.puts "Fasten: file/folder not found: #{path}"
51
+ exit 1
52
+ end
42
53
  end
54
+ end
55
+
56
+ def opt_parser # rubocop:disable Metrics/MethodLength
57
+ return @opt_parser if defined? @opt_parser
58
+
59
+ @options = { developer: false }
60
+
61
+ @opt_parser = OptionParser.new do |opts|
62
+ opts.banner = "Usage: #{$PROGRAM_NAME} [options] FILE/DIRECTORY"
63
+ opts.separator ''
64
+ opts.separator 'Options'
65
+
66
+ opts.on '-n', '--name NAME', String, "Name of this job" do |name|
67
+ @options[:name] = name
68
+ end
69
+ opts.on '-w', '--workers WORKERS', Numeric, "Number of processes/threads to use (#{Parallel.physical_processor_count} on this machine)" do |workers|
70
+ @options[:workers] = workers
71
+ end
72
+ opts.on '-t', '--threads' do
73
+ @options[:use_threads] = true
74
+ end
75
+ opts.on '-p', '--processes' do
76
+ @options[:use_threads] = false
77
+ end
78
+ opts.on '-v', '--version' do
79
+ puts Fasten::VERSION
80
+ exit 0
81
+ end
82
+ opts.on_tail '-h', '--help' do
83
+ puts opts
84
+ exit 0
85
+ end
86
+ end
87
+ end
88
+
89
+ def show_help
90
+ puts opt_parser
91
+ exit 1
92
+ end
93
+
94
+ def invoke
95
+ opt_parser.parse!
96
+
97
+ show_help if ARGV.length.zero?
43
98
 
44
- executor.perform
45
- executor.stats_table
99
+ runner(@options)
100
+ load_fasten ARGV
46
101
 
47
- executor.task_list.map(&:response)
102
+ runner.perform
48
103
  end
49
104
  end
50
105
  end
@@ -1,33 +1,58 @@
1
+ require 'English'
2
+ require 'parallel'
3
+ require 'pry'
4
+ require 'os'
5
+
6
+ require 'fasten/support/dag'
7
+ require 'fasten/support/logger'
8
+ require 'fasten/support/state'
9
+ require 'fasten/support/stats'
10
+ require 'fasten/support/ui'
11
+ require 'fasten/support/yaml'
12
+ require 'fasten/timeout_queue'
13
+
1
14
  module Fasten
2
- class Executor
3
- include Fasten::Logger
4
- include Fasten::State
5
- include Fasten::DAG
6
- include Fasten::UI
7
- include Fasten::Yaml
8
- include Fasten::Stats
9
-
10
- attr_accessor :name, :workers, :worker_class, :pid, :fasten_dir, :developer, :stats, :worker_list, :block
11
-
12
- def initialize(name: nil, developer: STDIN.tty? && STDOUT.tty?, workers: Parallel.physical_processor_count, worker_class: Worker, fasten_dir: '.fasten')
13
- self.stats = name && true
14
- self.name = name || "#{self.class} #{$PID}"
15
- self.state = :IDLE
16
- self.workers = workers
17
- self.worker_class = worker_class
18
- self.fasten_dir = fasten_dir
19
- self.developer = developer
15
+ class Runner
16
+ include Fasten::Support::DAG
17
+ include Fasten::Support::Logger
18
+ include Fasten::Support::State
19
+ include Fasten::Support::Stats
20
+ include Fasten::Support::UI
21
+ include Fasten::Support::Yaml
22
+
23
+ attr_accessor :name, :workers, :worker_class, :fasten_dir, :developer, :stats, :worker_list, :use_threads, :queue
24
+
25
+ def initialize(name: nil, developer: STDIN.tty? && STDOUT.tty?, workers: Parallel.physical_processor_count, worker_class: Worker, fasten_dir: '.fasten', use_threads: !OS.posix?)
26
+ reconfigure(name: name, developer: developer, workers: workers, worker_class: worker_class, fasten_dir: fasten_dir, use_threads: use_threads)
27
+ end
28
+
29
+ def reconfigure(**options)
30
+ self.stats = options[:name] && true if options[:name] || options.key?(:stats)
31
+ self.name = options[:name] || "#{self.class} #{$PID}" if options[:name]
32
+ self.workers = options[:workers] if options[:workers]
33
+ self.worker_class = options[:worker_class] if options[:worker_class]
34
+ self.fasten_dir = options[:fasten_dir] if options[:fasten_dir]
35
+ self.developer = options[:developer] if options[:developer]
36
+ self.use_threads = options[:use_threads] if options[:use_threads]
20
37
 
21
38
  initialize_dag
22
39
  initialize_stats
23
40
  initialize_logger
24
41
 
25
- self.worker_list = []
42
+ self.worker_list ||= []
43
+ end
44
+
45
+ def task(name, **opts, &block)
46
+ add Task.new(name: name, **opts, block: block)
47
+ end
48
+
49
+ def register(&block)
50
+ instance_eval(&block)
26
51
  end
27
52
 
28
53
  def perform
29
- log_ini self, running_counters
30
54
  self.state = :RUNNING
55
+ log_ini self, running_counters
31
56
  load_stats
32
57
 
33
58
  run_ui do
@@ -38,9 +63,20 @@ module Fasten
38
63
  log_fin self, running_counters
39
64
 
40
65
  stats_add_entry(state, self)
66
+ ensure
41
67
  save_stats
42
68
  end
43
69
 
70
+ def map(list, &block)
71
+ list.each do |item|
72
+ add Fasten::Task.new name: item.to_s, request: item, block: block
73
+ end
74
+
75
+ perform
76
+
77
+ task_list.map(&:response)
78
+ end
79
+
44
80
  def done_counters
45
81
  "#{task_done_list.count}/#{task_list.count}"
46
82
  end
@@ -82,22 +118,53 @@ module Fasten
82
118
  end
83
119
 
84
120
  def wait_for_running_tasks
121
+ use_threads ? wait_for_running_tasks_thread : wait_for_running_tasks_fork
122
+ end
123
+
124
+ def wait_for_running_tasks_thread
125
+ self.queue ||= TimeoutQueue.new
126
+
127
+ while should_wait_for_running_tasks?
128
+ ui.update
129
+
130
+ tasks = queue.receive_with_timeout(0.5)
131
+
132
+ receive_workers_tasks_thread(tasks)
133
+ end
134
+
135
+ ui.update
136
+ end
137
+
138
+ def receive_workers_tasks_thread(tasks)
139
+ tasks&.each do |task|
140
+ task_running_list.delete task
141
+
142
+ task.worker.running_task = task.worker.state = nil
143
+
144
+ update_task task
145
+
146
+ log_fin task, done_counters
147
+ ui.force_clear
148
+ end
149
+ end
150
+
151
+ def wait_for_running_tasks_fork
85
152
  while should_wait_for_running_tasks?
86
153
  ui.update
87
154
  reads = worker_list.map(&:parent_read)
88
- reads, _writes, _errors = IO.select(reads, [], [], 1)
155
+ reads, _writes, _errors = IO.select(reads, [], [], 0.5)
89
156
 
90
- receive_workers_tasks(reads)
157
+ receive_workers_tasks_fork(reads)
91
158
  end
92
159
 
93
160
  ui.update
94
161
  end
95
162
 
96
- def receive_workers_tasks(reads)
163
+ def receive_workers_tasks_fork(reads)
97
164
  reads&.each do |read|
98
165
  next unless (worker = worker_list.find { |item| item.parent_read == read })
99
166
 
100
- task = worker.receive_response
167
+ task = worker.receive_response_from_child
101
168
 
102
169
  task_running_list.delete task
103
170
 
@@ -151,9 +218,8 @@ module Fasten
151
218
 
152
219
  unless worker
153
220
  @worker_id = (@worker_id || 0) + 1
154
- worker = worker_class.new executor: self, name: "#{worker_class}-#{format '%02X', @worker_id}"
155
- worker.block = block if block
156
- worker.fork
221
+ worker = worker_class.new runner: self, name: "#{worker_class}-#{format '%02X', @worker_id}", use_threads: use_threads
222
+ worker.start
157
223
  worker_list << worker
158
224
 
159
225
  log_info "Worker created: #{worker}"
@@ -170,7 +236,7 @@ module Fasten
170
236
 
171
237
  task = next_task
172
238
  log_ini task, "on worker #{worker}"
173
- worker.send_request(task)
239
+ worker.send_request_to_child(task)
174
240
  task_running_list << task
175
241
 
176
242
  ui.force_clear
@@ -183,5 +249,13 @@ module Fasten
183
249
 
184
250
  ui.force_clear
185
251
  end
252
+
253
+ def kind
254
+ 'runner'
255
+ end
256
+
257
+ def to_s
258
+ name
259
+ end
186
260
  end
187
261
  end
@@ -0,0 +1,56 @@
1
+ module Fasten
2
+ class StdThreadProxy
3
+ def initialize(original)
4
+ @original = original
5
+ end
6
+
7
+ def respond_to?(name, include_private = false)
8
+ target = Thread.current[:FASTEN_STD_THREAD_PROXY] || @original
9
+ target.send :respond_to?, name, include_private
10
+ end
11
+
12
+ private
13
+
14
+ def respond_to_missing?(name, include_private = false)
15
+ target = Thread.current[:FASTEN_STD_THREAD_PROXY] || @original
16
+ target.send :respond_to_missing?, name, include_private
17
+ end
18
+
19
+ def method_missing(method, *args, &block) # rubocop:disable MethodMissingSuper
20
+ target = Thread.current[:FASTEN_STD_THREAD_PROXY] || @original
21
+ target.send method, *args, &block
22
+ end
23
+
24
+ class << self
25
+ def install
26
+ return if @installed
27
+
28
+ oldverbose = $VERBOSE
29
+ $VERBOSE = nil
30
+
31
+ Object.const_set :STDOUT, StdThreadProxy.new(STDOUT)
32
+ Object.const_set :STDERR, StdThreadProxy.new(STDERR)
33
+ $stdout = StdThreadProxy.new $stdout
34
+ $stderr = StdThreadProxy.new $stderr
35
+
36
+ @installed = true
37
+ ensure
38
+ $VERBOSE = oldverbose
39
+ end
40
+
41
+ def thread_io=(io)
42
+ Thread.current[:FASTEN_STD_THREAD_PROXY] = io
43
+ end
44
+
45
+ def thread_io
46
+ Thread.current[:FASTEN_STD_THREAD_PROXY]
47
+ end
48
+
49
+ def uninstall
50
+ return unless @installed
51
+
52
+ @installed = nil
53
+ end
54
+ end
55
+ end
56
+ end