coderunner 0.11.0

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.
@@ -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
+