fasten 0.7.6 → 0.8.0

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: 0a5f2710522752673a8cbaf767ad0a9310c5cc24e980139ef274c957422ad90b
4
- data.tar.gz: 6f58aa4dbd2a8996e65fa26d70e64e9bb1ac5bd0e4a6d6da05c04919e1b810ea
3
+ metadata.gz: c77fcc3eddc4f86d6b6a2ad36fbeb6f7edb302c6068b65df3dd61d2531e8251a
4
+ data.tar.gz: 3638c6cf10144c9a47bedfca7ada81547c3f2b15a440a81b1c4b8a055bd38d3d
5
5
  SHA512:
6
- metadata.gz: 247189b714300179c8b9ab1ec7bbab9d643b9bb2d7c3aff4fbe6b991debe2345de12e696650985f01c2b1e71efee51e1649ffe2719314c5e8127fedc92d7df4d
7
- data.tar.gz: 71476a45dc759402cbc19972586a3080ebd4e6b6b2a2fbfacfa70ec135336e38a2070e9394c9af2be3ea970fad8a2849f3e1075675484ac4d977dd3055ab43b1
6
+ metadata.gz: 2b0ca6dcec14736e254d66ce33f536f70982923d638403f7e3a4cb0c950e59e74727fb47d847d24a8f9a1a80ad594d0cbae9734ef3ef9bdd7e5cc6b12b913ea5
7
+ data.tar.gz: b1e139f7a7f62677a581a47ca95959919430a13d338e0adf3731d13d2675cbbfeba9a3173d31a5659002da3635a254f6b59cb95060042d77a54cb2faf4359537
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fasten (0.7.6)
4
+ fasten (0.8.0)
5
5
  binding_of_caller
6
6
  hirb
7
7
  os
data/README.md CHANGED
@@ -21,7 +21,7 @@ It has been released so people can try it and make feature requests, comments an
21
21
  ### Execution:
22
22
  - [x] tasks are executed in parallel, using worker processes/threads
23
23
  - [x] process are preferred on POSIX systems, otherwise threads are used
24
- - [x] default number of workers is the # of real cpu cores on the system
24
+ - [x] default number of jobs is the # of real cpu cores on the system
25
25
  - [x] in case of task Error or Exception, the whole run will be stopped
26
26
  - [x] runner saves a log file in `$(pwd)/fasten/log/runner/*name_of_runner*.log`
27
27
  - [x] each task saves its STDERR/STDOUT to a log file in `$(pwd)/fasten/log/task/*name_of_task*.log`
@@ -30,14 +30,14 @@ It has been released so people can try it and make feature requests, comments an
30
30
 
31
31
  ### UI/Curses
32
32
  - [x] only available if the 'curses' gem is installed
33
- - [x] Display number of workers running, idle, waiting, and number of workers (max)
33
+ - [x] Display number of jobs running, idle, waiting, and number of jobs (max)
34
34
  - [x] Display current running tasks, pending tasks, waiting tasks, etc; showing which task is pending because other tasks need to be run first
35
35
  - [x] Display the number of tasks done/pending
36
36
  - [x] Display a progressbar
37
37
  - [x] Display current local time
38
38
  - [x] Pause whole runner with `P` key (waits current running tasks end)
39
39
  - [x] Resume paused runner with `R` key
40
- - [x] Press ⬅️ or ➡️ keys to dynamically increase/decrease number of workers
40
+ - [x] Press ⬅️ or ➡️ keys to dynamically increase/decrease number of jobs
41
41
  - [ ] Use ⬆️ and ⬇️ to select tasks
42
42
  - [ ] Calculate ETA, assuming all tasks take same time
43
43
  - [ ] Calculate ETA, based on saved tasks statistics
@@ -14,7 +14,7 @@ module Fasten
14
14
  false
15
15
  end
16
16
 
17
- def default_workers
17
+ def default_jobs
18
18
  Parallel.physical_processor_count
19
19
  end
20
20
 
@@ -35,7 +35,7 @@ module Fasten
35
35
 
36
36
  require 'fasten/ui/curses'
37
37
 
