rbbt-util 5.44.1 → 6.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/bin/rbbt +67 -90
  3. data/etc/app.d/base.rb +2 -2
  4. data/etc/app.d/semaphores.rb +3 -3
  5. data/lib/rbbt/annotations/annotated_array.rb +207 -207
  6. data/lib/rbbt/annotations/refactor.rb +27 -0
  7. data/lib/rbbt/annotations/util.rb +282 -282
  8. data/lib/rbbt/annotations.rb +343 -320
  9. data/lib/rbbt/association/database.rb +200 -225
  10. data/lib/rbbt/association/index.rb +294 -291
  11. data/lib/rbbt/association/item.rb +227 -227
  12. data/lib/rbbt/association/open.rb +35 -34
  13. data/lib/rbbt/association/util.rb +0 -169
  14. data/lib/rbbt/association.rb +2 -4
  15. data/lib/rbbt/entity/identifiers.rb +119 -118
  16. data/lib/rbbt/entity/refactor.rb +12 -0
  17. data/lib/rbbt/entity.rb +319 -315
  18. data/lib/rbbt/hpc/batch.rb +72 -53
  19. data/lib/rbbt/hpc/lsf.rb +2 -2
  20. data/lib/rbbt/hpc/orchestrate/batches.rb +2 -2
  21. data/lib/rbbt/hpc/orchestrate/chains.rb +25 -5
  22. data/lib/rbbt/hpc/orchestrate/rules.rb +2 -2
  23. data/lib/rbbt/hpc/orchestrate.rb +19 -13
  24. data/lib/rbbt/hpc/slurm.rb +18 -18
  25. data/lib/rbbt/knowledge_base/entity.rb +13 -5
  26. data/lib/rbbt/knowledge_base/query.rb +2 -2
  27. data/lib/rbbt/knowledge_base/registry.rb +32 -31
  28. data/lib/rbbt/knowledge_base/traverse.rb +1 -1
  29. data/lib/rbbt/knowledge_base.rb +1 -1
  30. data/lib/rbbt/monitor.rb +36 -25
  31. data/lib/rbbt/persist/refactor.rb +166 -0
  32. data/lib/rbbt/persist/tsv/tokyocabinet.rb +105 -105
  33. data/lib/rbbt/persist/tsv.rb +187 -185
  34. data/lib/rbbt/persist.rb +556 -551
  35. data/lib/rbbt/refactor.rb +20 -0
  36. data/lib/rbbt/resource/path/refactor.rb +178 -0
  37. data/lib/rbbt/resource/path.rb +317 -497
  38. data/lib/rbbt/resource/util.rb +0 -48
  39. data/lib/rbbt/resource.rb +3 -390
  40. data/lib/rbbt/tsv/accessor.rb +2 -838
  41. data/lib/rbbt/tsv/attach.rb +303 -299
  42. data/lib/rbbt/tsv/change_id.rb +244 -245
  43. data/lib/rbbt/tsv/csv.rb +87 -85
  44. data/lib/rbbt/tsv/dumper.rb +2 -100
  45. data/lib/rbbt/tsv/excel.rb +26 -24
  46. data/lib/rbbt/tsv/field_index.rb +4 -1
  47. data/lib/rbbt/tsv/filter.rb +3 -2
  48. data/lib/rbbt/tsv/index.rb +2 -284
  49. data/lib/rbbt/tsv/manipulate.rb +750 -747
  50. data/lib/rbbt/tsv/marshal.rb +3 -3
  51. data/lib/rbbt/tsv/matrix.rb +2 -2
  52. data/lib/rbbt/tsv/parallel/through.rb +2 -1
  53. data/lib/rbbt/tsv/parallel/traverse.rb +783 -781
  54. data/lib/rbbt/tsv/parser.rb +678 -678
  55. data/lib/rbbt/tsv/refactor.rb +195 -0
  56. data/lib/rbbt/tsv/stream.rb +253 -251
  57. data/lib/rbbt/tsv/util.rb +420 -420
  58. data/lib/rbbt/tsv.rb +210 -208
  59. data/lib/rbbt/util/R/eval.rb +4 -4
  60. data/lib/rbbt/util/R/plot.rb +62 -166
  61. data/lib/rbbt/util/R.rb +21 -18
  62. data/lib/rbbt/util/cmd.rb +2 -318
  63. data/lib/rbbt/util/color.rb +269 -269
  64. data/lib/rbbt/util/colorize.rb +89 -89
  65. data/lib/rbbt/util/concurrency/processes/refactor.rb +22 -0
  66. data/lib/rbbt/util/concurrency/processes/worker.rb +2 -2
  67. data/lib/rbbt/util/concurrency/processes.rb +389 -386
  68. data/lib/rbbt/util/config.rb +169 -167
  69. data/lib/rbbt/util/iruby.rb +20 -0
  70. data/lib/rbbt/util/log/progress/report.rb +241 -241
  71. data/lib/rbbt/util/log/progress/util.rb +99 -99
  72. data/lib/rbbt/util/log/progress.rb +102 -102
  73. data/lib/rbbt/util/log/refactor.rb +49 -0
  74. data/lib/rbbt/util/log.rb +486 -532
  75. data/lib/rbbt/util/migrate.rb +1 -1
  76. data/lib/rbbt/util/misc/concurrent_stream.rb +248 -246
  77. data/lib/rbbt/util/misc/development.rb +12 -11
  78. data/lib/rbbt/util/misc/exceptions.rb +117 -112
  79. data/lib/rbbt/util/misc/format.rb +2 -230
  80. data/lib/rbbt/util/misc/indiferent_hash.rb +2 -107
  81. data/lib/rbbt/util/misc/inspect.rb +2 -476
  82. data/lib/rbbt/util/misc/lock.rb +109 -106
  83. data/lib/rbbt/util/misc/omics.rb +9 -1
  84. data/lib/rbbt/util/misc/pipes.rb +765 -793
  85. data/lib/rbbt/util/misc/refactor.rb +20 -0
  86. data/lib/rbbt/util/misc/ssw.rb +27 -17
  87. data/lib/rbbt/util/misc/system.rb +0 -15
  88. data/lib/rbbt/util/misc.rb +39 -20
  89. data/lib/rbbt/util/named_array/refactor.rb +4 -0
  90. data/lib/rbbt/util/named_array.rb +3 -220
  91. data/lib/rbbt/util/open/refactor.rb +7 -0
  92. data/lib/rbbt/util/open.rb +3 -857
  93. data/lib/rbbt/util/procpath.rb +6 -6
  94. data/lib/rbbt/util/python/paths.rb +27 -0
  95. data/lib/rbbt/util/python/run.rb +115 -0
  96. data/lib/rbbt/util/python/script.rb +110 -0
  97. data/lib/rbbt/util/python/util.rb +3 -3
  98. data/lib/rbbt/util/python.rb +22 -81
  99. data/lib/rbbt/util/semaphore.rb +152 -148
  100. data/lib/rbbt/util/simpleopt.rb +9 -8
  101. data/lib/rbbt/util/ssh/refactor.rb +19 -0
  102. data/lib/rbbt/util/ssh.rb +122 -118
  103. data/lib/rbbt/util/tar.rb +117 -115
  104. data/lib/rbbt/util/tmpfile.rb +69 -67
  105. data/lib/rbbt/util/version.rb +2 -0
  106. data/lib/rbbt/workflow/refactor/entity.rb +11 -0
  107. data/lib/rbbt/workflow/refactor/export.rb +66 -0
  108. data/lib/rbbt/workflow/refactor/inputs.rb +24 -0
  109. data/lib/rbbt/workflow/refactor/recursive.rb +64 -0
  110. data/lib/rbbt/workflow/refactor/task_info.rb +65 -0
  111. data/lib/rbbt/workflow/refactor.rb +153 -0
  112. data/lib/rbbt/workflow/remote_workflow/driver/ssh.rb +55 -32
  113. data/lib/rbbt/workflow/remote_workflow/remote_step/rest.rb +3 -1
  114. data/lib/rbbt/workflow/remote_workflow/remote_step/ssh.rb +14 -5
  115. data/lib/rbbt/workflow/remote_workflow/remote_step.rb +19 -7
  116. data/lib/rbbt/workflow/remote_workflow.rb +6 -1
  117. data/lib/rbbt/workflow/step/run.rb +766 -766
  118. data/lib/rbbt/workflow/step/save_load_inputs.rb +254 -254
  119. data/lib/rbbt/workflow/step.rb +2 -362
  120. data/lib/rbbt/workflow/task.rb +118 -118
  121. data/lib/rbbt/workflow/usage.rb +289 -287
  122. data/lib/rbbt/workflow/util/archive.rb +6 -5
  123. data/lib/rbbt/workflow/util/data.rb +1 -1
  124. data/lib/rbbt/workflow/util/orchestrator.rb +249 -246
  125. data/lib/rbbt/workflow/util/trace.rb +79 -44
  126. data/lib/rbbt/workflow.rb +4 -882
  127. data/lib/rbbt-util.rb +21 -13
  128. data/lib/rbbt.rb +16 -3
  129. data/python/rbbt/__init__.py +19 -1
  130. data/share/Rlib/plot.R +37 -37
  131. data/share/Rlib/svg.R +22 -5
  132. data/share/install/software/lib/install_helpers +1 -1
  133. data/share/rbbt_commands/hpc/list +2 -3
  134. data/share/rbbt_commands/hpc/orchestrate +4 -4
  135. data/share/rbbt_commands/hpc/tail +2 -0
  136. data/share/rbbt_commands/hpc/task +10 -7
  137. data/share/rbbt_commands/lsf/list +2 -3
  138. data/share/rbbt_commands/lsf/orchestrate +4 -4
  139. data/share/rbbt_commands/lsf/tail +2 -0
  140. data/share/rbbt_commands/lsf/task +10 -7
  141. data/share/rbbt_commands/migrate +1 -1
  142. data/share/rbbt_commands/pbs/list +2 -3
  143. data/share/rbbt_commands/pbs/orchestrate +4 -4
  144. data/share/rbbt_commands/pbs/tail +2 -0
  145. data/share/rbbt_commands/pbs/task +10 -7
  146. data/share/rbbt_commands/resource/produce +8 -1
  147. data/share/rbbt_commands/slurm/list +2 -3
  148. data/share/rbbt_commands/slurm/orchestrate +4 -4
  149. data/share/rbbt_commands/slurm/tail +2 -0
  150. data/share/rbbt_commands/slurm/task +10 -7
  151. data/share/rbbt_commands/system/clean +5 -5
  152. data/share/rbbt_commands/system/status +5 -5
  153. data/share/rbbt_commands/tsv/get +2 -3
  154. data/share/rbbt_commands/tsv/info +10 -13
  155. data/share/rbbt_commands/tsv/keys +18 -14
  156. data/share/rbbt_commands/tsv/slice +2 -2
  157. data/share/rbbt_commands/tsv/transpose +6 -2
  158. data/share/rbbt_commands/workflow/info +20 -24
  159. data/share/rbbt_commands/workflow/list +1 -1
  160. data/share/rbbt_commands/workflow/prov +20 -13
  161. data/share/rbbt_commands/workflow/server +11 -1
  162. data/share/rbbt_commands/workflow/task +76 -71
  163. data/share/rbbt_commands/workflow/write_info +26 -9
  164. data/share/software/opt/ssw/ssw.c +861 -0
  165. data/share/software/opt/ssw/ssw.h +130 -0
  166. data/share/workflow_config.ru +3 -3
  167. metadata +40 -2
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