fasten 0.7.6 → 0.8.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: 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