SciMed-bj 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,86 @@
1
+ class Hash
2
+ begin
3
+ method "to_options"
4
+ rescue
5
+ def to_options
6
+ inject(Hash.new){|h, kv| h.update kv.first.to_s.to_sym => kv.last}
7
+ end
8
+ def to_options!
9
+ replace to_options
10
+ end
11
+ end
12
+
13
+ begin
14
+ method "to_string_options"
15
+ rescue
16
+ def to_string_options
17
+ inject(Hash.new){|h, kv| h.update kv.first.to_s => kv.last}
18
+ end
19
+ def to_string_options!
20
+ replace to_string_options
21
+ end
22
+ end
23
+
24
+ begin
25
+ method "reverse_merge"
26
+ rescue
27
+ def reverse_merge other
28
+ other.merge self
29
+ end
30
+ def reverse_merge! other
31
+ replace reverse_merge(other)
32
+ end
33
+ end
34
+
35
+ begin
36
+ method "slice"
37
+ rescue
38
+ def slice(*keys)
39
+ allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
40
+ reject { |key,| !allowed.include?(key) }
41
+ end
42
+ end
43
+
44
+ begin
45
+ method "slice!"
46
+ rescue
47
+ def slice!(*keys)
48
+ replace(slice(*keys))
49
+ end
50
+ end
51
+ end
52
+
53
+ class Object
54
+ begin
55
+ method "returning"
56
+ rescue
57
+ def returning value, &block
58
+ block.call value
59
+ value
60
+ end
61
+ end
62
+ end
63
+
64
+ class Object
65
+ def singleton_class &block
66
+ @singleton_class ||=
67
+ class << self
68
+ self
69
+ end
70
+ block ? @singleton_class.module_eval(&block) : @singleton_class
71
+ end
72
+ end
73
+
74
+ class String
75
+ begin
76
+ method 'underscore'
77
+ rescue
78
+ def underscore
79
+ gsub(/::/, '/').
80
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
81
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
82
+ tr("-", "_").
83
+ downcase
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,426 @@
1
+ class Bj
2
+ #
3
+ # table base class
4
+ #
5
+ class Table < ActiveRecord::Base
6
+ module ClassMethods
7
+ fattr("list"){ Array.new }
8
+ fattr("migration"){}
9
+
10
+ def migration_code classname = "BjMigration"
11
+ <<-code
12
+ class #{ classname } < ActiveRecord::Migration
13
+ def self.up
14
+ Bj::Table.each{|table| table.up}
15
+ end
16
+ def self.down
17
+ Bj::Table.reverse_each{|table| table.down}
18
+ end
19
+ end
20
+ code
21
+ end
22
+
23
+ def up
24
+ migration_class.up
25
+ end
26
+
27
+ def down
28
+ migration_class.down
29
+ end
30
+
31
+ def migration_class
32
+ table = self
33
+ @migration_class ||=
34
+ Class.new(ActiveRecord::Migration) do
35
+ sc =
36
+ class << self
37
+ self
38
+ end
39
+ sc.module_eval{ fattr :table => table }
40
+ sc.module_eval &table.migration
41
+ end
42
+ end
43
+
44
+ def content_column_names
45
+ @content_column_names = content_columns.map{|column| column.name}
46
+ end
47
+
48
+ def create_hash_for options
49
+ options.to_options!
50
+ hash = {}
51
+ content_column_names.each do |key|
52
+ key = key.to_s.to_sym
53
+ hash[key] = options[key]
54
+ end
55
+ hash
56
+ end
57
+
58
+ def each *a, &b
59
+ list.each *a, &b
60
+ end
61
+
62
+ def reverse_each *a, &b
63
+ list.reverse.each *a, &b
64
+ end
65
+ end
66
+ send :extend, ClassMethods
67
+
68
+ module InstanceMethods
69
+ def to_hash
70
+ oh = OrderedHash.new
71
+ self.class.content_column_names.each{|c| oh[c] = self[c]}
72
+ oh
73
+ end
74
+ end
75
+ send :include, InstanceMethods
76
+
77
+ module RecursivelyInherited
78
+ def inherited other
79
+ super
80
+ ensure
81
+ (Table.list << other).uniq!
82
+ basename = other.name.split(%r/::/).last.underscore
83
+ Table.singleton_class{ fattr basename => other }
84
+ other.send :extend, RecursivelyInherited
85
+ end
86
+ end
87
+ send :extend, RecursivelyInherited
88
+
89
+ #
90
+ # table classes
91
+ #
92
+ class Job < Table
93
+ set_table_name "bj_job"
94
+ set_primary_key "#{ table_name }_id"
95
+
96
+ migration {
97
+ define_method :up do
98
+ create_table table.table_name, :primary_key => table.primary_key, :force => true do |t|
99
+ t.column "command" , :text
100
+
101
+ t.column "state" , :text
102
+ t.column "priority" , :integer
103
+ t.column "tag" , :text
104
+ t.column "is_restartable" , :integer
105
+
106
+ t.column "submitter" , :text
107
+ t.column "runner" , :text
108
+ t.column "pid" , :integer
109
+
110
+ t.column "submitted_at" , :datetime
111
+ t.column "started_at" , :datetime
112
+ t.column "finished_at" , :datetime
113
+
114
+ t.column "env" , :text
115
+ t.column "stdin" , :text
116
+ t.column "stdout" , :text
117
+ t.column "stderr" , :text
118
+ t.column "exit_status" , :integer
119
+ end
120
+ end
121
+
122
+ define_method :down do
123
+ drop_table table.table_name
124
+ end
125
+ }
126
+
127
+ module ClassMethods
128
+ def submit jobs, options = {}, &block
129
+ jobs = Joblist.for jobs, options
130
+ returned = []
131
+ transaction do
132
+ jobs.each do |job|
133
+ job = create_hash_for(job.reverse_merge(submit_defaults))
134
+ job = create! job
135
+ returned << (block ? block.call(job) : job)
136
+ end
137
+ end
138
+ returned
139
+ end
140
+
141
+ def submit_defaults
142
+ {
143
+ :state => "pending",
144
+ :priority => 0,
145
+ :tag => "",
146
+ :is_restartable => true,
147
+ :submitter => Bj.hostname,
148
+ :submitted_at => Time.now,
149
+ }
150
+ end
151
+ end
152
+ send :extend, ClassMethods
153
+
154
+ module InstanceMethods
155
+ def title
156
+ "job[#{ id }](#{ command })"
157
+ end
158
+
159
+ def finished
160
+ reload
161
+ exit_status
162
+ end
163
+ alias_method "finished?", "finished"
164
+
165
+ def run! options = {}
166
+ job = self
167
+ thread = nil
168
+
169
+ command = job.command
170
+ env = job.env ? YAML.load(job.env) : {}
171
+ stdin = job.stdin || ''
172
+ stdout = job.stdout || ''
173
+ stderr = job.stderr || ''
174
+ started_at = Time.now
175
+
176
+ job.state = "starting"
177
+ job.save!
178
+
179
+ thread = Util.start command, :cwd=>Bj.rails_root, :env=>env, :stdin=>stdin, :stdout=>stdout, :stderr=>stderr
180
+
181
+ job.state = "running"
182
+ job.runner = Bj.hostname
183
+ job.pid = thread.pid
184
+ job.started_at = started_at
185
+
186
+ Bj.transaction(options) do
187
+ job.save!
188
+ job.reload
189
+ end
190
+
191
+ exit_status = thread.value
192
+
193
+ job.state = "finished"
194
+ job.finished_at = Time.now
195
+ job.stdout = stdout
196
+ job.stderr = stderr
197
+ job.exit_status = exit_status
198
+
199
+ Bj.transaction(options) do
200
+ job.save!
201
+ job.reload
202
+ end
203
+
204
+ job
205
+ end
206
+ end
207
+ send :include, InstanceMethods
208
+ end
209
+
210
+ class JobArchive < Job
211
+ set_table_name "bj_job_archive"
212
+ set_primary_key "#{ table_name }_id"
213
+
214
+ migration {
215
+ define_method(:up) do
216
+ create_table table.table_name, :primary_key => table.primary_key, :force => true do |t|
217
+ t.column "command" , :text
218
+
219
+ t.column "state" , :text
220
+ t.column "priority" , :integer
221
+ t.column "tag" , :text
222
+ t.column "is_restartable" , :integer
223
+
224
+ t.column "submitter" , :text
225
+ t.column "runner" , :text
226
+ t.column "pid" , :integer
227
+
228
+ t.column "submitted_at" , :datetime
229
+ t.column "started_at" , :datetime
230
+ t.column "finished_at" , :datetime
231
+ t.column "archived_at" , :datetime
232
+
233
+ t.column "env" , :text
234
+ t.column "stdin" , :text
235
+ t.column "stdout" , :text
236
+ t.column "stderr" , :text
237
+ t.column "exit_status" , :integer
238
+ end
239
+ end
240
+
241
+ define_method(:down) do
242
+ drop_table table.table_name
243
+ end
244
+ }
245
+ end
246
+
247
+ class Config < Table
248
+ set_table_name "bj_config"
249
+ set_primary_key "#{ table_name }_id"
250
+
251
+ migration {
252
+ define_method(:up) do
253
+ create_table table.table_name, :primary_key => table.primary_key, :force => true do |t|
254
+ t.column "hostname" , :text
255
+ t.column "key" , :text
256
+ t.column "value" , :text
257
+ t.column "cast" , :text
258
+ end
259
+
260
+ begin
261
+ add_index table.table_name, %w[ hostname key ], :unique => true
262
+ rescue Exception
263
+ STDERR.puts "WARNING: your database is sucking and does not support unique indexes on text fields!?"
264
+ end
265
+ end
266
+
267
+ define_method(:down) do
268
+ begin
269
+ remove_index table.table_name, :column => %w[ hostname key ]
270
+ rescue Exception
271
+ end
272
+ drop_table table.table_name
273
+ end
274
+ }
275
+
276
+ module ClassMethods
277
+ def [] key
278
+ get key
279
+ end
280
+
281
+ def get key, options = {}
282
+ transaction do
283
+ options.to_options!
284
+ hostname = options[:hostname] || Bj.hostname
285
+ record = find :first, :conditions => conditions(:key => key, :hostname => hostname)
286
+ record ? record.value : default_for(key)
287
+ end
288
+ end
289
+
290
+ def conditions options = {}
291
+ options.to_options!
292
+ options.reverse_merge!(
293
+ :hostname => Bj.hostname
294
+ )
295
+ options
296
+ end
297
+
298
+ def default_for key
299
+ record = find :first, :conditions => conditions(:key => key, :hostname => '*')
300
+ record ? record.value : nil
301
+ end
302
+
303
+ def []= key, value
304
+ set key, value
305
+ end
306
+
307
+ def set key, value, options = {}
308
+ transaction do
309
+ options.to_options!
310
+ hostname = options[:hostname] || Bj.hostname
311
+ record = find :first, :conditions => conditions(:key => key, :hostname => hostname), :lock => true
312
+ cast = options[:cast] || cast_for(value)
313
+ key = key.to_s
314
+ value = value.to_s
315
+ if record
316
+ record["value"] = value
317
+ record["cast"] = cast
318
+ record.save!
319
+ else
320
+ create! :hostname => hostname, :key => key, :value => value, :cast => cast
321
+ end
322
+ value
323
+ end
324
+ end
325
+
326
+ def delete key
327
+ transaction do
328
+ record = find :first, :conditions => conditions(:key => key), :lock => true
329
+ if record
330
+ record.destroy
331
+ record
332
+ else
333
+ nil
334
+ end
335
+ end
336
+ end
337
+
338
+ def has_key? key
339
+ record = find :first, :conditions => conditions(:key => key)
340
+ record ? record : false
341
+ end
342
+ alias_method "has_key", "has_key?"
343
+
344
+ def keys
345
+ find(:all, :conditions => conditions).map(&:key)
346
+ end
347
+
348
+ def values
349
+ find(:all, :conditions => conditions).map(&:value)
350
+ end
351
+
352
+ def for options = {}
353
+ oh = OrderedHash.new
354
+ find(:all, :conditions => conditions(options)).each do |record|
355
+ oh[record.key] = record.value
356
+ end
357
+ oh
358
+ end
359
+
360
+ def cast_for value
361
+ case value
362
+ when TrueClass, FalseClass
363
+ 'to_bool'
364
+ when NilClass
365
+ 'to_nil'
366
+ when Fixnum, Bignum
367
+ 'to_i'
368
+ when Float
369
+ 'to_f'
370
+ when Time
371
+ 'to_time'
372
+ when Symbol
373
+ 'to_sym'
374
+ else
375
+ case value.to_s
376
+ when %r/^\d+$/
377
+ 'to_i'
378
+ when %r/^\d+\.\d+$/
379
+ 'to_f'
380
+ when %r/^nil$|^$/
381
+ 'to_nil'
382
+ when %r/^true|false$/
383
+ 'to_bool'
384
+ else
385
+ 'to_s'
386
+ end
387
+ end
388
+ end
389
+
390
+ def casts
391
+ @casts ||= {
392
+ 'to_bool' => lambda do |value|
393
+ value.to_s =~ %r/^true$/i ? true : false
394
+ end,
395
+ 'to_i' => lambda do |value|
396
+ Integer value.to_s.gsub(%r/^(-)?0*/,'\1')
397
+ end,
398
+ 'to_f' => lambda do |value|
399
+ Float value.to_s.gsub(%r/^0*/,'')
400
+ end,
401
+ 'to_time' => lambda do |value|
402
+ Time.parse(value.to_s)
403
+ end,
404
+ 'to_sym' => lambda do |value|
405
+ value.to_s.to_sym
406
+ end,
407
+ 'to_nil' => lambda do |value|
408
+ value.to_s =~ %r/^nil$|^$/i ? nil : value.to_s
409
+ end,
410
+ 'to_s' => lambda do |value|
411
+ value.to_s
412
+ end,
413
+ }
414
+ end
415
+ end
416
+ send :extend, ClassMethods
417
+
418
+ module InstanceMethods
419
+ def value
420
+ self.class.casts[cast][self["value"]]
421
+ end
422
+ end
423
+ send :include, InstanceMethods
424
+ end
425
+ end
426
+ end