rbbt-util 5.44.1 → 6.0.4

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.
Files changed (175) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/bin/rbbt +67 -90
  4. data/bin/rbbt_exec.rb +2 -2
  5. data/etc/app.d/base.rb +2 -2
  6. data/etc/app.d/semaphores.rb +3 -3
  7. data/lib/rbbt/annotations/annotated_array.rb +207 -207
  8. data/lib/rbbt/annotations/refactor.rb +27 -0
  9. data/lib/rbbt/annotations/util.rb +282 -282
  10. data/lib/rbbt/annotations.rb +343 -320
  11. data/lib/rbbt/association/database.rb +200 -225
  12. data/lib/rbbt/association/index.rb +294 -291
  13. data/lib/rbbt/association/item.rb +227 -227
  14. data/lib/rbbt/association/open.rb +35 -34
  15. data/lib/rbbt/association/util.rb +0 -169
  16. data/lib/rbbt/association.rb +2 -4
  17. data/lib/rbbt/entity/identifiers.rb +119 -118
  18. data/lib/rbbt/entity/refactor.rb +12 -0
  19. data/lib/rbbt/entity.rb +319 -315
  20. data/lib/rbbt/hpc/batch.rb +72 -53
  21. data/lib/rbbt/hpc/lsf.rb +2 -2
  22. data/lib/rbbt/hpc/orchestrate/batches.rb +2 -2
  23. data/lib/rbbt/hpc/orchestrate/chains.rb +25 -5
  24. data/lib/rbbt/hpc/orchestrate/rules.rb +2 -2
  25. data/lib/rbbt/hpc/orchestrate.rb +19 -13
  26. data/lib/rbbt/hpc/slurm.rb +18 -18
  27. data/lib/rbbt/knowledge_base/entity.rb +13 -5
  28. data/lib/rbbt/knowledge_base/query.rb +2 -2
  29. data/lib/rbbt/knowledge_base/registry.rb +32 -31
  30. data/lib/rbbt/knowledge_base/traverse.rb +1 -1
  31. data/lib/rbbt/knowledge_base.rb +1 -1
  32. data/lib/rbbt/monitor.rb +36 -25
  33. data/lib/rbbt/persist/refactor.rb +166 -0
  34. data/lib/rbbt/persist/tsv/tokyocabinet.rb +105 -105
  35. data/lib/rbbt/persist/tsv.rb +187 -185
  36. data/lib/rbbt/persist.rb +556 -551
  37. data/lib/rbbt/refactor.rb +20 -0
  38. data/lib/rbbt/resource/path/refactor.rb +178 -0
  39. data/lib/rbbt/resource/path.rb +317 -497
  40. data/lib/rbbt/resource/util.rb +0 -48
  41. data/lib/rbbt/resource.rb +3 -390
  42. data/lib/rbbt/tsv/accessor.rb +2 -838
  43. data/lib/rbbt/tsv/attach.rb +303 -299
  44. data/lib/rbbt/tsv/change_id.rb +244 -245
  45. data/lib/rbbt/tsv/csv.rb +87 -85
  46. data/lib/rbbt/tsv/dumper.rb +2 -100
  47. data/lib/rbbt/tsv/excel.rb +26 -24
  48. data/lib/rbbt/tsv/field_index.rb +4 -1
  49. data/lib/rbbt/tsv/filter.rb +3 -2
  50. data/lib/rbbt/tsv/index.rb +2 -284
  51. data/lib/rbbt/tsv/manipulate.rb +750 -747
  52. data/lib/rbbt/tsv/marshal.rb +3 -3
  53. data/lib/rbbt/tsv/matrix.rb +2 -2
  54. data/lib/rbbt/tsv/parallel/through.rb +2 -1
  55. data/lib/rbbt/tsv/parallel/traverse.rb +783 -781
  56. data/lib/rbbt/tsv/parser.rb +678 -678
  57. data/lib/rbbt/tsv/refactor.rb +195 -0
  58. data/lib/rbbt/tsv/stream.rb +253 -251
  59. data/lib/rbbt/tsv/util.rb +420 -420
  60. data/lib/rbbt/tsv.rb +210 -208
  61. data/lib/rbbt/util/R/eval.rb +4 -4
  62. data/lib/rbbt/util/R/plot.rb +62 -166
  63. data/lib/rbbt/util/R.rb +21 -18
  64. data/lib/rbbt/util/cmd.rb +2 -318
  65. data/lib/rbbt/util/color.rb +269 -269
  66. data/lib/rbbt/util/colorize.rb +89 -89
  67. data/lib/rbbt/util/concurrency/processes/refactor.rb +22 -0
  68. data/lib/rbbt/util/concurrency/processes/worker.rb +2 -2
  69. data/lib/rbbt/util/concurrency/processes.rb +389 -386
  70. data/lib/rbbt/util/config.rb +169 -167
  71. data/lib/rbbt/util/filecache.rb +1 -1
  72. data/lib/rbbt/util/iruby.rb +20 -0
  73. data/lib/rbbt/util/log/progress/report.rb +241 -241
  74. data/lib/rbbt/util/log/progress/util.rb +99 -99
  75. data/lib/rbbt/util/log/progress.rb +102 -102
  76. data/lib/rbbt/util/log/refactor.rb +49 -0
  77. data/lib/rbbt/util/log.rb +486 -532
  78. data/lib/rbbt/util/migrate.rb +2 -2
  79. data/lib/rbbt/util/misc/concurrent_stream.rb +248 -246
  80. data/lib/rbbt/util/misc/development.rb +12 -11
  81. data/lib/rbbt/util/misc/exceptions.rb +117 -112
  82. data/lib/rbbt/util/misc/format.rb +2 -230
  83. data/lib/rbbt/util/misc/indiferent_hash.rb +2 -107
  84. data/lib/rbbt/util/misc/inspect.rb +2 -476
  85. data/lib/rbbt/util/misc/lock.rb +109 -106
  86. data/lib/rbbt/util/misc/omics.rb +9 -1
  87. data/lib/rbbt/util/misc/pipes.rb +765 -793
  88. data/lib/rbbt/util/misc/refactor.rb +20 -0
  89. data/lib/rbbt/util/misc/ssw.rb +27 -17
  90. data/lib/rbbt/util/misc/system.rb +92 -105
  91. data/lib/rbbt/util/misc.rb +39 -20
  92. data/lib/rbbt/util/named_array/refactor.rb +4 -0
  93. data/lib/rbbt/util/named_array.rb +3 -220
  94. data/lib/rbbt/util/open/refactor.rb +7 -0
  95. data/lib/rbbt/util/open.rb +3 -857
  96. data/lib/rbbt/util/procpath.rb +6 -6
  97. data/lib/rbbt/util/python/paths.rb +27 -0
  98. data/lib/rbbt/util/python/run.rb +115 -0
  99. data/lib/rbbt/util/python/script.rb +110 -0
  100. data/lib/rbbt/util/python/util.rb +3 -3
  101. data/lib/rbbt/util/python.rb +22 -81
  102. data/lib/rbbt/util/semaphore.rb +152 -148
  103. data/lib/rbbt/util/simpleopt.rb +9 -8
  104. data/lib/rbbt/util/ssh/refactor.rb +19 -0
  105. data/lib/rbbt/util/ssh.rb +122 -118
  106. data/lib/rbbt/util/tar.rb +117 -115
  107. data/lib/rbbt/util/tmpfile.rb +69 -67
  108. data/lib/rbbt/util/version.rb +2 -0
  109. data/lib/rbbt/workflow/refactor/entity.rb +11 -0
  110. data/lib/rbbt/workflow/refactor/export.rb +66 -0
  111. data/lib/rbbt/workflow/refactor/inputs.rb +24 -0
  112. data/lib/rbbt/workflow/refactor/recursive.rb +64 -0
  113. data/lib/rbbt/workflow/refactor/task_info.rb +66 -0
  114. data/lib/rbbt/workflow/refactor.rb +150 -0
  115. data/lib/rbbt/workflow/remote_workflow/driver/rest.rb +1 -2
  116. data/lib/rbbt/workflow/remote_workflow/driver/ssh.rb +55 -32
  117. data/lib/rbbt/workflow/remote_workflow/remote_step/rest.rb +3 -1
  118. data/lib/rbbt/workflow/remote_workflow/remote_step/ssh.rb +14 -5
  119. data/lib/rbbt/workflow/remote_workflow/remote_step.rb +19 -7
  120. data/lib/rbbt/workflow/remote_workflow.rb +6 -1
  121. data/lib/rbbt/workflow/step/run.rb +766 -766
  122. data/lib/rbbt/workflow/step/save_load_inputs.rb +254 -254
  123. data/lib/rbbt/workflow/step.rb +2 -362
  124. data/lib/rbbt/workflow/task.rb +118 -118
  125. data/lib/rbbt/workflow/usage.rb +289 -287
  126. data/lib/rbbt/workflow/util/archive.rb +6 -5
  127. data/lib/rbbt/workflow/util/data.rb +1 -1
  128. data/lib/rbbt/workflow/util/orchestrator.rb +249 -246
  129. data/lib/rbbt/workflow/util/trace.rb +79 -44
  130. data/lib/rbbt/workflow.rb +4 -882
  131. data/lib/rbbt-util.rb +21 -13
  132. data/lib/rbbt.rb +16 -3
  133. data/python/rbbt/__init__.py +96 -4
  134. data/python/rbbt/workflow/remote.py +104 -0
  135. data/python/rbbt/workflow.py +64 -0
  136. data/python/test.py +10 -0
  137. data/share/Rlib/plot.R +37 -37
  138. data/share/Rlib/svg.R +22 -5
  139. data/share/install/software/lib/install_helpers +1 -1
  140. data/share/rbbt_commands/hpc/list +2 -3
  141. data/share/rbbt_commands/hpc/orchestrate +4 -4
  142. data/share/rbbt_commands/hpc/tail +2 -0
  143. data/share/rbbt_commands/hpc/task +10 -7
  144. data/share/rbbt_commands/lsf/list +2 -3
  145. data/share/rbbt_commands/lsf/orchestrate +4 -4
  146. data/share/rbbt_commands/lsf/tail +2 -0
  147. data/share/rbbt_commands/lsf/task +10 -7
  148. data/share/rbbt_commands/migrate +1 -1
  149. data/share/rbbt_commands/pbs/list +2 -3
  150. data/share/rbbt_commands/pbs/orchestrate +4 -4
  151. data/share/rbbt_commands/pbs/tail +2 -0
  152. data/share/rbbt_commands/pbs/task +10 -7
  153. data/share/rbbt_commands/resource/produce +8 -1
  154. data/share/rbbt_commands/slurm/list +2 -3
  155. data/share/rbbt_commands/slurm/orchestrate +4 -4
  156. data/share/rbbt_commands/slurm/tail +2 -0
  157. data/share/rbbt_commands/slurm/task +10 -7
  158. data/share/rbbt_commands/system/clean +5 -5
  159. data/share/rbbt_commands/system/status +5 -5
  160. data/share/rbbt_commands/tsv/get +2 -3
  161. data/share/rbbt_commands/tsv/info +10 -13
  162. data/share/rbbt_commands/tsv/keys +18 -14
  163. data/share/rbbt_commands/tsv/slice +2 -2
  164. data/share/rbbt_commands/tsv/transpose +6 -2
  165. data/share/rbbt_commands/workflow/info +20 -24
  166. data/share/rbbt_commands/workflow/list +1 -1
  167. data/share/rbbt_commands/workflow/prov +20 -13
  168. data/share/rbbt_commands/workflow/retry +43 -0
  169. data/share/rbbt_commands/workflow/server +12 -2
  170. data/share/rbbt_commands/workflow/task +80 -73
  171. data/share/rbbt_commands/workflow/write_info +26 -9
  172. data/share/software/opt/ssw/ssw.c +861 -0
  173. data/share/software/opt/ssw/ssw.h +130 -0
  174. data/share/workflow_config.ru +3 -3
  175. metadata +45 -6
