coderunner 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,727 @@
1
+ class CodeRunner
2
+
3
+ # In the next section are the implementations of all the standard Code Runner commands and some helper functions.
4
+
5
+ def self.set_runner_defaults(copts = {})
6
+ (DEFAULT_RUNNER_OPTIONS.keys - [:sys, :script_folder]).each do |var|
7
+ DEFAULT_RUNNER_OPTIONS[var] = copts[LONG_TO_SHORT[var]]
8
+ end
9
+ set_class_defaults(copts)
10
+ # ep DEFAULT_RUNNER_OPTIONS
11
+ end
12
+
13
+ def self.set_class_defaults(copts={})
14
+ (CLASS_OPTIONS.keys - []).each do |var|
15
+ CLASS_OPTIONS[var] = copts[LONG_TO_SHORT[var]]
16
+ set(var, CLASS_OPTIONS[var])
17
+ end
18
+ end
19
+
20
+ # List the available modlets for the given code (copts[:C] or -C on the command line).
21
+
22
+ def self.available_modlets(copts={})
23
+ process_command_options(copts)
24
+ puts "\nAvailable modlets for #{copts[:C]}:"
25
+ entries = []
26
+ begin
27
+ entries += Dir.entries(SCRIPT_FOLDER + "/code_modules/#{copts[:C]}/my_modlets")
28
+ rescue
29
+ end
30
+ begin
31
+ entries += Dir.entries(SCRIPT_FOLDER + "/code_modules/#{copts[:C]}/default_modlets")
32
+ rescue
33
+ end
34
+ entries.each do |modlet|
35
+ puts "\t" + File.basename(modlet, '.rb') unless ['.', '..', '.svn', '.directory'].include? modlet or modlet=~ /defaults/
36
+ end
37
+ end
38
+
39
+ # List the available defaults files for the given code (copts[:C] or -C on the command line).
40
+
41
+ def self.available_defaults_files(copts={})
42
+ process_command_options(copts)
43
+ puts "\nAvailable defaults files for #{copts[:C]}:"
44
+ entries = []
45
+ begin
46
+ entries += Dir.entries(SCRIPT_FOLDER + "/code_modules/#{copts[:C]}/my_defaults_files")
47
+ rescue
48
+ end
49
+ begin
50
+ entries += Dir.entries(SCRIPT_FOLDER + "/code_modules/#{copts[:C]}/defaults_files")
51
+ rescue
52
+ end
53
+ entries.each do |defaults_file|
54
+ puts "\t" + File.basename(defaults_file, '.rb').sub(/_defaults/, '') unless ['.', '..', '.svn', '.directory'].include? defaults_file
55
+ end
56
+ end
57
+
58
+ # Cancel the job with the given id. The user is asked interactively for confirmation and whether they would like to delete the folder for that job as well.
59
+
60
+ def self.cancel(id, copts={})
61
+ runner = fetch_runner(copts)
62
+ runner.cancel_job(id.to_i)
63
+ end
64
+
65
+ def self.continue_in_new_folder(folder, copts={})
66
+ runner=fetch_runner(copts)
67
+ options = {}
68
+ if copts[:f] or copts[:j]
69
+ options[:copy_ids] = runner.filtered_ids
70
+ end
71
+
72
+ runner.continue_in_new_folder(folder, options)
73
+ end
74
+
75
+ def self.delete(copts={})
76
+ runner = fetch_runner(copts)
77
+ runner.destroy
78
+ end
79
+
80
+ # def self.executable_name # :nodoc:
81
+ # ""
82
+ # end
83
+ #
84
+ # def self.rcp # :nodoc:
85
+ # @rcp ||= KitHash.new
86
+ # end
87
+ def self.netcdf_plot(netcdf_file, vars, indices, copts={})
88
+ process_command_options(copts)
89
+ begin
90
+ require "numru/netcdf"
91
+ rescue LoadError
92
+ eputs "Error: No Ruby NetCDF library (was it installed correctly?): data analysis for netcdf files not possible."
93
+ return
94
+ end
95
+ start_indices = indices.split(',').map{|idx| idx = idx.split(':')[0] if idx =~ /:/ ; eval(idx) || 0}
96
+ end_indices = indices.split(',').map{|idx| idx = idx.split(':')[1] if idx =~ /:/ ; eval(idx) || -1}
97
+
98
+ ep 'start_indices', start_indices, 'end_indices', end_indices
99
+ file = NumRu::NetCDF.open(netcdf_file)
100
+ to_plot = vars.split(',').map do |var|
101
+ ep 'var', var
102
+ [file.var(var).get('start'=> start_indices, 'end'=> end_indices).to_a.flatten]
103
+ end
104
+ ep 'to_plot', to_plot
105
+ kit = GraphKit.quick_create(*to_plot)
106
+ ep 'copts', copts
107
+ kit.instance_eval(copts[:w]) if copts[:w]
108
+ kit.gnuplot
109
+ STDIN.gets
110
+ kit.close
111
+ end
112
+
113
+
114
+
115
+ def self.print_queue_status(copts={})
116
+ begin
117
+ eputs queue_status
118
+ rescue => err
119
+ eputs "General queue status doesn't work on this system; showing queue status for this folder"
120
+ # p err
121
+ runner = fetch_runner(copts)
122
+ eputs runner.queue_status
123
+ end
124
+ end
125
+
126
+
127
+
128
+
129
+
130
+ def self.reference(class_or_method, copts={})
131
+ code_folders = Dir.recursive_entries(SCRIPT_FOLDER + '/code_modules').grep(/\/ri$/).map{|fold| ['-d', fold]}.flatten
132
+ # ep code_folders
133
+
134
+ # require 'rdoc/ri/driver'
135
+
136
+ # "
137
+ # op = @ri_count ? [] : (@ri_count = true; ['--no-use-cache'])
138
+ # trap(1){puts 'No help available'}
139
+ # at_exit{raise ""}
140
+ # p op
141
+ begin
142
+ eputs "Looking up #{class_or_method}"
143
+ RDoc::RI::Driver.run ['-d', SCRIPT_FOLDER + '/ri', class_or_method.to_s] + code_folders
144
+ rescue => err
145
+ eputs "Unknown class or method or no help available: #{err}"
146
+ end
147
+ # trap(1){}
148
+ end
149
+
150
+
151
+ def self.directory(id, copts={})
152
+ runner = fetch_runner(copts)
153
+ puts runner.run_list[id.to_i].directory
154
+ end
155
+ def self.film(copts={})
156
+ runner = fetch_runner(copts)
157
+ copts[:F][:graphkit_modify] = copts[:w]
158
+ runner.make_film_from_lists(copts[:G], copts[:g], copts[:F])
159
+ end
160
+
161
+ def self.generate_documentation(username = nil, copts = {})
162
+ ep 'username', username||=ENV['USER']
163
+
164
+ ####### Here we use the command line documentation to generate a fake ruby file that rdoc will understand.
165
+ File.open("class_methods_rdoc.rb", 'w') do |file|
166
+ file.puts <<EOF
167
+ class CodeRunner
168
+
169
+
170
+ #{COMMANDS_WITH_HELP.inject("") do |str, (long, short, nargs, comhelp, argnames, options)|
171
+ (puts "Please run this command in the coderunner trunk directory"; exit) unless Dir.pwd =~ /coderunner\/trunk$/
172
+ str << <<EOF2
173
+ # #{comhelp.gsub(/\n/, "\n # ")}
174
+ #
175
+ # Possible options:
176
+ #
177
+ #{options.inject("") do |str, opt|
178
+ longop, shortop, req, ophelp = COMMAND_LINE_FLAGS_WITH_HELP.find{|arr| arr[1] == "-" + opt.to_s}
179
+ str << " # :#{opt} --- #{ophelp.gsub(/\n/, "\n # ")}\n #\n"
180
+ end}
181
+
182
+ def self.#{long}(#{(argnames+[""]).join(",")}command_options={})
183
+ end
184
+
185
+ EOF2
186
+ end
187
+ }
188
+ end
189
+ EOF
190
+ end
191
+ # exit
192
+
193
+ system "rm -rf doc/"
194
+ system "rm -rf ri/"
195
+ raise 'Please set RDOC_COMMAND' unless ENV['RDOC_COMMAND']
196
+ system "#{ENV['RDOC_COMMAND']} --format=html -t 'CodeRunner Documentation' -m INDEX.rb INDEX.rb code_runner_version.rb gnuplot.rb graphkit_gnuplot.rb graphkit.rb gsl_tools.rb run_backwards_compatibility.rb feedback.rb run.rb fortran_namelist.rb graphs_and_films.rb class_methods_rdoc.rb instance_methods.rb"
197
+ system "#{ENV['RDOC_COMMAND']} -r --op ri INDEX.rb code_runner_version.rb gnuplot.rb graphkit_gnuplot.rb graphkit.rb gsl_tools.rb run_backwards_compatibility.rb feedback.rb run.rb fortran_namelist.rb graphs_and_films.rb class_methods_rdoc.rb instance_methods.rb"
198
+
199
+ exit if username == ""
200
+
201
+ string = "rsync -av --delete doc/ #{username},coderunner@web.sourceforge.net:htdocs/api_documentation/"
202
+
203
+ puts string
204
+ exec string
205
+
206
+ end
207
+
208
+ def self.start_launcher(refresh, max_queue, copts={})
209
+ raise "Raise refresh is #{refresh}: it must be >= 1" if refresh.to_i < 1
210
+ raise "Raise max_queue is #{max_queue}: it must be >= 5" if max_queue.to_i < 5
211
+ #raise "Launcher already running" if %x[ps -e -o cmd].split("\n").grep(/coderunner\s+launch/).size > 0
212
+ require 'thread'
213
+ tl = ENV['HOME'] + "/.coderunner_to_launch_#{ENV['CODE_RUNNER_LAUNCHER']}" #SCRIPT_FOLDER + '/to_launch'
214
+ exit unless Feedback.get_boolean( "Launch directory #{tl} already exists: it is suggested that you change the prefix by changing the environment variable CODE_RUNNER_LAUNCHER. Do you wish to continue (don't select yes unless you know what you are doing)?") if FileTest.exist? tl
215
+ # FileUtils.rm_r tl if FileTest.exist? tl
216
+ eputs "Starting launcher\n"
217
+ at_exit{FileUtils.rm_r tl}
218
+ FileUtils.makedirs tl
219
+ Thread.new{loop{`cp #{tl}/queue_status.txt #{tl}/queue_status2.txt; ps > #{tl}/queue_status.txt`; sleep 1}}
220
+
221
+ mutex = Mutex.new
222
+ processes= []
223
+
224
+ Thread.new do
225
+ loop do
226
+ Dir.entries(tl).each do |file|
227
+ next unless file =~ (/(^.*)\.stop/)
228
+ pid = $1
229
+ mutex.synchronize{Process.kill(pid); processes.delete pid}
230
+ end
231
+ sleep refresh.to_i
232
+ end
233
+ end
234
+
235
+ Dir.chdir(tl) do
236
+ ppid = $$
237
+ loop do
238
+ sleep refresh.to_i while processes.size >= max_queue.to_i
239
+ # processes = []
240
+ Dir.entries(tl).grep(/(^.*)\.start/).each do |file|
241
+ file =~ (/(^.*)\.start/)
242
+ id = $1
243
+ command = File.read file
244
+ pid = fork do
245
+ processes.each do |wpid|
246
+ sleep refresh.to_i while %x[ps -e -o pid,ppid].split("\n").grep(Regexp.new("^\\s*#{wpid}\\s+#{ppid}")).size > 0
247
+ end
248
+ exec(command)
249
+ end
250
+ `cp #{tl}/queue_status.txt #{tl}/queue_status2.txt; ps > #{tl}/queue_status.txt`
251
+ mutex.synchronize{processes.push pid}
252
+
253
+ File.open(id + '.pid', 'w'){|file| file.puts pid}
254
+ FileUtils.rm(file)
255
+
256
+ Thread.new{Process.wait pid; mutex.synchronize{processes.delete pid}}
257
+ end
258
+ # processes.each{|pid| Process.wait pid}
259
+ sleep refresh.to_i
260
+ end
261
+ end
262
+ end
263
+
264
+
265
+ def self.code_runner_execute(ruby_fragment, copts={})
266
+ #eval(ruby_fragment, GLOBAL_BINDING)
267
+ eval(ruby_fragment)
268
+ end
269
+ def self.execute(ruby_fragment, copts={})
270
+ eval(ruby_fragment, GLOBAL_BINDING)
271
+ #eval(ruby_fragment)
272
+ end
273
+ def self.load_file(files, copts={})
274
+ process_command_options(copts)
275
+ # begin
276
+ files.split(/\s*,\s*/).each do |file|
277
+ # p file
278
+ raise ArgumentError.new("#{file} is not a file.") unless File.file? file
279
+ load file
280
+ end
281
+ # rescue
282
+ # eval(files)
283
+ # end
284
+
285
+ end
286
+
287
+ def self.parameter_scan(parameter_scan_array_file, copts={})
288
+ parameter_scan_array = eval(File.read(parameter_scan_array_file))
289
+ # process_copts(copts)
290
+ runner = fetch_runner(copts)
291
+ skip = true unless copts[:k] == false
292
+ folder = Dir.pwd
293
+ Log.logf("self.parameter_scan")
294
+ # @@runners = {}
295
+ @@mutex = Mutex.new
296
+ # @runner = new(folder, code: copts[:C], modlet: copts[:m], version: copts[:v], executable: copts[:X])
297
+ @@psppipe = PPipe.new(parameter_scan_array.size + 2, true, controller_refresh: 0.5, redirect: false)
298
+ parameter_scan_array.each do |parameter_scan|
299
+ @@psppipe.fork do
300
+ runner.parameter_scan(parameter_scan, copts[:p][0], skip: skip, nprocs: copts[:n])
301
+ end
302
+ end
303
+ @@psppipe.finish
304
+ @@psppipe = nil
305
+ end
306
+ def self.plot_graph(copts = {})
307
+ # process_copts(copts)
308
+ runner = fetch_runner(copts)
309
+ string_to_eval = copts[:w]
310
+ #options = (options and options =~ /\S/) ? eval(options): {}
311
+ eputs 'Starting Graph'
312
+ kit = runner.graphkit_from_lists(copts[:G], copts[:g])
313
+ kit.gnuplot(eval: string_to_eval)
314
+ gets
315
+ kit.close
316
+ end
317
+ def self.readout(copts={})
318
+ # process_copts(copts)
319
+ runner = fetch_runner(copts)
320
+ puts runner.readout
321
+ end
322
+ def self.recheck(id, copts={})
323
+ # process_copts(copts)
324
+ runner = fetch_runner(copts)
325
+ runner.run_list[copts[:R]].recheck
326
+ runner.respond_to_requests
327
+ end
328
+ def self.code_command(string, copts = {})
329
+ process_command_options(copts)
330
+ copts[:no_update] = true
331
+ unless copts[:C]
332
+ if FileTest.exist? file=Dir.pwd + '/.code_runner_script_defaults.rb'
333
+ copts[:C] = eval(File.read(file))[:code]
334
+ elsif self.runner
335
+ copts[:C] = self.runner.code
336
+ end
337
+ end
338
+
339
+ run_class = setup_run_class(copts[:C], modlet: copts[:m])
340
+ run_class.class_eval(string)
341
+
342
+ # runner = fetch_runner(copts)
343
+ # runner.run_class.class_eval(string)
344
+ end
345
+ def self.run_command(string, copts={})
346
+ # process_copts(copts)
347
+ runner = fetch_runner(copts)
348
+
349
+ eputs "Calling run_commmand..."
350
+ # puts "Warning: Use large cache is on (-U or -u) -- no results will be saved" if runner.use_large_cache
351
+ ppipe = PPipe.new(runner.filtered_ids.size + 1, false) if copts[:M]
352
+ no_save = (runner.class == RemoteCodeRunner or copts[:y] =~ /no-save/)
353
+ # runner.generate_combined_ids
354
+ # ep runner.filtered_ids
355
+ runner.filtered_ids.each do |id|
356
+ run = runner.combined_run_list[id]
357
+
358
+ if no_save or run.is_phantom
359
+ if copts[:M]
360
+ fork{run.instance_eval(string)}
361
+ else
362
+ run.instance_eval(string)
363
+ end
364
+ else
365
+ if copts[:M]
366
+ pn = ppipe.fork do
367
+ Dir.chdir(run.directory) do
368
+ run.instance_eval(string);
369
+ run.save
370
+ run.write_results
371
+ end
372
+ ppipe.i_send(id, Marshal.dump(run), tp: 0)
373
+ end
374
+ else
375
+ Dir.chdir(run.directory){run.instance_eval(string); run.save; run.write_results}
376
+ end
377
+
378
+ end
379
+ end
380
+ unless no_save
381
+ (runner.filtered_ids.each{|id| runner.run_list[id] = Marshal.load(ppipe.w_recv(id).contents)};ppipe.finish) if copts[:M]
382
+ runner.save_large_cache
383
+ end
384
+
385
+ # Process.waitall
386
+ runner.respond_to_requests
387
+ end
388
+ def self.runner_eval(string, copts = {})
389
+ # process_copts(copts)
390
+ runner = fetch_runner(copts)
391
+
392
+ return_val = runner.instance_eval(string)
393
+
394
+ if copts[:Z]
395
+ Kernel.puts(server_dump(return_val))
396
+ else
397
+ return return_val
398
+ end
399
+
400
+ end
401
+ def self.scan(scan_string, copts={})
402
+ # process_copts(copts)
403
+ runner = fetch_runner(copts)
404
+ runner.simple_scan(scan_string, nprocs: copts[:n], version: copts[:v], skip: copts[:k], parameters: copts[:p][0])
405
+ end
406
+ def self.submit(copts = {})
407
+ # process_copts(copts)
408
+ runner = fetch_runner(copts)
409
+ # raise "something is already submitting" if FileTest.exist? "submitting"
410
+ runs = []
411
+ raise "Parameters must be an array of inspected hashes" unless copts[:p].kind_of? Array
412
+ Dir.chdir(copts[:Y]) do
413
+
414
+ copts[:p].push nil if copts[:p] == []
415
+ # ep copts[:p]; exit
416
+ copts[:p].each do |pars|
417
+ run = runner.run_class.new(runner)
418
+ # p pars
419
+ run.update_submission_parameters(pars)
420
+ runs.push run
421
+ end
422
+ # exit
423
+ end
424
+ runner.submit(runs, nprocs: copts[:n], version: copts[:v], skip: copts[:k], job_chain: copts[:J], no_update_before_submit: copts[:no_update_before_submit])
425
+ end
426
+ def self.resubmit(copts = {})
427
+ # process_copts(copts)
428
+ runner = fetch_runner(copts)
429
+ # raise "something is already submitting" if FileTest.exist? "submitting"
430
+ runs = []
431
+ raise "Parameters must be an array of inspected hashes" unless copts[:p].kind_of? Array
432
+ Dir.chdir(copts[:Y]) do
433
+ runs = runner.filtered_ids.map do |id|
434
+ eputs id
435
+ run = runner.run_list[id].dup
436
+ if copts[:smart_resubmit_name]
437
+ eputs "Smart name"
438
+ run.set(:naming_pars, [:resubmit_id])
439
+ run.resubmit_id = run.id
440
+ end
441
+ run.update_submission_parameters(copts[:p][0], false)
442
+ run.run_name = nil unless copts[:rerun]
443
+ run
444
+ end
445
+ end
446
+ #throw(:here)
447
+
448
+ runner.submit(runs, nprocs: copts[:n], version: copts[:v], skip: copts[:k], job_chain: copts[:J], no_update_before_submit: copts[:no_update_before_submit], replace_existing: copts[:replace_existing], smart_resubmit_name: copts[:smart_resubmit_name], rerun: copts[:rerun])
449
+ end
450
+
451
+ # This method allows the straightforward submission of a single command using the batch queue on any system.
452
+ def self.submit_command(jid, comm, copts={})
453
+ process_command_options(copts)
454
+ submitter = Object.new
455
+ submitter.instance_variable_set(:@command, comm)
456
+ submitter.instance_variable_set(:@jid, jid)
457
+ submitter.instance_variable_set(:@nprocs, copts[:n])
458
+ submitter.instance_variable_set(:@wall_mins, copts[:W])
459
+ submitter.instance_variable_set(:@project, copts[:P])
460
+ class << submitter
461
+ include CodeRunner::SYSTEM_MODULE
462
+ def executable_name
463
+ 'custom'
464
+ end
465
+ def job_identifier
466
+ @jid
467
+ end
468
+ def run_command
469
+ @command
470
+ end
471
+ end
472
+ submitter.execute
473
+ end
474
+
475
+
476
+
477
+ def self.readout(copts={})
478
+ runner = fetch_runner(copts)
479
+ runner.readout
480
+ end
481
+ def self.show_values_of(expression, copts={})
482
+ runner = fetch_runner(copts)
483
+ p runner.filtered_ids.map{|id| runner.run_list[id].instance_eval(expression)}.uniq.sort
484
+ end
485
+ def self.status_with_comments(copts={})
486
+ copts[:with_comments] = true
487
+ status(copts)
488
+ end
489
+ def self.status(copts={})
490
+ # process_copts(copts)
491
+ runner = fetch_runner(copts)
492
+ runner.print_out(0, with_comments: copts[:with_comments]) unless copts[:interactive_start] or copts[:Z] or copts[:no_print_out]
493
+ end
494
+ def self.status_loop(copts={})
495
+ # process_copts(copts)
496
+ runner = fetch_runner(copts)
497
+ runner.print_out(0, with_comments: copts[:with_comments]) unless copts[:interactive_start] or copts[:Z] or copts[:no_print_out]
498
+ break_out = false
499
+ loop do
500
+ old_trap = trap(2){eputs " Terminating loop, please wait..."; break_out = true}
501
+ runner.use_large_cache = true
502
+ runner.update(false)
503
+ (trap(2, old_trap); break) if break_out
504
+ runner.recheck_filtered_runs(false)
505
+ runner.print_out(nil, with_comments: copts[:with_comments])
506
+ trap(2, old_trap)
507
+ break if break_out
508
+ break if not runner.run_list.values.find do |r|
509
+ not [:Complete, :Failed].include? r.status
510
+ end
511
+ #ep "sleep"
512
+ sleep 3
513
+ #ep "end sleep"
514
+ end
515
+ end
516
+ def self.write_graph(name, copts={})
517
+ # process_copts(copts)
518
+ runner = fetch_runner(copts)
519
+ eputs 'Starting Graph'
520
+ kit = runner.graphkit_from_lists(copts[:G], copts[:g])
521
+ options = copts[:w]
522
+ options = (options and options =~ /\S/) ? eval(options): {}
523
+ name = nil unless name =~ /\S/
524
+ max = 0
525
+ name.sub!(/^\~/, ENV['HOME']) if name
526
+ if name and name =~ /%d\./
527
+ regex = Regexp.new(Regexp.escape(File.basename(name)).sub(/%d/, '(?<number>\d+)'))
528
+ Dir.entries(File.dirname(name)).join("\n").scan(regex) do
529
+ max = [max, $~[:number].to_i].max
530
+ end
531
+ name = name.sub(/%d/, (max + 1).to_s)
532
+ end
533
+ raise "kit doesn't have a file_name and no filename specified; can't write graph" unless name or (kit.file_name.class == String and kit.file_name =~ /\S/)
534
+ Dir.chdir(COMMAND_FOLDER){kit.gnuplot_write((name or kit.file_name), options)}
535
+ end
536
+ def self.read_default_command_options(copts)
537
+ DEFAULT_COMMAND_OPTIONS.each do |key, value|
538
+ copts[key] ||= value
539
+ end
540
+ end
541
+ def self.process_command_options(copts)
542
+ if copts[:true]
543
+ copts[:true].to_s.split(//).each do |letter|
544
+ copts[letter.to_sym] = true
545
+ end
546
+ end
547
+ if copts[:false]
548
+ copts[:false].to_s.split(//).each do |letter|
549
+ copts[letter.to_sym] = false
550
+ end
551
+ end
552
+
553
+ read_default_command_options(copts)
554
+ copts.each do |key, value|
555
+ copts[LONG_TO_SHORT[key]] = value if LONG_TO_SHORT[key]
556
+ end
557
+
558
+
559
+ if copts[:j] # j can be a number '65' or list of numbers '65,43,382'
560
+ copts[:f]= "#{eval("[#{copts[:j]}]").inspect}.include? id"
561
+ end
562
+ if copts[:z]
563
+ Log.log_file = Dir.pwd + '/.cr_logfile.txt'
564
+ Log.clean_up
565
+ else
566
+ Log.log_file = nil
567
+ end
568
+ copts[:F] = (copts[:F].class == Hash ? copts[:F] : (copts[:F].class == String and copts[:F] =~ /\A\{.*\}\Z/) ? eval(copts[:F]) : {})
569
+ copts[:G]= [copts[:G]] if copts[:G].kind_of? String
570
+ copts[:g]= [copts[:g]] if copts[:g].kind_of? String
571
+ # if copts[:p] and copts[:p].class == String # should be a hash or an inspected hash
572
+ # copts[:p] = eval(copts[:p])
573
+ # end
574
+ copts[:p] = [copts[:p]].compact unless copts[:p].class == Array
575
+ #for i in 0...copts[:p].size
576
+
577
+ copts[:Y] ||= DEFAULT_COMMAND_OPTIONS[:Y] if DEFAULT_COMMAND_OPTIONS[:Y]
578
+ if copts[:Y] and copts[:Y] =~ /:/
579
+ set_class_defaults(copts)
580
+ copts[:running_remotely] = true
581
+ else
582
+ copts[:Y].gsub!(/~/, ENV['HOME']) if copts[:Y]
583
+ Dir.chdir((copts[:Y] or Dir.pwd)) do
584
+ set_runner_defaults(copts)
585
+ # ep DEFAULT_RUNNER_OPTIONS
586
+ end
587
+ end
588
+ # ep Log.log_file
589
+ #copts[:code_copts].each{|k,v| CODE_OPTIONS[k] = v} if copts[:code_copts]
590
+ copts.keys.map{|k| k.to_s}.grep(/_options$/).map{|k| k.to_sym}.each do |k|
591
+ CODE_OPTIONS[k.to_s.sub('_options','').to_sym] = copts[k]
592
+ end
593
+
594
+ end
595
+
596
+ CODE_OPTIONS={}
597
+
598
+ # Retrieve the runner with the folder (and possibly server) given in copts[:Y]. If no runner has been loaded for that folder, load one.
599
+
600
+ def self.fetch_runner(copts={})
601
+ # ep copts
602
+ # If copts(:Y) is an array of locations, return a merged runner of those locations
603
+ if copts[:Y].kind_of? Array
604
+ runners = copts[:Y].map do |location|
605
+ new_copts = copts.dup.absorb(Y: location)
606
+ fetch_runner(new_copts)
607
+ end
608
+ return Merged.new(*runners)
609
+ end
610
+ process_command_options(copts)
611
+ # ep copts
612
+ @runners ||= {}
613
+ runner = nil
614
+ if copts[:Y] and copts[:Y] =~ /:/
615
+ copts_r = copts.dup
616
+ host, folder = copts[:Y].split(':')
617
+ copts_r[:Y] = nil
618
+ copts[:Y] = nil
619
+ unless @runners[[host, folder]]
620
+ runner = @runners[[host, folder]] = RemoteCodeRunner.new(host, folder, copts)
621
+ (eputs 'Updating remote...'; runner.update) unless (copts[:g] and (copts[:g].kind_of? String or copts[:g].size > 0)) or copts[:no_update] or copts[:cache]
622
+ else
623
+ runner = @runners[[host, folder]]
624
+ end
625
+ runner.process_copts(copts)
626
+ else
627
+
628
+ copts[:Y] ||= Dir.pwd
629
+ Dir.chdir((copts[:Y] or Dir.pwd)) do
630
+ unless @runners[copts[:Y]]
631
+ runner = @runners[copts[:Y]] = CodeRunner.new(Dir.pwd, code: copts[:C], modlet: copts[:m], version: copts[:v], executable: copts[:X], defaults_file: copts[:D])
632
+ runner.update unless copts[:no_update]
633
+ else
634
+ runner = @runners[copts[:Y]]
635
+ end
636
+ # p 'reading defaults', @r.conditions, DEFAULT_RUNNER_OPTIONS
637
+ runner.read_defaults
638
+ # p 'read defaults', @r.conditions
639
+
640
+ end #Dir.chdir
641
+ end
642
+ # ep copts
643
+ return runner
644
+ # @r.read_defaults
645
+ end
646
+ def self.update_runners
647
+ @runners ||= {}
648
+ @runners.each{|runner| runner.update}
649
+ end
650
+
651
+
652
+ def self.runner
653
+ @runners.values[0]
654
+ end
655
+
656
+
657
+ def self.manual(copts={})
658
+ help = <<EOF
659
+
660
+
661
+ -------------CodeRunner Manual---------------
662
+
663
+ Written by Edmund Highcock (2009)
664
+
665
+ NAME
666
+
667
+ coderunner
668
+
669
+
670
+ SYNOPSIS
671
+
672
+ coderunner <command> [arguments] [options]
673
+
674
+
675
+ DESCRIPTION
676
+
677
+ CodeRunner is a framework for the running and analysis of large simulations. It is a Ruby package and can be used to write Ruby scripts. However it also has a powerful command line interface. The aim is to be able to submit simulations, analyse data and plot graphs all using simple commands. This manual is a quick reference. For a more tutorial style introduction to CodeRunner go to
678
+ http://coderunner.sourceforge.net
679
+
680
+ This help page documents the commandline interface. For API documentation see
681
+ http://coderunner.sourceforge.net/api_documentation
682
+
683
+ As is standard, <> indicates a parameter to be supplied, and [] indicates an option, unless otherwise stated.
684
+
685
+ EXAMPLES
686
+
687
+ $ coderunner sub -p '{height: 34.2, width: 221}' -n 24x4 -W 300
688
+
689
+ $ coderunner can 34 -U
690
+
691
+ $ coderunner plot -G 'height:width;{};depth==2.4 and status == :Completed;height'
692
+
693
+ $ coderunner st -ul
694
+
695
+ $ coderunner rc 'p status' -U
696
+
697
+ COMMANDS
698
+
699
+ Either the long or the short form of the command may be used, except in interactive mode, where only short form can be used.
700
+
701
+ Long(Short) <Arguments> (Meaningful Options)
702
+ ---------------------------------------------
703
+
704
+ #{(COMMANDS_WITH_HELP.sort_by{|arr| arr[0]}.map do |arr|
705
+ sprintf(" %s %s(%s) \n %s", "#{arr[0]}(#{arr[1]})", arr[4].map{|arg| "<#{arg}>"}.join(' ').sub(/(.)$/, '\1 '), arr[5].map{|op| op.to_s}.join(','), arr[3], )
706
+ end).join("\n\n")}
707
+
708
+ OPTIONS
709
+
710
+ #{((COMMAND_LINE_FLAGS_WITH_HELP + LONG_COMMAND_LINE_OPTIONS).map do |arr|
711
+ sprintf(" %-15s %-2s\n %s", arr[0], arr[1], arr[3])
712
+ end).join("\n\n")
713
+ }
714
+
715
+ EOF
716
+ puts help.gsub(/(.{63,73} |.{73})/){"#$1\\\n "}
717
+ end
718
+
719
+
720
+
721
+
722
+
723
+ end
724
+
725
+
726
+
727
+