miga-base 0.7.16.1 → 0.7.16.7

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: c515f327c9d7178b1891283f849d422885b3640f8cded39cfccd048e354acf16
4
- data.tar.gz: 889a399e0fa68b54c901ec513e2049ab046593bc433185511516dbf9b3cedb7d
3
+ metadata.gz: affb99901724300ab46e2e7b1ef3f4e227f4288bef3a0634c8caa5f86b10b345
4
+ data.tar.gz: fc51e29cc954afd22ae6ab59c59393165a3ea64455807bac8e2300660f2c2673
5
5
  SHA512:
6
- metadata.gz: f4a9d5515ddf4b208b81612ceafcdae0eeb9cd37266df5f0175cef859adb9b24fd6e9ac5adf384ad9c91f8ecc08d6d5522eef8b9dd96e7d39740b14f83fdaf53
7
- data.tar.gz: 117bc5b917e1008084e064cd4d87f290a83b6962e93560abfad254d23345a7685bf9ad3a345f2ade98ea5c13b4be52ccf608683ede8c320f3b8ee1250c2cec32
6
+ metadata.gz: f8c9f1c7c307e408080ea80a4496eba48fe9d05220b6e636490958358c5a19da1f2ee86971c4b02b8200fcd8d5f01ec949b62dfbfce7b70b68da8ce940c7f5bf
7
+ data.tar.gz: cc4fed1bdef75754f4110dc768cc87b4766e6f7cf91166fdfa321657952066831b39b6da10aa598929a0155c93f555ba7ed0c0afe3dc118a92a7c954ce271551
data/bin/miga CHANGED
@@ -7,4 +7,5 @@ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
7
7
  require 'miga'
8
8
  require 'miga/cli'
9
9
 
10
- MiGA::Cli.new(ARGV).launch
10
+ MiGA::Cli.new(ARGV).launch(true)
11
+
@@ -7,6 +7,7 @@ class MiGA::Cli::Action::Doctor < MiGA::Cli::Action
7
7
  include MiGA::Cli::Action::Doctor::Base
8
8
 
9
9
  def parse_cli
10
+ cli.defaults = { threads: 1 }
10
11
  cli.defaults = Hash[@@OPERATIONS.keys.map { |i| [i, true] }]
11
12
  cli.parse do |opt|
12
13
  operation_n = Hash[@@OPERATIONS.map { |k, v| [v[0], k] }]
@@ -24,6 +25,10 @@ class MiGA::Cli::Action::Doctor < MiGA::Cli::Action
24
25
  @@OPERATIONS.each_key { |i| cli[i] = false }
25
26
  cli[op_k] = true
26
27
  end
28
+ opt.on(
29
+ '-t', '--threads INT', Integer,
30
+ "Concurrent threads to use. By default: #{cli[:threads]}"
31
+ ) { |v| cli[:threads] = v }
27
32
  end
28
33
  end
29
34
 
@@ -59,11 +64,19 @@ class MiGA::Cli::Action::Doctor < MiGA::Cli::Action
59
64
  # Perform status operation with MiGA::Cli +cli+
60
65
  def check_status(cli)
61
66
  cli.say 'Updating metadata status'
62
- n, k = cli.load_project.dataset_names.size, 0
63
- cli.load_project.each_dataset do |d|
64
- cli.advance('Datasets:', k += 1, n, false)
65
- d.recalculate_status
67
+ p = cli.load_project
68
+ n = p.dataset_names.size
69
+ (0 .. cli[:threads] - 1).map do |i|
70
+ Process.fork do
71
+ k = 0
72
+ cli.load_project.each_dataset do |d|
73
+ k += 1
74
+ cli.advance('Datasets:', k, n, false) if i == 0
75
+ d.recalculate_status if k % cli[:threads] == i
76
+ end
77
+ end
66
78
  end
79
+ Process.waitall
67
80
  cli.say
68
81
  end
69
82
 
@@ -71,36 +84,59 @@ class MiGA::Cli::Action::Doctor < MiGA::Cli::Action
71
84
  # Perform databases operation with MiGA::Cli +cli+
72
85
  def check_db(cli)