data/lib/rbbt/persist.rb CHANGED
@@ -1,551 +1,556 @@
1
- require 'rbbt'
2
- require 'rbbt/util/misc'
3
- require 'rbbt/util/open'
4
-
5
- require 'rbbt/persist/tsv'
6
- require 'set'
7
-
8
- module Persist
9
- class << self
10
- attr_accessor :cachedir
11
- def self.cachedir=(cachedir)
12
- @cachedir = Path === cachedir ? cachedir : Path.setup(cachedir)
13
- end
14
- def self.cachedir
15
- @cachedir ||= Rbbt.var.cache.persistence
16
- end
17
-
18
- attr_accessor :lock_dir
19
-
20
- def lock_dir
21
- @lock_dir ||= Rbbt.tmp.persist_locks
22
- end
23
- end
24
-
25
- MEMORY = {} unless defined? MEMORY
26
- MAX_FILE_LENGTH = 150
27
-
28
- # Is 'file' newer than 'path'? return non-true if path is newer than file
29
- def self.newer?(path, file, by_link = false)
30
- return true if not Open.exists?(file)
31
- path = path.find if Path === path
32
- file = file.find if Path === file
33
- if by_link
34
- patht = File.exist?(path) ? File.lstat(path).mtime : nil
35
- filet = File.exist?(file) ? File.lstat(file).mtime : nil
36
- else
37
- patht = Open.mtime(path)
38
- filet = Open.mtime(file)
39
- end
40
- return true if patht.nil? || filet.nil?
41
- diff = patht - filet
42
- return diff if diff < 0
43
- return false
44
- end
45
-
46
- def self.is_persisted?(path, persist_options = {})
47
- return true if Open.remote?(path)
48
- return true if Open.ssh?(path)
49
- return false if not Open.exists? path
50
- return false if TrueClass === persist_options[:update]
51
-
52
- expiration = persist_options[:expiration]
53
- if expiration
54
- seconds = Misc.timespan(expiration)
55
- patht = Open.mtime(path)
56
- return false if Time.now > patht + seconds
57
- end
58
-
59
- check = persist_options[:check]
60
- return true if check.nil?
61
-
62
- missing = check.reject{|file| Open.exists?(file) }
63
- return false if missing.any?
64
-
65
- return true unless ENV["RBBT_UPDATE"]
66
-
67
- if Array === check
68
- newer = check.select{|file| newer? path, file}
69
- return true if newer.empty?
70
- Log.medium "Persistence check for #{path} failed in: #{ Misc.fingerprint(newer)}"
71
- return false
72
- else
73
- ! newer?(path, check)
74
- end
75
- end
76
-
77
- def self.persistence_path(file, persist_options = {}, options = {})
78
- persistence_file = Misc.process_options persist_options, :file
79
- return persistence_file unless persistence_file.nil?
80
-
81
- prefix = Misc.process_options persist_options, :prefix
82
-
83
- if prefix.nil?
84
- perfile = file.to_s.gsub(/\//, '>')
85
- else
86
- perfile = prefix.to_s + ":" + file.to_s.gsub(/\//, '>')
87
- end
88
-
89
- perfile.sub!(/\.b?gz$/,'')
90
-
91
- if options.include? :filters
92
- options[:filters].each do |match,value|
93
- perfile = perfile + "&F[#{match}=#{Misc.digest(value.inspect)}]"
94
- end
95
- end
96
-
97
- persistence_dir = Misc.process_options(persist_options, :dir) || Persist.cachedir
98
- Path.setup(persistence_dir) unless Path === persistence_dir
99
-
100
- filename = perfile.gsub(/\s/,'_').gsub(/\//,'>')
101
- clean_options = options.dup
102
- clean_options.delete :unnamed
103
- clean_options.delete "unnamed"
104
-
105
- filename = filename[0..MAX_FILE_LENGTH] << Misc.digest(filename[MAX_FILE_LENGTH+1..-1]) if filename.length > MAX_FILE_LENGTH + 10
106
-
107
- options_md5 = Misc.hash2md5 clean_options
108
- filename << ":" << options_md5 unless options_md5.empty?
109
-
110
- persistence_dir[filename]
111
- end
112
-
113
- TRUE_STRINGS = Set.new ["true", "True", "TRUE", "t", "T", "1", "yes", "Yes", "YES", "y", "Y", "ON", "on"] unless defined? TRUE_STRINGS
114
- def self.load_file(path, type)
115
- begin
116
- case (type || :marshal).to_sym
117
- when :path
118
- Path.setup(Open.read(path).strip)
119
- when :nil
120
- nil
121
- when :boolean
122
- TRUE_STRINGS.include? Open.read(path).chomp.strip
123
- when :annotations
124
- Annotated.load_tsv TSV.open(path)
125
- when :tsv
126
- TSV.open(path)
127
- when :marshal_tsv
128
- TSV.setup(Marshal.load(Open.open(path)))
129
- when :fwt
130
- FixWidthTable.get(path)
131
- when :string, :text
132
- Open.read(path)
133
- when :binary
134
- f = Open.open(path, :mode => 'rb')
135
- res = f.read
136
- f.close
137
- res.force_encoding("ASCII-8BIT") if res.respond_to? :force_encoding
138
- res
139
- when :array
140
- res = Open.read(path).split("\n", -1)
141
- res.pop if res.last and res.last.empty?
142
- res
143
- when :marshal
144
- Open.open(path) do |stream|
145
- content = stream.read.unpack("m").first
146
- Marshal.load(content)
147
- end
148
- when :json
149
- Open.open(path) do |stream|
150
- JSON.parse(stream.read)
151
- end
152
- when :yaml
153
- Misc.load_yaml(path)
154
- when :float
155
- Open.read(path).to_f
156
- when :integer
157
- Open.read(path).to_i
158
- else
159
- raise "Unknown persistence: #{ type }"
160
- end
161
- rescue
162
- Log.medium "Exception loading #{ type } #{ path }: #{$!.message}"
163
- raise $!
164
- end
165
- end
166
-
167
- def self.save_file(path, type, content, lockfile = nil)
168
- if content.nil?
169
- lockfile.unlock if lockfile and lockfile.locked?
170
- return
171
- end
172
-
173
- case (type || :marshal).to_sym
174
- when :path
175
- Open.write(path, content)
176
- when :nil
177
- nil
178
- when :boolean
179
- Misc.sensiblewrite(path, content ? "true" : "false", :lock => lockfile)
180
- when :fwt
181
- content.file.seek 0
182
- Misc.sensiblewrite(path, content.file.read, :lock => lockfile)
183
- when :tsv
184
- content = content.to_s if TSV === content
185
- Misc.sensiblewrite(path, content, :lock => lockfile)
186
- when :annotations
187
- Misc.sensiblewrite(path, Annotated.tsv(content, :all).to_s, :lock => lockfile)
188
- when :string, :text
189
- Misc.sensiblewrite(path, content, :lock => lockfile)
190
- when :binary
191
- content.force_encoding("ASCII-8BIT") if content.respond_to? :force_encoding
192
- f = Open.open(path, :mode => 'wb')
193
- f.puts content
194
- f.close
195
- content
196
- when :array
197
- case content
198
- when Array
199
- if content.empty?
200
- Misc.sensiblewrite(path, "", :lock => lockfile)
201
- else
202
- Misc.sensiblewrite(path, content * "\n" + "\n", :lock => lockfile)
203
- end
204
- when IO
205
- Misc.sensiblewrite(path, content, :lock => lockfile)
206
- else
207
- Misc.sensiblewrite(path, content.to_s, :lock => lockfile)
208
- end
209
- when :marshal_tsv
210
- Misc.sensiblewrite(path, Marshal.dump(content.dup), :lock => lockfile)
211
- when :marshal
212
- dump = Marshal.dump(content)
213
- Misc.sensiblewrite(path, [dump].pack("m"), :lock => lockfile)
214
- when :json
215
- Misc.sensiblewrite(path, JSON.dump(content), :lock => lockfile)
216
- when :yaml
217
- Misc.sensiblewrite(path, YAML.dump(content), :lock => lockfile)
218
- when :float, :integer, :tsv
219
- Misc.sensiblewrite(path, content.to_s, :lock => lockfile)
220
- else
221
- raise "Unknown persistence: #{ type }"
222
- end
223
- end
224
-
225
- def self.tee_stream_thread(stream, path, type, callback = nil, abort_callback = nil, lockfile = nil)
226
- file, out = Misc.tee_stream(stream)
227
-
228
- out.pair = file
229
- file.pair = out
230
-
231
- saver_thread = Thread.new do
232
- begin
233
- file.threads = []
234
- Thread.current["name"] = "file saver: " + path
235
- save_file(path, type, file, lockfile)
236
- rescue Aborted
237
- Log.medium "Persist stream thread aborted: #{ Log.color :blue, path }"
238
- file.abort if file.respond_to? :abort
239
- raise $!
240
- rescue Exception
241
- Log.medium "Persist stream thread exception: #{ Log.color :blue, path }"
242
- file.abort if file.respond_to? :abort
243
- raise $!
244
- rescue Exception
245
- Log.exception $!
246
- raise $!
247
- end
248
- end
249
-
250
- threads = [saver_thread]
251
- threads += stream.threads if stream.respond_to?(:threads) && stream.threads
252
- ConcurrentStream.setup(out, :threads => threads, :filename => path)
253
-
254
- #out.callback = callback
255
- out.abort_callback = abort_callback
256
- out.lockfile = stream.lockfile if stream.respond_to? :lockfile and stream.lockfile
257
-
258
- #stream.callback = callback
259
- #stream.abort_callback = abort_callback
260
-
261
- out
262
- end
263
-
264
- class << self
265
- alias tee_stream tee_stream_thread
266
- end
267
-
268
- def self.get_result(path, type, persist_options, lockfile, &block)
269
- res = yield path
270
- stream = res if IO === res
271
- stream = res.stream if res.respond_to? :stream
272
-
273
- if stream
274
- if persist_options[:no_load] == :stream
275
- callback = stream.respond_to?(:callback)? stream.callback : nil
276
- abort_callback = stream.respond_to?(:abort_callback)? stream.abort_callback : nil
277
-
278
- # This is to avoid calling the callbacks twice, since they have been
279
- # moved to the new 'res' stream
280
- #stream.callback = nil
281
- #stream.abort_callback = nil
282
-
283
- res = tee_stream(stream, path, type, callback, abort_callback, lockfile)
284
-
285
- #res.lockfile = lockfile
286
-
287
- raise KeepLocked.new res
288
- else
289
- stream = res.get_stream if res.respond_to? :get_stream
290
- begin
291
- Open.write(path, stream)
292
- Open.open(path) do |stream|
293
- case type
294
- when :array
295
- stream.read.split "\n"
296
- when :tsv
297
- TSV.open(stream)
298
- else
299
- stream.read
300
- end
301
- end
302
- rescue
303
- stream.abort if stream.respond_to? :abort
304
- raise $!
305
- end
306
- end
307
- else
308
- res
309
- end
310
- end
311
-
312
- def self.persist_file(path, type, persist_options, &block)
313
- Misc.insist do
314
- begin
315
- if is_persisted?(path, persist_options)
316
- Log.low "Persist up-to-date: #{ path } - #{Misc.fingerprint persist_options}"
317
- return path if persist_options[:no_load]
318
- return load_file(path, type)
319
- else
320
- Open.rm path if Open.exists? path
321
- end
322
- rescue Aborted, Interrupt
323
- Log.warn "Aborted loading persistence (#{ type }) #{ path }: #{$!.message}. Not erasing."
324
- raise $!
325
- rescue Exception
326
- Log.warn "Exception loading persistence (#{ type }) #{ path }: #{$!.message}. Erase and retry."
327
- Open.rm path if Open.exists? path
328
- raise $!
329
- end
330
- end
331
-
332
- lock_filename = Persist.persistence_path(path + '.persist', {:dir => Persist.lock_dir})
333
- begin
334
- lock_options = Misc.pull_keys persist_options, :lock
335
- lock_options = lock_options[:lock] if Hash === lock_options[:lock]
336
- Misc.lock lock_filename, lock_options do |lockfile|
337
- Misc.insist do
338
- if is_persisted?(path, persist_options)
339
- Log.low "Persist up-to-date (suddenly): #{ path } - #{Misc.fingerprint persist_options}"
340
- lockfile.unlock if lockfile.locked?
341
- return path if persist_options[:no_load]
342
- return load_file(path, type)
343
- end
344
- end
345
-
346
- Log.medium "Persist create: #{ path } - #{type} #{Misc.fingerprint persist_options}"
347
-
348
- res = get_result(path, type, persist_options, lockfile, &block)
349
-
350
- save_file(path, type, res, lockfile)
351
-
352
- Open.notify_write(path)
353
-
354
- return path if persist_options[:no_load] || type == :path
355
-
356
- res
357
- end
358
-
359
- rescue Lockfile::StolenLockError
360
- Log.medium "Lockfile stolen: #{path} - #{lock_filename}"
361
- Log.exception $!
362
- sleep 1 + rand(2)
363
- retry
364
- rescue TryAgain
365
- begin
366
- Open.rm path
367
- rescue
368
- end if Open.exists? path
369
- raise $!
370
- rescue Exception
371
- Log.medium "Error in persist: #{path}#{Open.exists?(path) ? Log.color(:red, " Erasing") : ""}"
372
-
373
- begin
374
- Open.rm path
375
- rescue
376
- end if Open.exists? path
377
-
378
- raise $!
379
- end
380
- end
381
-
382
- def self.persist(name, type = nil, persist_options = {}, &block)
383
- type ||= :marshal
384
-
385
- persist_options ||= {}
386
- if type == :memory && persist_options[:file] && persist_options[:persist]
387
- repo = persist_options[:repo] || Persist::MEMORY
388
- if persist_options[:persist] == :update || persist_options[:update]
389
- repo.delete persist_options[:file]
390
- end
391
- return repo[persist_options[:file]] ||= yield
392
- end
393
-
394
- if FalseClass === persist_options[:persist]
395
- yield
396
- else
397
- persist_options[:update] = true if persist_options[:persist].to_s == "update"
398
- other_options = Misc.process_options persist_options, :other
399
- path = persistence_path(name, persist_options, other_options || {})
400
-
401
- if ENV["RBBT_UPDATE_TSV_PERSIST"] == 'true' and name and Open.exists?(name)
402
- persist_options[:check] ||= []
403
- persist_options[:check] << name
404
- else
405
- check_options = {}
406
- end
407
-
408
- case
409
- when type.to_sym == :memory
410
- repo = persist_options[:repo] || Persist::MEMORY
411
- path = path.find if Path === path
412
- repo.delete path if persist_options[:update]
413
- repo[path] ||= yield
414
-
415
- when (type.to_sym == :annotations and (persist_options.include?(:annotation_repo) || persist_options.include?(:repo)))
416
-
417
- repo = persist_options[:annotation_repo] || persist_options[:repo]
418
-
419
- keys = nil
420
- subkey = name + ":"
421
-
422
- if String === repo
423
- repo = repo.find if Path === repo
424
- repo = Persist.open_tokyocabinet(repo, false, :list, "BDB")
425
- repo.read_and_close do
426
- keys = repo.range subkey + 0.chr, true, subkey + 254.chr, true
427
- end
428
- else
429
- repo.read_and_close do
430
- keys = repo.range subkey + 0.chr, true, subkey + 254.chr, true
431
- end
432
- end
433
-
434
- repo.read
435
-
436
- case
437
- when (keys.length == 1 and keys.first == subkey + 'NIL')
438
- nil
439
- when (keys.length == 1 and keys.first == subkey + 'EMPTY')
440
- []
441
- when (keys.length == 1 and keys.first =~ /:SINGLE$/)
442
- key = keys.first
443
- values = repo.with_read do
444
- repo[key]
445
- end
446
- Annotated.load_tsv_values(key, values, "literal", "annotation_types", "JSON")
447
- when (keys.any? and not keys.first =~ /ANNOTATED_DOUBLE_ARRAY/)
448
- repo.with_read do
449
- keys.sort_by{|k| k.split(":").last.to_i}.collect{|key|
450
- v = repo[key]
451
- Annotated.load_tsv_values(key, v, "literal", "annotation_types", "JSON")
452
- }
453
- end
454
- when (keys.any? and keys.first =~ /ANNOTATED_DOUBLE_ARRAY/)
455
- repo.with_read do
456
-
457
- res = keys.sort_by{|k| k.split(":").last.to_i}.collect{|key|
458
- v = repo[key]
459
- Annotated.load_tsv_values(key, v, "literal", "annotation_types", "JSON")
460
- }
461
-
462
- res.first.annotate res
463
- res.extend AnnotatedArray
464
-
465
- res
466
- end
467
- else
468
- entities = yield
469
-
470
- repo.write_and_read do
471
- case
472
- when entities.nil?
473
- repo[subkey + "NIL"] = nil
474
- when entities.empty?
475
- repo[subkey + "EMPTY"] = nil
476
- when (not Array === entities or (AnnotatedArray === entities and not Array === entities.first))
477
- tsv_values = entities.tsv_values("literal", "annotation_types", "JSON")
478
- repo[subkey + entities.id << ":" << "SINGLE"] = tsv_values
479
- when (not Array === entities or (AnnotatedArray === entities and AnnotatedArray === entities.first))
480
- entities.each_with_index do |e,i|
481
- next if e.nil?
482
- tsv_values = e.tsv_values("literal", "annotation_types", "JSON")
483
- repo[subkey + "ANNOTATED_DOUBLE_ARRAY:" << i.to_s] = tsv_values
484
- end
485
- else
486
- entities.each_with_index do |e,i|
487
- next if e.nil?
488
- tsv_values = e.tsv_values("literal", "annotation_types", "JSON")
489
- repo[subkey + i.to_s] = tsv_values
490
- end
491
- end
492
- end
493
-
494
- entities
495
- end
496
-
497
- else
498
- path = path.find if Path === path
499
- persist_file(path, type, persist_options, &block)
500
- end
501
-
502
- end
503
- end
504
-
505
- def self.memory(name, options = {}, &block)
506
- case options
507
- when nil
508
- persist name, :memory, :file => name, &block
509
- when String
510
- persist name, :memory, :file => name + "_" << options, &block
511
- else
512
- options = options.dup
513
- file = name
514
- repo = options.delete :repo if options and options.any?
515
- update = options.delete :update if options and options.any?
516
- file << "_" << (options[:key] ? options[:key] : Misc.hash2md5(options)) if options and options.any?
517
- persist name, :memory, {:repo => repo, :update => update, :persist => true, :file => file}.merge(options), &block
518
- end
519
- end
520
- end
521
-
522
- module LocalPersist
523
-
524
- attr_accessor :local_persist_dir
525
-
526
- def local_persist_dir
527
- @local_persist_dir ||= Rbbt.var.cache.persistence.find(:lib) if defined? Rbbt
528
- @local_persist_dir
529
- end
530
-
531
- def local_persist_dir=(value)
532
- @local_persist_dir = value
533
- end
534
-
535
- def self.local_persist(name, type = nil, options= {}, persist_options = nil, &block)
536
- persist_options ||= {}
537
- persist_options = {:dir => Rbbt.var.cache.persistence.find(:lib)}.merge persist_options
538
- persist_options[:other] = options
539
- Persist.persist(name, type, persist_options, &block)
540
- end
541
-
542
- def local_persist(name, type = nil, options= {}, persist_options = nil, &block)
543
- persist_options ||= {}
544
- persist_options = {:dir => local_persist_dir}.merge persist_options
545
- self.local_persist(name, type, options, persist_options, &block)
546
- end
547
-
548
- def local_persist_tsv(source, name, opt = {}, options= {}, &block)
549
- Persist.persist_tsv(source, name, opt, options.merge({:dir => local_persist_dir, :persist => true}), &block)
550
- end
551
- end
1
+ require_relative 'refactor'
2
+ Rbbt.require_instead 'scout/persist'
3
+ Rbbt.require_instead 'scout/tsv'
4
+ require_relative 'persist/refactor'
5
+ require_relative 'util/misc/lock'
6
+ #require 'rbbt'
7
+ #require 'rbbt/util/misc'
8
+ #require 'rbbt/util/open'
9
+ #
10
+ #require 'rbbt/persist/tsv'
11
+ #require 'set'
12
+ #
13
+ #module Persist
14
+ # class << self
15
+ # attr_accessor :cachedir
16
+ # def self.cachedir=(cachedir)
17
+ # @cachedir = Path === cachedir ? cachedir : Path.setup(cachedir)
18
+ # end
19
+ # def self.cachedir
20
+ # @cachedir ||= Rbbt.var.cache.persistence
21
+ # end
22
+ #
23
+ # attr_accessor :lock_dir
24
+ #
25
+ # def lock_dir
26
+ # @lock_dir ||= Rbbt.tmp.persist_locks
27
+ # end
28
+ # end
29
+ #
30
+ # MEMORY = {} unless defined? MEMORY
31
+ # MAX_FILE_LENGTH = 150
32
+ #
33
+ # # Is 'file' newer than 'path'? return non-true if path is newer than file
34
+ # def self.newer?(path, file, by_link = false)
35
+ # return true if not Open.exists?(file)
36
+ # path = path.find if Path === path
37
+ # file = file.find if Path === file
38
+ # if by_link
39
+ # patht = File.exist?(path) ? File.lstat(path).mtime : nil
40
+ # filet = File.exist?(file) ? File.lstat(file).mtime : nil
41
+ # else
42
+ # patht = Open.mtime(path)
43
+ # filet = Open.mtime(file)
44
+ # end
45
+ # return true if patht.nil? || filet.nil?
46
+ # diff = patht - filet
47
+ # return diff if diff < 0
48
+ # return false
49
+ # end
50
+ #
51
+ # def self.is_persisted?(path, persist_options = {})
52
+ # return true if Open.remote?(path)
53
+ # return true if Open.ssh?(path)
54
+ # return false if not Open.exists? path
55
+ # return false if TrueClass === persist_options[:update]
56
+ #
57
+ # expiration = persist_options[:expiration]
58
+ # if expiration
59
+ # seconds = Misc.timespan(expiration)
60
+ # patht = Open.mtime(path)
61
+ # return false if Time.now > patht + seconds
62
+ # end
63
+ #
64
+ # check = persist_options[:check]
65
+ # return true if check.nil?
66
+ #
67
+ # missing = check.reject{|file| Open.exists?(file) }
68
+ # return false if missing.any?
69
+ #
70
+ # return true unless ENV["RBBT_UPDATE"]
71
+ #
72
+ # if Array === check
73
+ # newer = check.select{|file| newer? path, file}
74
+ # return true if newer.empty?
75
+ # Log.medium "Persistence check for #{path} failed in: #{ Misc.fingerprint(newer)}"
76
+ # return false
77
+ # else
78
+ # ! newer?(path, check)
79
+ # end
80
+ # end
81
+ #
82
+ # def self.persistence_path(file, persist_options = {}, options = {})
83
+ # persistence_file = Misc.process_options persist_options, :file
84
+ # return persistence_file unless persistence_file.nil?
85
+ #
86
+ # prefix = Misc.process_options persist_options, :prefix
87
+ #
88
+ # if prefix.nil?
89
+ # perfile = file.to_s.gsub(/\//, '>')
90
+ # else
91
+ # perfile = prefix.to_s + ":" + file.to_s.gsub(/\//, '>')
92
+ # end
93
+ #
94
+ # perfile.sub!(/\.b?gz$/,'')
95
+ #
96
+ # if options.include? :filters
97
+ # options[:filters].each do |match,value|
98
+ # perfile = perfile + "&F[#{match}=#{Misc.digest(value.inspect)}]"
99
+ # end
100
+ # end
101
+ #
102
+ # persistence_dir = Misc.process_options(persist_options, :dir) || Persist.cachedir
103
+ # Path.setup(persistence_dir) unless Path === persistence_dir
104
+ #
105
+ # filename = perfile.gsub(/\s/,'_').gsub(/\//,'>')
106
+ # clean_options = options.dup
107
+ # clean_options.delete :unnamed
108
+ # clean_options.delete "unnamed"
109
+ #
110
+ # filename = filename[0..MAX_FILE_LENGTH] << Misc.digest(filename[MAX_FILE_LENGTH+1..-1]) if filename.length > MAX_FILE_LENGTH + 10
111
+ #
112
+ # options_md5 = Misc.hash2md5 clean_options
113
+ # filename << ":" << options_md5 unless options_md5.empty?
114
+ #
115
+ # persistence_dir[filename]
116
+ # end
117
+ #
118
+ # TRUE_STRINGS = Set.new ["true", "True", "TRUE", "t", "T", "1", "yes", "Yes", "YES", "y", "Y", "ON", "on"] unless defined? TRUE_STRINGS
119
+ # def self.load_file(path, type)
120
+ # begin
121
+ # case (type || :marshal).to_sym
122
+ # when :path
123
+ # Path.setup(Open.read(path).strip)
124
+ # when :nil
125
+ # nil
126
+ # when :boolean
127
+ # TRUE_STRINGS.include? Open.read(path).chomp.strip
128
+ # when :annotations
129
+ # Annotated.load_tsv TSV.open(path)
130
+ # when :tsv
131
+ # TSV.open(path)
132
+ # when :marshal_tsv
133
+ # TSV.setup(Marshal.load(Open.open(path)))
134
+ # when :fwt
135
+ # FixWidthTable.get(path)
136
+ # when :string, :text
137
+ # Open.read(path)
138
+ # when :binary
139
+ # f = Open.open(path, :mode => 'rb')
140
+ # res = f.read
141
+ # f.close
142
+ # res.force_encoding("ASCII-8BIT") if res.respond_to? :force_encoding
143
+ # res
144
+ # when :array
145
+ # res = Open.read(path).split("\n", -1)
146
+ # res.pop if res.last and res.last.empty?
147
+ # res
148
+ # when :marshal
149
+ # Open.open(path) do |stream|
150
+ # content = stream.read.unpack("m").first
151
+ # Marshal.load(content)
152
+ # end
153
+ # when :json
154
+ # Open.open(path) do |stream|
155
+ # JSON.parse(stream.read)
156
+ # end
157
+ # when :yaml
158
+ # Misc.load_yaml(path)
159
+ # when :float
160
+ # Open.read(path).to_f
161
+ # when :integer
162
+ # Open.read(path).to_i
163
+ # else
164
+ # raise "Unknown persistence: #{ type }"
165
+ # end
166
+ # rescue
167
+ # Log.medium "Exception loading #{ type } #{ path }: #{$!.message}"
168
+ # raise $!
169
+ # end
170
+ # end
171
+ #
172
+ # def self.save_file(path, type, content, lockfile = nil)
173
+ # if content.nil?
174
+ # lockfile.unlock if lockfile and lockfile.locked?
175
+ # return
176
+ # end
177
+ #
178
+ # case (type || :marshal).to_sym
179
+ # when :path
180
+ # Open.write(path, content)
181
+ # when :nil
182
+ # nil
183
+ # when :boolean
184
+ # Misc.sensiblewrite(path, content ? "true" : "false", :lock => lockfile)
185
+ # when :fwt
186
+ # content.file.seek 0
187
+ # Misc.sensiblewrite(path, content.file.read, :lock => lockfile)
188
+ # when :tsv
189
+ # content = content.to_s if TSV === content
190
+ # Misc.sensiblewrite(path, content, :lock => lockfile)
191
+ # when :annotations
192
+ # Misc.sensiblewrite(path, Annotated.tsv(content, :all).to_s, :lock => lockfile)
193
+ # when :string, :text
194
+ # Misc.sensiblewrite(path, content, :lock => lockfile)
195
+ # when :binary
196
+ # content.force_encoding("ASCII-8BIT") if content.respond_to? :force_encoding
197
+ # f = Open.open(path, :mode => 'wb')
198
+ # f.puts content
199
+ # f.close
200
+ # content
201
+ # when :array
202
+ # case content
203
+ # when Array
204
+ # if content.empty?
205
+ # Misc.sensiblewrite(path, "", :lock => lockfile)
206
+ # else
207
+ # Misc.sensiblewrite(path, content * "\n" + "\n", :lock => lockfile)
208
+ # end
209
+ # when IO
210
+ # Misc.sensiblewrite(path, content, :lock => lockfile)
211
+ # else
212
+ # Misc.sensiblewrite(path, content.to_s, :lock => lockfile)
213
+ # end
214
+ # when :marshal_tsv
215
+ # Misc.sensiblewrite(path, Marshal.dump(content.dup), :lock => lockfile)
216
+ # when :marshal
217
+ # dump = Marshal.dump(content)
218
+ # Misc.sensiblewrite(path, [dump].pack("m"), :lock => lockfile)
219
+ # when :json
220
+ # Misc.sensiblewrite(path, JSON.dump(content), :lock => lockfile)
221
+ # when :yaml
222
+ # Misc.sensiblewrite(path, YAML.dump(content), :lock => lockfile)
223
+ # when :float, :integer, :tsv
224
+ # Misc.sensiblewrite(path, content.to_s, :lock => lockfile)
225
+ # else
226
+ # raise "Unknown persistence: #{ type }"
227
+ # end
228
+ # end
229
+ #
230
+ # def self.tee_stream_thread(stream, path, type, callback = nil, abort_callback = nil, lockfile = nil)
231
+ # file, out = Misc.tee_stream(stream)
232
+ #
233
+ # out.pair = file
234
+ # file.pair = out
235
+ #
236
+ # saver_thread = Thread.new do
237
+ # begin
238
+ # file.threads = []
239
+ # Thread.current["name"] = "file saver: " + path
240
+ # save_file(path, type, file, lockfile)
241
+ # rescue Aborted
242
+ # Log.medium "Persist stream thread aborted: #{ Log.color :blue, path }"
243
+ # file.abort if file.respond_to? :abort
244
+ # raise $!
245
+ # rescue Exception
246
+ # Log.medium "Persist stream thread exception: #{ Log.color :blue, path }"
247
+ # file.abort if file.respond_to? :abort
248
+ # raise $!
249
+ # rescue Exception
250
+ # Log.exception $!
251
+ # raise $!
252
+ # end
253
+ # end
254
+ #
255
+ # threads = [saver_thread]
256
+ # threads += stream.threads if stream.respond_to?(:threads) && stream.threads
257
+ # ConcurrentStream.setup(out, :threads => threads, :filename => path)
258
+ #
259
+ # #out.callback = callback
260
+ # out.abort_callback = abort_callback
261
+ # out.lockfile = stream.lockfile if stream.respond_to? :lockfile and stream.lockfile
262
+ #
263
+ # #stream.callback = callback
264
+ # #stream.abort_callback = abort_callback
265
+ #
266
+ # out
267
+ # end
268
+ #
269
+ # class << self
270
+ # alias tee_stream tee_stream_thread
271
+ # end
272
+ #
273
+ # def self.get_result(path, type, persist_options, lockfile, &block)
274
+ # res = yield path
275
+ # stream = res if IO === res
276
+ # stream = res.stream if res.respond_to? :stream
277
+ #
278
+ # if stream
279
+ # if persist_options[:no_load] == :stream
280
+ # callback = stream.respond_to?(:callback)? stream.callback : nil
281
+ # abort_callback = stream.respond_to?(:abort_callback)? stream.abort_callback : nil
282
+ #
283
+ # # This is to avoid calling the callbacks twice, since they have been
284
+ # # moved to the new 'res' stream
285
+ # #stream.callback = nil
286
+ # #stream.abort_callback = nil
287
+ #
288
+ # res = tee_stream(stream, path, type, callback, abort_callback, lockfile)
289
+ #
290
+ # #res.lockfile = lockfile
291
+ #
292
+ # raise KeepLocked.new res
293
+ # else
294
+ # stream = res.get_stream if res.respond_to? :get_stream
295
+ # begin
296
+ # Open.write(path, stream)
297
+ # Open.open(path) do |stream|
298
+ # case type
299
+ # when :array
300
+ # stream.read.split "\n"
301
+ # when :tsv
302
+ # TSV.open(stream)
303
+ # else
304
+ # stream.read
305
+ # end
306
+ # end
307
+ # rescue
308
+ # stream.abort if stream.respond_to? :abort
309
+ # raise $!
310
+ # end
311
+ # end
312
+ # else
313
+ # res
314
+ # end
315
+ # end
316
+ #
317
+ # def self.persist_file(path, type, persist_options, &block)
318
+ # Misc.insist do
319
+ # begin
320
+ # if is_persisted?(path, persist_options)
321
+ # Log.low "Persist up-to-date: #{ path } - #{Misc.fingerprint persist_options}"
322
+ # return path if persist_options[:no_load]
323
+ # return load_file(path, type)
324
+ # else
325
+ # Open.rm path if Open.exists? path
326
+ # end
327
+ # rescue Aborted, Interrupt
328
+ # Log.warn "Aborted loading persistence (#{ type }) #{ path }: #{$!.message}. Not erasing."
329
+ # raise $!
330
+ # rescue Exception
331
+ # Log.warn "Exception loading persistence (#{ type }) #{ path }: #{$!.message}. Erase and retry."
332
+ # Open.rm path if Open.exists? path
333
+ # raise $!
334
+ # end
335
+ # end
336
+ #
337
+ # lock_filename = Persist.persistence_path(path + '.persist', {:dir => Persist.lock_dir})
338
+ # begin
339
+ # lock_options = Misc.pull_keys persist_options, :lock
340
+ # lock_options = lock_options[:lock] if Hash === lock_options[:lock]
341
+ # Misc.lock lock_filename, lock_options do |lockfile|
342
+ # Misc.insist do
343
+ # if is_persisted?(path, persist_options)
344
+ # Log.low "Persist up-to-date (suddenly): #{ path } - #{Misc.fingerprint persist_options}"
345
+ # lockfile.unlock if lockfile.locked?
346
+ # return path if persist_options[:no_load]
347
+ # return load_file(path, type)
348
+ # end
349
+ # end
350
+ #
351
+ # Log.medium "Persist create: #{ path } - #{type} #{Misc.fingerprint persist_options}"
352
+ #
353
+ # res = get_result(path, type, persist_options, lockfile, &block)
354
+ #
355
+ # save_file(path, type, res, lockfile)
356
+ #
357
+ # Open.notify_write(path)
358
+ #
359
+ # return path if persist_options[:no_load] || type == :path
360
+ #
361
+ # res
362
+ # end
363
+ #
364
+ # rescue Lockfile::StolenLockError
365
+ # Log.medium "Lockfile stolen: #{path} - #{lock_filename}"
366
+ # Log.exception $!
367
+ # sleep 1 + rand(2)
368
+ # retry
369
+ # rescue TryAgain
370
+ # begin
371
+ # Open.rm path
372
+ # rescue
373
+ # end if Open.exists? path
374
+ # raise $!
375
+ # rescue Exception
376
+ # Log.medium "Error in persist: #{path}#{Open.exists?(path) ? Log.color(:red, " Erasing") : ""}"
377
+ #
378
+ # begin
379
+ # Open.rm path
380
+ # rescue
381
+ # end if Open.exists? path
382
+ #
383
+ # raise $!
384
+ # end
385
+ # end
386
+ #
387
+ # def self.persist(name, type = nil, persist_options = {}, &block)
388
+ # type ||= :marshal
389
+ #
390
+ # persist_options ||= {}
391
+ # if type == :memory && persist_options[:file] && persist_options[:persist]
392
+ # repo = persist_options[:repo] || Persist::MEMORY
393
+ # if persist_options[:persist] == :update || persist_options[:update]
394
+ # repo.delete persist_options[:file]
395
+ # end
396
+ # return repo[persist_options[:file]] ||= yield
397
+ # end
398
+ #
399
+ # if FalseClass === persist_options[:persist]
400
+ # yield
401
+ # else
402
+ # persist_options[:update] = true if persist_options[:persist].to_s == "update"
403
+ # other_options = Misc.process_options persist_options, :other
404
+ # path = persistence_path(name, persist_options, other_options || {})
405
+ #
406
+ # if ENV["RBBT_UPDATE_TSV_PERSIST"] == 'true' and name and Open.exists?(name)
407
+ # persist_options[:check] ||= []
408
+ # persist_options[:check] << name
409
+ # else
410
+ # check_options = {}
411
+ # end
412
+ #
413
+ # case
414
+ # when type.to_sym == :memory
415
+ # repo = persist_options[:repo] || Persist::MEMORY
416
+ # path = path.find if Path === path
417
+ # repo.delete path if persist_options[:update]
418
+ # repo[path] ||= yield
419
+ #
420
+ # when (type.to_sym == :annotations and persist_options.include? :annotation_repo)
421
+ #
422
+ # repo = persist_options[:annotation_repo]
423
+ #
424
+ # keys = nil
425
+ # subkey = name + ":"
426
+ #
427
+ # if String === repo
428
+ # repo = repo.find if Path === repo
429
+ # repo = Persist.open_tokyocabinet(repo, false, :list, "BDB")
430
+ # repo.read_and_close do
431
+ # keys = repo.range subkey + 0.chr, true, subkey + 254.chr, true
432
+ # end
433
+ # else
434
+ # repo.read_and_close do
435
+ # keys = repo.range subkey + 0.chr, true, subkey + 254.chr, true
436
+ # end
437
+ # end
438
+ #
439
+ # repo.read
440
+ #
441
+ # case
442
+ # when (keys.length == 1 and keys.first == subkey + 'NIL')
443
+ # nil
444
+ # when (keys.length == 1 and keys.first == subkey + 'EMPTY')
445
+ # []
446
+ # when (keys.length == 1 and keys.first =~ /:SINGLE$/)
447
+ # key = keys.first
448
+ # values = repo.with_read do
449
+ # repo[key]
450
+ # end
451
+ # Annotated.load_tsv_values(key, values, "literal", "annotation_types", "JSON")
452
+ # when (keys.any? and not keys.first =~ /ANNOTATED_DOUBLE_ARRAY/)
453
+ # repo.with_read do
454
+ # keys.sort_by{|k| k.split(":").last.to_i}.collect{|key|
455
+ # v = repo[key]
456
+ # Annotated.load_tsv_values(key, v, "literal", "annotation_types", "JSON")
457
+ # }
458
+ # end
459
+ # when (keys.any? and keys.first =~ /ANNOTATED_DOUBLE_ARRAY/)
460
+ # repo.with_read do
461
+ #
462
+ # res = keys.sort_by{|k| k.split(":").last.to_i}.collect{|key|
463
+ # v = repo[key]
464
+ # Annotated.load_tsv_values(key, v, "literal", "annotation_types", "JSON")
465
+ # }
466
+ #
467
+ # res.first.annotate res
468
+ # res.extend AnnotatedArray
469
+ #
470
+ # res
471
+ # end
472
+ # else
473
+ # entities = yield
474
+ #
475
+ # repo.write_and_read do
476
+ # case
477
+ # when entities.nil?
478
+ # repo[subkey + "NIL"] = nil
479
+ # when entities.empty?
480
+ # repo[subkey + "EMPTY"] = nil
481
+ # when (not Array === entities or (AnnotatedArray === entities and not Array === entities.first))
482
+ # tsv_values = entities.tsv_values("literal", "annotation_types", "JSON")
483
+ # repo[subkey + entities.id << ":" << "SINGLE"] = tsv_values
484
+ # when (not Array === entities or (AnnotatedArray === entities and AnnotatedArray === entities.first))
485
+ # entities.each_with_index do |e,i|
486
+ # next if e.nil?
487
+ # tsv_values = e.tsv_values("literal", "annotation_types", "JSON")
488
+ # repo[subkey + "ANNOTATED_DOUBLE_ARRAY:" << i.to_s] = tsv_values
489
+ # end
490
+ # else
491
+ # entities.each_with_index do |e,i|
492
+ # next if e.nil?
493
+ # tsv_values = e.tsv_values("literal", "annotation_types", "JSON")
494
+ # repo[subkey + i.to_s] = tsv_values
495
+ # end
496
+ # end
497
+ # end
498
+ #
499
+ # entities
500
+ # end
501
+ #
502
+ # else
503
+ # path = path.find if Path === path
504
+ # persist_file(path, type, persist_options, &block)
505
+ # end
506
+ #
507
+ # end
508
+ # end
509
+ #
510
+ # def self.memory(name, options = {}, &block)
511
+ # case options
512
+ # when nil
513
+ # persist name, :memory, :file => name, &block
514
+ # when String
515
+ # persist name, :memory, :file => name + "_" << options, &block
516
+ # else
517
+ # options = options.dup
518
+ # file = name
519
+ # repo = options.delete :repo if options and options.any?
520
+ # update = options.delete :update if options and options.any?
521
+ # file << "_" << (options[:key] ? options[:key] : Misc.hash2md5(options)) if options and options.any?
522
+ # persist name, :memory, {:repo => repo, :update => update, :persist => true, :file => file}.merge(options), &block
523
+ # end
524
+ # end
525
+ #end
526
+ #
527
+ #module LocalPersist
528
+ #
529
+ # attr_accessor :local_persist_dir
530
+ #
531
+ # def local_persist_dir
532
+ # @local_persist_dir ||= Rbbt.var.cache.persistence.find(:lib) if defined? Rbbt
533
+ # @local_persist_dir
534
+ # end
535
+ #
536
+ # def local_persist_dir=(value)
537
+ # @local_persist_dir = value
538
+ # end
539
+ #
540
+ # def self.local_persist(name, type = nil, options= {}, persist_options = nil, &block)
541
+ # persist_options ||= {}
542
+ # persist_options = {:dir => Rbbt.var.cache.persistence.find(:lib)}.merge persist_options
543
+ # persist_options[:other] = options
544
+ # Persist.persist(name, type, persist_options, &block)
545
+ # end
546
+ #
547
+ # def local_persist(name, type = nil, options= {}, persist_options = nil, &block)
548
+ # persist_options ||= {}
549
+ # persist_options = {:dir => local_persist_dir}.merge persist_options
550
+ # self.local_persist(name, type, options, persist_options, &block)
551
+ # end
552
+ #
553
+ # def local_persist_tsv(source, name, opt = {}, options= {}, &block)
554
+ # Persist.persist_tsv(source, name, opt, options.merge({:dir => local_persist_dir, :persist => true}), &block)
555
+ # end
556
+ #end