38
- @default_ui_mode = :curses
38
+ @default_ui_mode = STDIN.tty? && STDOUT.tty? ? :curses : :console
39
39
  rescue StandardError, LoadError
40
40
  @default_ui_mode = :console
41
41
  end
data/lib/fasten/runner.rb CHANGED
@@ -18,27 +18,26 @@ module Fasten
18
18
  include Fasten::Support::UI
19
19
  include Fasten::Support::Yaml
20
20
 
21
- attr_accessor :name, :stats, :summary, :workers, :worker_class, :fasten_dir, :use_threads, :ui_mode, :developer, :worker_list, :queue, :tasks
21
+ attr_accessor :name, :stats, :summary, :jobs, :worker_class, :fasten_dir, :use_threads, :ui_mode, :developer, :workers, :queue, :tasks
22
22
 
23
23
  def initialize(**options)
24
- %i[name stats summary workers worker_class fasten_dir use_threads ui_mode developer].each do |key|
24
+ %i[name stats summary jobs worker_class fasten_dir use_threads ui_mode developer].each do |key|
25
25
  options[key] = Fasten.send "default_#{key}" unless options.key? key
26
26
  end
27
27
 
28
- @tasks = TaskManager.new
28
+ @tasks = TaskManager.new(targets: options[:targets] || [])
29
+ @workers = []
29
30
 
30
31
  reconfigure(options)
31
32
  end
32
33
 
33
34
  def reconfigure(**options)
34
- %i[name stats summary workers worker_class fasten_dir use_threads ui_mode developer].each do |key|
35
+ %i[name stats summary jobs worker_class fasten_dir use_threads ui_mode developer].each do |key|
35
36
  send "#{key}=", options[key] if options.key? key
36
37
  end
37
38
 
38
39
  initialize_stats
39
40
  initialize_logger
40
-
41
- self.worker_list ||= []
42
41
  end
43
42
 
44
43
  def task(name, **opts, &block)
@@ -117,7 +116,7 @@ module Fasten
117
116
  end
118
117
 
119
118
  def should_wait_for_running_tasks?
120
- tasks.running? && (tasks.no_waiting? || tasks.failed? || %i[PAUSING QUITTING].include?(state)) || tasks.running.count >= workers
119
+ tasks.running? && (tasks.no_waiting? || tasks.failed? || %i[PAUSING QUITTING].include?(state)) || tasks.running.count >= jobs
121
120
  end
122
121
 
123
122
  def wait_for_running_tasks
@@ -130,13 +129,13 @@ module Fasten
130
129
  while should_wait_for_running_tasks?
131
130
  ui.update
132
131
 
133
- receive_workers_tasks_thread queue.receive_with_timeout(0.5)
132
+ receive_jobs_tasks_thread queue.receive_with_timeout(0.5)
134
133
  end
135
134
 
136
135
  ui.update
137
136
  end
138
137
 
139
- def receive_workers_tasks_thread(items)
138
+ def receive_jobs_tasks_thread(items)
140
139
  items&.each do |task|
141
140
  tasks.running.delete task
142
141
 
@@ -153,18 +152,18 @@ module Fasten
153
152
  def wait_for_running_tasks_fork
154
153
  while should_wait_for_running_tasks?
155
154
  ui.update
156
- reads = worker_list.map(&:parent_read)
155
+ reads = workers.map(&:parent_read)
157
156
  reads, _writes, _errors = IO.select(reads, [], [], 0.5)
158
157
 
159
- receive_workers_tasks_fork(reads)
158
+ receive_jobs_tasks_fork(reads)
160
159
  end
161
160
 
162
161
  ui.update
163
162
  end
164
163
 
165
- def receive_workers_tasks_fork(reads)
164
+ def receive_jobs_tasks_fork(reads)
166
165
  reads&.each do |read|
167
- next unless (worker = worker_list.find { |item| item.parent_read == read })
166
+ next unless (worker = workers.find { |item| item.parent_read == read })
168
167
 
169
168
  task = worker.receive_response_from_child
170
169
 
@@ -206,24 +205,24 @@ module Fasten
206
205
  end
207
206
 
208
207
  def remove_workers_as_needed