73
86
  cli.say 'Checking integrity of databases'
74
- n, k = cli.load_project.dataset_names.size, 0
75
- cli.load_project.each_dataset do |d|
76
- cli.advance('Datasets:', k += 1, n, false)
77
- each_database_file(d) do |db_file, metric, result|
78
- check_sqlite3_database(db_file, metric) do
79
- cli.say(" > Removing malformed database from #{d.name}:#{result} ")
80
- File.unlink(db_file)
81
- r = d.result(result) or next
82
- [r.path(:done), r.path].each { |f| File.unlink(f) if File.exist?(f) }
87
+ p = cli.load_project
88
+ n = p.dataset_names.size
89
+ (0 .. cli[:threads] - 1).map do |i|
90
+ Process.fork do
91
+ k = 0
92
+ p.each_dataset do |d|
93
+ k += 1
94
+ cli.advance('Datasets:', k, n, false) if i == 0
95
+ next unless k % cli[:threads] == i
96
+ each_database_file(d) do |db_file, metric, result|
97
+ check_sqlite3_database(db_file, metric) do
98
+ cli.say(
99
+ " > Removing malformed database from #{d.name}:#{result} "
100
+ )
101
+ File.unlink(db_file)
102
+ r = d.result(result) or next
103
+ [r.path(:done), r.path].each do |f|
104
+ File.unlink(f) if File.exist?(f)
105
+ end
106
+ end
107
+ end
83
108
  end
84
109
  end
85
110
  end
111
+ Process.waitall
86
112
  cli.say
87
113
  end
88
114
 
89
115
  ##
90
116
  # Perform bidirectional operation with MiGA::Cli +cli+
91
117
  def check_bidir(cli)
92
- cli.say 'Checking that reference distances are bidirectional'
118
+ cli.say 'Checking if reference distances are bidirectional'
93
119
  ref_ds = cli.load_project.each_dataset.select(&:ref?)
94
120
  ref_names = ref_ds.map(&:name)
95
- n, k = ref_ds.size, 0
96
- ref_ds.each do |d|
97
- cli.advance('Datasets:', k += 1, n, false)
98
- saved = saved_targets(d)
99
- next if saved.nil?
121
+ n = ref_ds.size
122
+ (0 .. cli[:threads] - 1).map do |i|
123
+ Process.fork do
124
+ k = 0
125
+ ref_ds.each do |d|
126
+ k += 1
127
+ cli.advance('Datasets:', k, n, false) if i == 0
128
+ next unless k % cli[:threads] == i
100
129
 
101
- to_save = ref_names - saved
102
- to_save.each { |k| save_bidirectional(cli.load_project.dataset(k), d) }
130
+ saved = saved_targets(d)
131
+ next if saved.nil?
132
+
133
+ (ref_names - saved).each do |k|
134
+ save_bidirectional(cli.load_project.dataset(k), d)
135
+ end
136
+ end
137
+ end
103
138
  end
139
+ Process.waitall
104
140
  cli.say
105
141
  end
106
142
 
@@ -134,10 +134,19 @@ module MiGA::Cli::Action::Doctor::Base
134
134
 
135
135
  data[0], data[1] = data[1], data[0]
136
136
  SQLite3::Database.new(db_file_b) do |conn|
137
- conn.execute(
138
- "insert into #{metric} (seq1, seq2, #{metric}, sd, n, omega) " +
139
- "values(?, ?, ?, ?, ?, ?)", data
140
- )
137
+ attempts = 0
138
+ begin
139
+ attempts += 1
140
+ conn.execute(
141
+ "insert into #{metric} (seq1, seq2, #{metric}, sd, n, omega) " +
142
+ "values(?, ?, ?, ?, ?, ?)", data
143
+ )
144
+ rescue SQLite3::BusyException => e
145
+ raise "Cannot populate #{db_file_b}: #{e.message}" if attempts > 3
146
+
147
+ sleep(1)
148
+ retry
149
+ end
141
150
  end
142
151
  end
143
152
  end
@@ -70,7 +70,7 @@ class MiGA::Cli::Action::Get < MiGA::Cli::Action
70
70
  glob = get_sub_cli
71
71
  p = cli.load_project
