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 +4 -4
- data/.rubocop.yml +4 -0
- data/Gemfile.lock +11 -9
- data/exe/fasten +5 -0
- data/fasten.gemspec +4 -2
- data/lib/fasten.rb +86 -31
- data/lib/fasten/{executor.rb → runner.rb} +102 -28
- data/lib/fasten/std_thread_proxy.rb +56 -0
- data/lib/fasten/support/dag.rb +130 -0
- data/lib/fasten/support/fork_worker.rb +107 -0
- data/lib/fasten/support/logger.rb +57 -0
- data/lib/fasten/support/state.rb +32 -0
- data/lib/fasten/support/stats.rb +137 -0
- data/lib/fasten/support/thread_worker.rb +61 -0
- data/lib/fasten/support/ui.rb +22 -0
- data/lib/fasten/support/yaml.rb +54 -0
- data/lib/fasten/task.rb +16 -7
- data/lib/fasten/timeout_queue.rb +36 -0
- data/lib/fasten/ui/console.rb +7 -7
- data/lib/fasten/ui/curses.rb +26 -22
- data/lib/fasten/version.rb +1 -1
- data/lib/fasten/worker.rb +48 -81
- metadata +34 -14
- data/lib/fasten/dag.rb +0 -137
- data/lib/fasten/logger.rb +0 -62
- data/lib/fasten/state.rb +0 -30
- data/lib/fasten/stats.rb +0 -137
- data/lib/fasten/ui.rb +0 -18
- data/lib/fasten/yaml.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a62e1fda9d93b3a6740a65e81a53bcb4449910e770572df0b6c1a0d908e70cf
|
4
|
+
data.tar.gz: 8bacfb093fe45101875b161fd9fb8385df565f60a1c5714b1866bb57a5e7eea6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b466b834558bc93de7d1c6cd01829e7930bc266bf8e0a3f34c34d379f5cc8425c0e60595650a1cc03869c1926eaa2993151406b05e51e4bdfd388a432d00394
|
7
|
+
data.tar.gz: 1b47208c3c81702f184ac1878af2ac8fdc9d0390ad926feb7a8f7cb8552cb27a74b4171e372f12da5ec3b36305a229c650d139aa88b07314aaeee16a7bf4925b
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fasten (0.
|
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.
|
22
|
+
method_source (0.9.1)
|
23
|
+
os (1.0.0)
|
23
24
|
parallel (1.12.1)
|
24
|
-
parser (2.5.
|
25
|
+
parser (2.5.3.0)
|
25
26
|
ast (~> 2.4.0)
|
26
27
|
powerpack (0.1.2)
|
27
|
-
pry (0.
|
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.
|
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.
|
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.
|
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.
|
70
|
+
1.17.1
|
data/exe/fasten
ADDED
data/fasten.gemspec
CHANGED
@@ -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.
|
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)
|
data/lib/fasten.rb
CHANGED
@@ -1,50 +1,105 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
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/
|
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
|
-
|
11
|
+
def runner_from_yaml(path, **options)
|
12
|
+
runner = Fasten::Runner.new(**options)
|
13
|
+
runner.load_yaml(path)
|
28
14
|
|
29
|
-
|
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
|
-
|
38
|
-
|
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
|
-
|
41
|
-
|
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
|
-
|
45
|
-
|
99
|
+
runner(@options)
|
100
|
+
load_fasten ARGV
|
46
101
|
|
47
|
-
|
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
|
3
|
-
include Fasten::
|
4
|
-
include Fasten::
|
5
|
-
include Fasten::
|
6
|
-
include Fasten::
|
7
|
-
include Fasten::
|
8
|
-
include Fasten::
|
9
|
-
|
10
|
-
attr_accessor :name, :workers, :worker_class, :
|
11
|
-
|
12
|
-
def initialize(name: nil, developer: STDIN.tty? && STDOUT.tty?, workers: Parallel.physical_processor_count, worker_class: Worker, fasten_dir: '.fasten')
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
self.
|
18
|
-
self.
|
19
|
-
self.
|
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, [], [],
|
155
|
+
reads, _writes, _errors = IO.select(reads, [], [], 0.5)
|
89
156
|
|
90
|
-
|
157
|
+
receive_workers_tasks_fork(reads)
|
91
158
|
end
|
92
159
|
|
93
160
|
ui.update
|
94
161
|
end
|
95
162
|
|
96
|
-
def
|
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.
|
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
|
155
|
-
worker.
|
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.
|
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
|