209
- while worker_list.count > workers
210
- return unless (worker = worker_list.find { |item| item.running_task.nil? })
208
+ while workers.count > jobs
209
+ return unless (worker = workers.find { |item| item.running_task.nil? })
211
210
 
212
211
  worker.kill
213
- worker_list.delete worker
212
+ workers.delete worker
214
213
 
215
214
  ui.force_clear
216
215
  end
217
216
  end
218
217
 
219
218
  def find_or_create_worker
220
- worker = worker_list.find { |item| item.running_task.nil? }
219
+ worker = workers.find { |item| item.running_task.nil? }
221
220
 
222
221
  unless worker
223
222
  @worker_id = (@worker_id || 0) + 1
224
223
  worker = worker_class.new runner: self, name: "#{worker_class.to_s.gsub('::', '-')}-#{format '%02X', @worker_id}", use_threads: use_threads
225
224
  worker.start
226
- worker_list << worker
225
+ workers << worker
227
226
 
228
227
  log_info "Worker created: #{worker}"
229
228
 
@@ -234,7 +233,7 @@ module Fasten
234
233
  end
235
234
 
236
235
  def dispatch_pending_tasks
237
- while tasks.waiting? && tasks.running.count < workers
236
+ while tasks.waiting? && tasks.running.count < jobs
238
237
  worker = find_or_create_worker
239
238
 
240
239
  task = tasks.next
@@ -247,8 +246,8 @@ module Fasten
247
246
  end
248
247
 
249
248
  def remove_all_workers
250
- worker_list.each(&:kill)
251
- worker_list.clear
249
+ workers.each(&:kill)
250
+ workers.clear
252
251
 
253
252
  ui.force_clear
254
253
  end
@@ -112,8 +112,8 @@ module Fasten
112
112
  filters: { 'run' => FLOAT_FORMATTER, 'avg' => FLOAT_FORMATTER, 'std' => FLOAT_FORMATTER, 'err' => FLOAT_FORMATTER },
113
113
  description: false)
114
114
 
115
- puts format('∑tasks: %<task>s runner: %<runner>s saved: %<saved>s workers: %<workers>s',
116
- task: hformat(sub), runner: hformat(tot, sub), saved: hformat(sub - tot, sub), workers: workers.to_s)
115
+ puts format('∑tasks: %<task>s runner: %<runner>s saved: %<saved>s jobs: %<jobs>s',
116
+ task: hformat(sub), runner: hformat(tot, sub), saved: hformat(sub - tot, sub), jobs: jobs.to_s)
117
117
  end
118
118
 
119
119
  def stats_history(entry)
@@ -2,7 +2,7 @@ module Fasten
2
2
  class TaskManager < Array
3
3
  attr_reader :done, :failed, :pending, :running, :targets
4
4
 
5
- def initialize(targets: nil)
5
+ def initialize(targets: [])
6
6
  super()
7
7
 
8
8
  @map = {}
@@ -53,6 +53,7 @@ module Fasten
53
53
 
54
54
  reset
55
55
  setup_dependencies
56
+ setup_targets
56
57
  setup_scores
57
58
  move_pending_to_waiting
58
59
  end
@@ -87,8 +88,6 @@ module Fasten
87
88
  @running = by_state.delete(:RUNNING) || []
88
89
  @waiting = []
89
90
 
90
- return unless @targets.nil? || @targets.empty?
91
-
92
91
  @pending = by_state.values.flatten.each do |task|
93
92
  task.depends = []
94
93
  task.dependants = []
@@ -110,8 +109,37 @@ module Fasten
110
109
  end
111
110
  end
112
111
 
113
- def setup_scores
112
+ def setup_targets
113
+ return if @targets.empty?
114
+
115
+ @targets.each do |target|
116
+ task = target.is_a?(Task) ? target : @map[target]
117
+ raise "Target task #{target} not found" unless task
118
+
119
+ mark_needed(task)
120
+ end
121
+
122
+ @pending.reject { |task| task.state == :NEED }.each do |task|
123
+ @pending.delete task
124
+ delete task
125
+ end
126
+
114
127
  @pending.each do |task|