72
72
  glob.each do |sub_cli|
73
- rd = create_remote_dataset(sub_cli)
73
+ rd = create_remote_dataset(sub_cli, p)
74
74
  next if rd.nil?
75
75
 
76
76
  if sub_cli[:get_md]
@@ -115,7 +115,7 @@ class MiGA::Cli::Action::Get < MiGA::Cli::Action
115
115
  glob
116
116
  end
117
117
 
118
- def create_remote_dataset(sub_cli)
118
+ def create_remote_dataset(sub_cli, p)
119
119
  sub_cli.ensure_par(dataset: '-D', ids: '-I')
120
120
  unless sub_cli[:api_key].nil?
121
121
  ENV["#{sub_cli[:universe].to_s.upcase}_API_KEY"] = sub_cli[:api_key]
@@ -165,7 +165,7 @@ class MiGA::Cli::Action::GetDb < MiGA::Cli::Action
165
165
  def check_target
166
166
  return false if cli[:overwrite]
167
167
 
168
- file = File.expand_path(cli[:database], cli[:local])
168
+ file = File.expand_path(cli[:database].to_s, cli[:local])
169
169
  if Dir.exist? file
170
170
  warn "The target directory already exists: #{file}"
171
171
  true
@@ -8,7 +8,7 @@ class MiGA::Cli::Action::Run < MiGA::Cli::Action
8
8
  def parse_cli
9
9
  cli.defaults = { try_load: false, thr: 1, env: false }
10
10
  cli.parse do |opt|
11
- cli.opt_object(opt, [:project, :dataset_opt, :result])
11
+ cli.opt_object(opt, [:project, :dataset_opt, :result_opt])
12
12
  opt.on(
13
13
  '-t', '--threads INT', Integer,
14
14
  "Threads to use in the local run (by default: #{cli[:thr]})"
@@ -37,12 +37,18 @@ class MiGA::Cli::Action::Run < MiGA::Cli::Action
37
37
  cli[:thr] ||= ENV['CORES'].to_i unless ENV['CORES'].nil?
38
38
  cli[:result] = File.basename(cli[:result].to_s, '.bash').to_sym
39
39
  end
40
+ cli[:project] = nil if cli[:project].empty?
41
+ cli[:dataset] = nil if cli[:dataset].empty?
42
+ cli[:result] = nil if cli[:result].empty?
40
43
 
41
44
  # Unset dataset if the requested result is for projects
42
45
  if (MiGA::Project.RESULT_DIRS.keys + [:p]).include? cli[:result]
43
46
  cli[:dataset] = nil
44
47
  end
45
48
 
49
+ # Use virtual result if not explicitly passed
50
+ cli[:result] ||= cli[:dataset] ? :d : :p
51
+
46
52
  # Load project
47
53
  p = cli.load_project
48
54
 
@@ -56,10 +56,11 @@ module MiGA::Cli::OptHelper
56
56
  # - :project_type To allow (optionally) a type of project
57
57
  # - :project_type_req To require a type of project
58
58
  # - :result To require a type of project or dataset result
59
+ # - :result_opt To allow (optionally) a type of result
59
60
  # - :result_dataset To require a type of dataset result
60
61
  # - :result_project To require a type of project result
61
- # The options :result, :result_dataset, and :result_project are mutually
62
- # exclusive
62
+ # The options :result, :result_opt, :result_dataset, and :result_project
63
+ # are mutually exclusive
63
64
  def opt_object(opt, what = [:project, :dataset])
64
65
  what.each do |w|
65
66
  case w
@@ -82,10 +83,10 @@ module MiGA::Cli::OptHelper
82
83
  "#{req}Type of #{obj}. Recognized types include:",
83
84
  *klass.KNOWN_TYPES.map { |k, v| "~ #{k}: #{v[:description]}" }
84
85
  ) { |v| self[:type] = v.downcase.to_sym }