128
+ task.state = nil
129
+ end
130
+ end
131
+
132
+ def mark_needed(task)
133
+ return unless task.state == :IDLE
134
+
135
+ task.state = :NEED
136
+ task.depends.each do |depend_task|
137
+ mark_needed(depend_task)
138
+ end
139
+ end
140
+
141
+ def setup_scores
142
+ each do |task|
115
143
  task.run_score = task.dependants.count
116
144
  end
117
145
  end
@@ -5,8 +5,8 @@ module Fasten
5
5
  class Console
6
6
  extend Forwardable
7
7
 
8
- def_delegators :runner, :worker_list, :tasks, :worker_list
9
- def_delegators :runner, :name, :workers, :workers=, :state, :state=, :hformat
8
+ def_delegators :runner, :workers, :tasks
9
+ def_delegators :runner, :name, :jobs, :jobs=, :state, :state=, :hformat
10
10
 
11
11
  attr_accessor :runner
12
12
 
@@ -20,7 +20,7 @@ module Fasten
20
20
  puts <<~FIN
21
21
 
22
22
  = == === ==== ===== ====== ======= ======== ========= ==========
23
- Fasten your seatbelts! #{'💺' * workers} #{runner.use_threads ? 'threads' : 'processes'}
23
+ Fasten your seatbelts! #{'💺' * jobs} #{runner.use_threads ? 'threads' : 'processes'}
24
24
 
25
25
  #{name}
26
26
  FIN
@@ -9,8 +9,8 @@ module Fasten
9
9
  include ::Curses
10
10
  extend Forwardable
11
11
 
12
- def_delegators :runner, :worker_list, :tasks, :worker_list
13
- def_delegators :runner, :name, :workers, :workers=, :state, :state=
12
+ def_delegators :runner, :workers, :tasks
13
+ def_delegators :runner, :name, :jobs, :jobs=, :state, :state=
14
14
 
15
15
  attr_accessor :n_rows, :n_cols, :selected, :sel_index, :clear_needed, :message, :runner
16
16
 
@@ -28,7 +28,7 @@ module Fasten
28
28
  ui_keyboard
29
29
  clear if clear_needed
30
30
  draw_title
31
- ui_workers
31
+ ui_jobs
32
32
  ui_tasks
33
33
 
34
34
  refresh
@@ -96,15 +96,15 @@ module Fasten
96
96
  self.message = nil
97
97
 
98
98
  if key == Curses::Key::LEFT
99
- if workers <= 1
99
+ if jobs <= 1
100
100
  self.message = "Can't remove 1 worker left, press [P] to pause"
101
101
  else
102
- self.workers -= 1
103
- self.message = "Decreasing workers to #{workers}"
102
+ self.jobs -= 1
103
+ self.message = "Decreasing jobs to #{jobs}"
104
104
  end
105
105
  elsif key == Curses::Key::RIGHT
106
- self.workers += 1
107
- self.message = "Increasing workers to #{workers}"
106
+ self.jobs += 1
107
+ self.message = "Increasing jobs to #{jobs}"
108
108
  elsif key == Curses::Key::DOWN
109
109
  self.sel_index = sel_index ? [sel_index + 1, tasks.count - 1].min : 0
110
110
  self.selected = tasks[sel_index]
@@ -124,18 +124,18 @@ module Fasten
124
124
  force_clear
125
125
  end
126
126
 
127
- def ui_workers_summary
127
+ def ui_jobs_summary
128
128
  running_count = tasks.running.count
129
129
  waiting_count = tasks.waiting.count
130
- workers_count = worker_list.count
130
+ workers_count = workers.count
131
131
 
132
- "Procs running: #{running_count} idle: #{workers_count - running_count} waiting: #{waiting_count} #{runner.use_threads ? 'threads' : 'processes'}: #{workers}"
132
+ "Procs running: #{running_count} idle: #{workers_count - running_count} waiting: #{waiting_count} #{runner.use_threads ? 'threads' : 'processes'}: #{jobs}"
133
133
  end
134
134
 
135
- def ui_workers
136
- l = ui_text_aligned(1, :left, ui_workers_summary) + 1
135
+ def ui_jobs
136
+ l = ui_text_aligned(1, :left, ui_jobs_summary) + 1
137
137
 