85
- when :result
86
+ when :result, :result_opt
86
87
  opt.on(
87
88
  '-r', '--result STRING',
88
- '(Mandatory) Name of the result',
89
+ "#{"(Mandatory) " if w == :result}Name of the result",
89
90
  'Recognized names for dataset-specific results include:',
90
91
  *MiGA::Dataset.RESULT_DIRS.keys.map { |n| " ~ #{n}" },
91
92
  'Recognized names for project-wide results include:',
@@ -52,10 +52,44 @@ class MiGA::MiGA
52
52
  # 1,000 otherwise.
53
53
  # The report goes to $stderr iff --verborse
54
54
  def advance(step, n = 0, total = nil, bin = true)
55
- adv = total.nil? ? (n == 0 ? '' : num_suffix(n, bin)) :
56
- ('%.1f%% (%s/%s)' % [100.0 * n / total,
57
- num_suffix(n, bin), num_suffix(total, bin)])
58
- $stderr.print("[%s] %s %s \r" % [Time.now, step, adv])
55
+ # Initialize advance timing
56
+ @_advance_time ||= { last: nil, n: 0, avg: nil }
57
+ if n <= 1 || @_advance_time[:n] > n
58
+ @_advance_time[:last] = nil
59
+ @_advance_time[:n] = 0
60
+ @_advance_time[:avg] = nil
61
+ end
62
+
63
+ # Estimate timing
64
+ adv_n = n - @_advance_time[:n]
65
+ unless total.nil? || @_advance_time[:last].nil? || adv_n <= 0
66
+ if adv_n.to_f/n > 0.001
67
+ this_time = Time.now - @_advance_time[:last]
68
+ this_avg = this_time / adv_n
69
+ @_advance_time[:avg] ||= this_avg
70
+ @_advance_time[:avg] = 0.9 * @_advance_time[:avg] + 0.1 * this_avg
71
+ end
72
+ end
73
+ @_advance_time[:last] = Time.now
74
+ @_advance_time[:n] = n
75
+
76
+ # Report
77
+ adv_vals = [100.0 * n / total, num_suffix(n, bin), num_suffix(total, bin)]
78
+ adv =
79
+ total.nil? ? (n == 0 ? '' : num_suffix(n, bin)) :
80
+ ('%.1f%% (%s/%s)' % adv_vals)
81
+ left =
82
+ if @_advance_time[:avg].nil?
83
+ ''
84
+ else
85
+ left_time = @_advance_time[:avg] * (total - n) / 60 # <- in minutes
86
+ left_time < 0.01 ? ' ' :
87
+ left_time < 1 ? ('%.0fs left' % (left_time * 60)) :
88
+ left_time > 1440 ? ('%.1fd left' % (left_time / 1440)) :
89
+ left_time > 60 ? ('%.1fh left' % (left_time / 60)) :
90
+ ('%.1fm left' % left_time)
91
+ end
92
+ $stderr.print("[%s] %s %s %s \r" % [Time.now, step, adv, left])
59
93
  end
60
94
 
61
95
  ##
@@ -8,7 +8,7 @@ module MiGA
8
8
  # - Float representing the major.minor version.
9
9
  # - Integer representing gem releases of the current version.
10
10
  # - Integer representing minor changes that require new version number.
11
- VERSION = [0.7, 16, 1]
11
+ VERSION = [0.7, 16, 7]
12
12
 
13
13
  ##
14
14
  # Nickname for the current major.minor version.
@@ -16,7 +16,7 @@ module MiGA
16
16
 
17
17
  ##
18
18
  # Date of the current gem release.
19
- VERSION_DATE = Date.new(2020, 10, 19)
19
+ VERSION_DATE = Date.new(2020, 11, 22)
20
20
 
21
21
  ##
22
22
  # Reference of MiGA.
@@ -12,7 +12,7 @@ cd "$DIR"
12
12
  miga date > "miga-project.start"
13
13
 
14
14
  # Execute doctor
15
- miga doctor -P "$PROJECT" -v
15
+ miga doctor -P "$PROJECT" -t "$CORES" -v
16
16
 
17
17
  # Index taxonomy
18
18
  miga tax_index -P "$PROJECT" -i "miga-project.taxonomy.json" --ref --active
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miga-base
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.16.1
4
+ version: 0.7.16.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luis M. Rodriguez-R
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-19 00:00:00.000000000 Z
11
+ date: 2020-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: daemons