138
- worker_list.each_with_index do |worker, index|
138
+ workers.each_with_index do |worker, index|
139
139
  setpos 1, l + index
140
140
  attrs = worker.running? ? A_STANDOUT : color_pair(4) | A_DIM
141
141
  attrset attrs
@@ -227,7 +227,7 @@ module Fasten
227
227
  end
228
228
 
229
229
  def ui_tasks
230
- worker_list.each do |worker|
230
+ workers.each do |worker|
231
231
  worker.spinner = (worker.spinner + 1) % SPINNER_LEN if worker.running?
232
232
  end
233
233
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fasten
4
- VERSION = '0.7.6'
4
+ VERSION = '0.8.0'
5
5
  end
data/lib/fasten.rb CHANGED
@@ -63,7 +63,7 @@ module Fasten
63
63
  @load_path = []
64
64
 
65
65
  @opt_parser = OptionParser.new do |opts|
66
- opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
66
+ opts.banner = "Usage: #{$PROGRAM_NAME} [options] [targets]"
67
67
  opts.separator ''
68
68
  opts.separator 'Examples:'
69
69
  opts.separator ' fasten # load and run all task from fasten/*_fasten.rb'
@@ -72,26 +72,25 @@ module Fasten
72
72
  opts.separator ''
73
73
  opts.separator 'Options:'
74
74
 
75
- opts.on '-n NAME', '--name=NAME', String, "Change name of this runner (default: #{default_name} from current directory)" do |name|
75
+ opts.on '-n NAME', '--name NAME', String, "Change name of this runner (default: #{default_name} from current directory)" do |name|
76
76
  @options[:name] = name
77
77
  end
78
- opts.on '-f PATH', '--file=PATH', String, 'File or folder with ruby code' do |path|
78
+ opts.on '-f PATH', '--file PATH', String, 'File or folder with ruby code' do |path|
79
79
  @load_path << path
80
80
  end
81
- opts.on '-w WORKERS', '--workers=WORKERS', Numeric, "Number of processes/threads to use (default: #{default_workers} on this machine)" do |workers|
82
- @options[:workers] = workers
81
+ opts.on '-j JOBS', '--jobs JOBS', Numeric, "Maximum number of tasks to execute in parallel (default: #{default_jobs} on this machine)" do |jobs|
82
+ @options[:jobs] = jobs
83
83
  end
84
84
  opts.on '-s', '--[no-]summary', TrueClass, 'Display summary at the end of execution' do |boolean|
85
- puts "SUMMAMRY: #{boolean}"
86
85
  @options[:summary] = boolean
87
86
  end
88
87
  opts.on '--ui=UI', String, "Type of UI: curses, console. (default: #{default_ui_mode} on this machine)" do |ui_mode|
89
88
  @options[:ui_mode] = ui_mode
90
89
  end
91
- opts.on '-t', '--threads', "Use threads workers for parallel execution#{default_use_threads && ' (default on this machine)' || nil}" do
90
+ opts.on '-t', '--threads', "Use threads based jobs for parallel execution#{default_use_threads && ' (default on this machine)' || nil}" do
92
91
  @options[:use_threads] = true
93
92
  end
94
- opts.on '-p', '--processes', "Use process workers for parallel execution#{!default_use_threads && ' (default on this machine)' || nil}" do
93
+ opts.on '-p', '--processes', "Use process based jobs for parallel execution#{!default_use_threads && ' (default on this machine)' || nil}" do
95
94
  @options[:use_threads] = false
96
95
  end
97
96
  opts.on '-v', '--version', 'Display version info' do
@@ -112,7 +111,10 @@ module Fasten
112
111
  def invoke
113
112
  opt_parser.parse!
114
113
 
114
+ @options[:targets] = ARGV.to_a
115
+
115
116
  runner @options
117
+ @load_path = Dir['fasten/*_fasten.rb'] if @load_path.empty?
116
118
  load_fasten @load_path
117
119
 
118
120
  show_help 1 if runner.tasks.empty?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fasten
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.6
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aldrin Martoq
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-19 00:00:00.000000000 Z
11
+ date: 2018-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler