openstudio-workflow 1.0.0.pat1 → 1.0.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +16 -68
  4. data/Rakefile +9 -9
  5. data/bin/openstudio_cli +786 -0
  6. data/lib/openstudio/workflow/adapters/input/local.rb +97 -0
  7. data/lib/openstudio/workflow/adapters/output/local.rb +90 -0
  8. data/lib/openstudio/workflow/adapters/output/socket.rb +70 -0
  9. data/lib/openstudio/workflow/{jobs/run_preflight/run_preflight.rb → adapters/output/web.rb} +37 -19
  10. data/lib/openstudio/workflow/{adapter.rb → adapters/output_adapter.rb} +53 -51
  11. data/lib/openstudio/workflow/job.rb +22 -0
  12. data/lib/openstudio/workflow/jobs/{run_energyplus → resources}/monthly_report.idf +0 -0
  13. data/lib/openstudio/workflow/jobs/run_energyplus.rb +49 -0
  14. data/lib/openstudio/workflow/jobs/run_ep_measures.rb +55 -0
  15. data/lib/openstudio/workflow/jobs/run_initialization.rb +136 -0
  16. data/lib/openstudio/workflow/jobs/run_os_measures.rb +59 -0
  17. data/lib/openstudio/workflow/jobs/run_postprocess.rb +53 -0
  18. data/lib/openstudio/workflow/jobs/run_preprocess.rb +81 -0
  19. data/lib/openstudio/workflow/jobs/run_reporting_measures.rb +86 -0
  20. data/lib/openstudio/workflow/jobs/run_translation.rb +49 -0
  21. data/lib/openstudio/workflow/multi_delegator.rb +1 -3
  22. data/lib/openstudio/workflow/registry.rb +137 -0
  23. data/lib/openstudio/workflow/run.rb +182 -221
  24. data/lib/openstudio/workflow/time_logger.rb +1 -1
  25. data/lib/openstudio/workflow/util/energyplus.rb +564 -0
  26. data/lib/openstudio/workflow/util/io.rb +33 -0
  27. data/lib/openstudio/workflow/util/measure.rb +520 -0
  28. data/lib/openstudio/workflow/util/model.rb +100 -0
  29. data/lib/openstudio/workflow/util/post_process.rb +177 -0
  30. data/lib/openstudio/workflow/util/weather_file.rb +108 -0
  31. data/lib/openstudio/workflow/util.rb +14 -0
  32. data/lib/openstudio/workflow/version.rb +1 -1
  33. data/lib/openstudio/workflow_json.rb +399 -0
  34. data/lib/openstudio/workflow_runner.rb +213 -0
  35. data/lib/openstudio-workflow.rb +13 -118
  36. metadata +45 -85
  37. data/lib/openstudio/extended_runner.rb +0 -105
  38. data/lib/openstudio/workflow/adapters/local.rb +0 -101
  39. data/lib/openstudio/workflow/adapters/mongo.rb +0 -227
  40. data/lib/openstudio/workflow/jobs/lib/apply_measures.rb +0 -253
  41. data/lib/openstudio/workflow/jobs/run_energyplus/run_energyplus.rb +0 -314
  42. data/lib/openstudio/workflow/jobs/run_openstudio/run_openstudio.rb +0 -230
  43. data/lib/openstudio/workflow/jobs/run_postprocess/run_postprocess.rb +0 -110
  44. data/lib/openstudio/workflow/jobs/run_reporting_measures/run_reporting_measures.rb +0 -471
  45. data/lib/openstudio/workflow/jobs/run_runmanager/run_runmanager.rb +0 -247
  46. data/lib/openstudio/workflow/jobs/run_xml/run_xml.rb +0 -279
@@ -0,0 +1,786 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ######################################################################
4
+ # Copyright (c) 2008-2016, Alliance for Sustainable Energy.
5
+ # All rights reserved.
6
+ #
7
+ # This library is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU Lesser General Public
9
+ # License as published by the Free Software Foundation; either
10
+ # version 2.1 of the License, or (at your option) any later version.
11
+ #
12
+ # This library is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public
18
+ # License along with this library; if not, write to the Free Software
19
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ ######################################################################
21
+
22
+ Signal.trap('INT') { abort }
23
+
24
+ require 'openstudio-workflow'
25
+ require 'optparse'
26
+ require 'irb'
27
+ require 'json'
28
+ include OpenStudio::Workflow::Util::IO
29
+ include OpenStudio::Workflow::Util::Directory
30
+
31
+ $logger = Logger.new(STDOUT)
32
+ $logger.level = Logger::WARN
33
+
34
+ # This is the code chunk to allow for an embedded IRB shell. From Jason Roelofs, found on StackOverflow
35
+ module IRB # :nodoc:
36
+ def self.start_session(binding)
37
+ unless @__initialized
38
+ args = ARGV
39
+ ARGV.replace(ARGV.dup)
40
+ IRB.setup(nil)
41
+ ARGV.replace(args)
42
+ @__initialized = true
43
+ end
44
+
45
+ workspace = WorkSpace.new(binding)
46
+
47
+ irb = Irb.new(workspace)
48
+
49
+ @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
50
+ @CONF[:MAIN_CONTEXT] = irb.context
51
+
52
+ catch(:IRB_EXIT) do
53
+ irb.eval_input
54
+ end
55
+ end
56
+ end
57
+
58
+ # This is the save puts to use to catch EPIPE. Uses `puts` on the given IO object and safely ignores any Errno::EPIPE
59
+ #
60
+ # @param [String] message Message to output
61
+ # @param [Hash] opts Options hash
62
+ #
63
+ def safe_puts(message = nil, opts = nil)
64
+ message ||= ''
65
+ opts = {
66
+ io: $stdout,
67
+ printer: :puts
68
+ }.merge(opts || {})
69
+
70
+ begin
71
+ opts[:io].send(opts[:printer], message)
72
+ rescue Errno::EPIPE
73
+ # This is what makes this a `safe` puts
74
+ return
75
+ end
76
+ end
77
+
78
+ # This is a convenience method that properly handles duping the originally argv array so that it is not destroyed. This
79
+ # method will also automatically detect "-h" and "--help" and print help. And if any invalid options are detected, the
80
+ # help will be printed, as well
81
+ #
82
+ # @param [Object, nil] opts An instance of OptionParse to parse against, defaults to a new OptionParse instance
83
+ # @param [Array, nil] argv The argv input to be parsed, defaults to $argv
84
+ # @return[Array, nil] If this method returns `nil`, then you should assume that help was printed and parsing failed
85
+ #
86
+ def parse_options(opts = nil, argv = nil)
87
+ # Creating a shallow copy of the arguments so the OptionParser
88
+ # doesn't destroy the originals.
89
+ argv ||= $argv.dup
90
+
91
+ # Default opts to a blank optionparser if none is given
92
+ opts ||= OptionParser.new
93
+
94
+ # Add the help option, which must be on every command.
95
+ opts.on_tail('-h', '--help', 'Print this help') do
96
+ safe_puts(opts.help)
97
+ return nil
98
+ end
99
+
100
+ opts.parse!(argv)
101
+ return argv
102
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument
103
+ raise "Error: Invalid CLI option, #{opts.help.chomp}"
104
+ end
105
+
106
+ # This method will split the argv given into three parts: the flags to this command, the subcommand, and the flags to
107
+ # the subcommand. For example:
108
+ # -v status -h -v
109
+ # The above would yield 3 parts:
110
+ # ["-v"]
111
+ # "status"
112
+ # ["-h", "-v"]
113
+ # These parts are useful because the first is a list of arguments given to the current command, the second is a
114
+ # subcommand, and the third are the commands given to the subcommand
115
+ #
116
+ # @param [Array] argv The input to be split
117
+ # @return [Array] The split command as [main arguments, sub command, sub command arguments]
118
+ #
119
+ def split_main_and_subcommand(argv)
120
+ # Initialize return variables
121
+ main_args = nil
122
+ sub_command = nil
123
+ sub_args = []
124
+
125
+ # We split the arguments into two: One set containing any flags before a word, and then the rest. The rest are what
126
+ # get actually sent on to the subcommand
127
+ argv.each_index do |i|
128
+ unless argv[i].start_with?('-')
129
+ # We found the beginning of the sub command. Split the
130
+ # args up.
131
+ main_args = argv[0, i]
132
+ sub_command = argv[i]
133
+ sub_args = argv[i + 1, argv.length - i + 1]
134
+
135
+ # Break so we don't find the next non flag and shift our main args
136
+ break
137
+ end
138
+ end
139
+
140
+ # Handle the case that argv was empty or didn't contain any subcommand
141
+ main_args = argv.dup if main_args.nil?
142
+
143
+ [main_args, sub_command, sub_args]
144
+ end
145
+
146
+ # This CLI class processes the input args and invokes the proper command class
147
+ class CLI
148
+ # This constant maps subcommands to classes in this CLI and stores meta-data on them
149
+ COMMAND_LIST = {
150
+ run: [proc { ::Run }, { primary: true, working: true }],
151
+ apply_measure: [proc { ::ApplyMeasure }, { primary: true, working: false }],
152
+ gem_list: [proc { ::GemList }, { primary: true, working: true }],
153
+ gem_install: [proc { ::InstallGem }, { primary: false, working: true }],
154
+ measure: [proc { ::Measure }, { primary: true, working: false }],
155
+ e: [proc { ::ExecuteRubyScript }, { primary: false, working: true }],
156
+ i: [proc { ::InteractiveRubyShell }, { primary: false, working: true }],
157
+ openstudio_version: [proc { ::OpenStudioVersion }, { primary: true, working: true }],
158
+ energyplus_version: [proc { ::EnergyPlusVersion }, { primary: true, working: true }],
159
+ ruby_version: [proc { ::RubyVersion }, { primary: false, working: true }],
160
+ list_commands: [proc { ::ListCommands }, { primary: true, working: true }]
161
+ }.freeze
162
+
163
+ # This method instantiates the global variables $main_args, $sub_command, and $sub_args
164
+ #
165
+ # @param [Array] argv The arguments passed through the CLI
166
+ # @return [Object] An instance of the CLI class with initialized globals
167
+ #
168
+ def initialize(argv)
169
+ $main_args, $sub_command, $sub_args = split_main_and_subcommand(argv)
170
+
171
+ $logger.info("CLI Parsed Inputs: #{$main_args.inspect} #{$sub_command.inspect} #{$sub_args.inspect}")
172
+ end
173
+
174
+ # Checks to see if it should print the main help, and if not parses the subcommand into a class and executes it
175
+ def execute
176
+ $logger.debug "Main arguments are #{$main_args}"
177
+ $logger.debug "Sub-command is #{$sub_command}"
178
+ $logger.debug "Sub-arguments are #{$sub_args}"
179
+ if $main_args.include?('-h') || $main_args.include?('--help')
180
+ # Help is next in short-circuiting everything. Print
181
+ # the help and exit.
182
+ help
183
+ return 0
184
+ end
185
+
186
+ # If we reached this far then we must have a subcommand. If not,
187
+ # then we also just print the help and exit.
188
+ command_plugin = nil
189
+ if $sub_command
190
+ command_plugin = COMMAND_LIST[$sub_command.to_sym]
191
+ end
192
+
193
+ if !command_plugin || !$sub_command
194
+ help
195
+ return 1
196
+ end
197
+
198
+ command_class = command_plugin[0].call
199
+ $logger.debug("Invoking command class: #{command_class} #{$sub_args.inspect}")
200
+
201
+ # Initialize and execute the command class, returning the exit status.
202
+ result = 0
203
+ begin
204
+ result = command_class.new.execute($sub_args)
205
+ rescue Interrupt
206
+ $logger.error '?'
207
+ result = 1
208
+ end
209
+
210
+ result = 0 unless result.is_a?(Fixnum)
211
+ result
212
+ end
213
+
214
+ # Prints out the help text for the CLI
215
+ #
216
+ # @param [Boolean] list_all If set to true, the help prints all commands, however it otherwise only prints those
217
+ # marked as primary in #COMMAND_LIST
218
+ # @return [void]
219
+ # @see #COMMAND_LIST #::ListCommands
220
+ #
221
+ def help(list_all = false)
222
+ opts = OptionParser.new do |o|
223
+ o.banner = 'Usage: openstudio_cli [options] <command> [<args>]'
224
+ o.separator ''
225
+ o.on('-h', '--help', 'Print this help.')
226
+ o.on('--verbose', 'Print the full log to STDOUT')
227
+ o.on('--gem_path PATH', 'Path to use for installing gems to and loading gems from')
228
+ o.separator ''
229
+ o.separator 'Common commands:'
230
+
231
+ # Add the available subcommands as separators in order to print them
232
+ # out as well.
233
+ commands = {}
234
+ longest = 0
235
+ COMMAND_LIST.each do |key, data|
236
+ # Skip non-primary commands. These only show up in extended
237
+ # help output.
238
+ next unless list_all || data[1][:primary]
239
+
240
+ key = key.to_s
241
+ klass = data[0].call
242
+ commands[key] = klass.synopsis
243
+ longest = key.length if key.length > longest
244
+ end
245
+
246
+ commands.keys.sort.each do |key|
247
+ o.separator " #{key.ljust(longest + 2)} #{commands[key]}"
248
+ end
249
+
250
+ o.separator ''
251
+ o.separator 'For help on any individual command run `openstudio_cli COMMAND -h`'
252
+ unless list_all
253
+ o.separator ''
254
+ o.separator 'Additional subcommands are available, but are either more advanced'
255
+ o.separator 'or not commonly used. To see all subcommands, run the command'
256
+ o.separator '`openstudio_cli list_commands`.'
257
+ end
258
+ end
259
+
260
+ safe_puts opts.help
261
+ end
262
+ end
263
+
264
+ # Class to execute part or all of an OSW workflow
265
+ class Run
266
+ # Provides text for the main help functionality
267
+ def self.synopsis
268
+ 'Executes an OpenStudio Workflow file'
269
+ end
270
+
271
+ # Executes the standard, or one of two custom, workflows using the workflow-gem
272
+ #
273
+ # @param [Array] sub_argv Options passed to the run subcommand from the user input
274
+ # @return [Fixnum] Return status
275
+ #
276
+ def execute(sub_argv)
277
+ options = {}
278
+ options[:debug] = false
279
+ options[:no_simulation] = false
280
+ options[:workflow] = './workflow.osw'
281
+ options[:post_process] = false
282
+
283
+ opts = OptionParser.new do |o|
284
+ o.banner = 'Usage: openstudio_cli run [options]'
285
+ o.separator ''
286
+ o.separator 'Options:'
287
+ o.separator ''
288
+
289
+ o.on('-w', '--workflow [FILE]', 'Specify the FILE path to the workflow to run') do |workflow|
290
+ options[:workflow] = workflow
291
+ end
292
+ o.on('-m', '--measures_only', 'Only run the OpenStudio and EnergyPlus measures') do
293
+ options[:no_simulation] = true
294
+ end
295
+ o.on('-p', '--postprocess_only', 'Only run the reporting measures') do
296
+ options[:post_process] = true
297
+ end
298
+ o.on('--debug', 'Includes additional outputs for debugging failing workflows and does not clean up the run directory') do |f|
299
+ options[:debug] = f
300
+ end
301
+ end
302
+
303
+ # Parse the options
304
+ argv = parse_options(opts, sub_argv)
305
+ return 0 if argv.nil?
306
+ unless argv == []
307
+ $logger.error 'Extra arguments passed to the run command. Please refer to the help documentation.'
308
+ return 1
309
+ end
310
+ $logger.debug("Run command: #{argv.inspect} #{options.inspect}")
311
+
312
+ if options[:post_process] && options[:no_simulation]
313
+ $logger.error 'Both the -m and -p flags were set, which is an invalid combination.'
314
+ return 1
315
+ end
316
+
317
+ osw_path = options[:workflow]
318
+ osw_path = File.absolute_path(File.join(Dir.pwd, osw_path)) unless Pathname.new(osw_path).absolute?
319
+ $logger.debug "Path for the OSW: #{osw_path}"
320
+
321
+ adapter_options = { workflow_filename: File.basename(osw_path) }
322
+ input_adapter = OpenStudio::Workflow.load_input_adapter 'local', adapter_options
323
+ adapter_options[:output_directory] = input_adapter.run_directory File.dirname(osw_path)
324
+ output_adapter = OpenStudio::Workflow.load_output_adapter 'local', adapter_options
325
+ run_options = options[:debug] ? { debug: true, cleanup: false } : {}
326
+ if options[:no_simulation]
327
+ run_options[:jobs] = [
328
+ { state: :queued, next_state: :initialization, options: { initial: true } },
329
+ { state: :initialization, next_state: :os_measures, job: :RunInitialization,
330
+ file: 'openstudio/workflow/jobs/run_initialization.rb', options: {} },
331
+ { state: :os_measures, next_state: :translator, job: :RunOpenStudioMeasures,
332
+ file: 'openstudio/workflow/jobs/run_os_measures.rb', options: {} },
333
+ { state: :translator, next_state: :ep_measures, job: :RunTranslation,
334
+ file: 'openstudio/workflow/jobs/run_translation.rb', options: {} },
335
+ { state: :ep_measures, next_state: :finished, job: :RunEnergyPlusMeasures,
336
+ file: 'openstudio/workflow/jobs/run_ep_measures.rb', options: {} },
337
+ { state: :finished },
338
+ { state: :errored }
339
+ ]
340
+ elsif options[:post_process]
341
+ run_options[:jobs] = [
342
+ { state: :queued, next_state: :initialization, options: { initial: true } },
343
+ { state: :initialization, next_state: :reporting_measures, job: :RunInitialization,
344
+ file: 'openstudio/workflow/jobs/run_initialization.rb', options: {} },
345
+ { state: :reporting_measures, next_state: :postprocess, job: :RunReportingMeasures,
346
+ file: 'openstudio/workflow/jobs/run_reporting_measures.rb', options: {} },
347
+ { state: :postprocess, next_state: :finished, job: :RunPostprocess,
348
+ file: 'openstudio/workflow/jobs/run_postprocess.rb', options: {} },
349
+ { state: :finished },
350
+ { state: :errored }
351
+ ]
352
+ run_options[:load_simulation_osm] = true
353
+ run_options[:load_simulation_idf] = true
354
+ run_options[:load_simulation_sql] = true
355
+ run_options[:preserve_run_dir] = true
356
+ end
357
+ k = OpenStudio::Workflow::Run.new input_adapter, output_adapter, File.dirname(osw_path), run_options
358
+ k.run
359
+
360
+ 0
361
+ end
362
+ end
363
+
364
+ # Class to apply an OpenStudio, EnergyPlus, or Reporting measure
365
+ # @abstract
366
+ class ApplyMeasure
367
+ # Provides text for the main help functionality
368
+ def self.synopsis
369
+ 'Applies an OpenStudio, EnergyPlus, or Reporting measure'
370
+ end
371
+
372
+ # Executes a single measure using an undefined interface
373
+ #
374
+ # @param [Array] sub_argv Options passed to the apply_measures subcommand from the user input
375
+ # @return [Fixnum] Return status
376
+ # @abstract
377
+ #
378
+ def execute(sub_argv)
379
+ # options = {}
380
+ # options[:debug] = false
381
+
382
+ # opts = OptionParser.new do |o|
383
+ # o.banner = 'Usage: openstudio_cli apply_measure'
384
+ # o.separator ''
385
+ # o.separator 'Options:'
386
+ # o.separator ''
387
+ # end
388
+
389
+ $logger.error 'This interface has yet to be defined.'
390
+
391
+ # Parse the options
392
+ argv = parse_options(opts, sub_argv)
393
+ return 1 unless argv
394
+ # $logger.debug("ApplyMeasure command: #{argv.inspect} #{options.inspect}")
395
+
396
+ 1
397
+ end
398
+ end
399
+
400
+ # Class to list the gems used by the CLI
401
+ class GemList
402
+ # Provides text for the main help functionality
403
+ def self.synopsis
404
+ 'Lists the set gems available to openstudio_cli'
405
+ end
406
+
407
+ # Alters the environment variable used to define the gem install location
408
+ #
409
+ # @param [Array] sub_argv Options passed to the gem_install subcommand from the user input
410
+ # @return [Fixnum] Return status
411
+ #
412
+ def execute(sub_argv)
413
+ require 'rubygems'
414
+ require 'rubygems/gem_runner'
415
+
416
+ # Parse the options
417
+ opts = OptionParser.new do |o|
418
+ o.banner = 'Usage: openstudio_cli gem_list'
419
+ end
420
+ argv = parse_options(opts, sub_argv)
421
+ unless argv == []
422
+ $logger.error 'Extra arguments passed to the gem_list command. Please refer to the help documentation.'
423
+ return 1
424
+ end
425
+
426
+ begin
427
+ Gem::GemRunner.new.run ['list']
428
+ rescue => e
429
+ $logger.error "Error listing gems: #{e.message} in #{e.backtrace.join("\n")}"
430
+ exit e.exit_code
431
+ end
432
+
433
+ 0
434
+ end
435
+ end
436
+
437
+ # Class to install gems using the RubyGems functionality
438
+ class InstallGem
439
+ # Provides text for the main help functionality
440
+ def self.synopsis
441
+ 'Installs a Gem using the embedded ruby'
442
+ end
443
+
444
+ # Executes the RubyGems gem install process, using the RubyGems options
445
+ #
446
+ # @param [Array] sub_argv Options passed to the gem_install subcommand from the user input
447
+ # @return [Fixnum] Return status
448
+ #
449
+ def execute(sub_argv)
450
+ require 'rubygems'
451
+ require 'rubygems/gem_runner'
452
+
453
+ # Parse the options
454
+ argv = sub_argv.unshift('install')
455
+ if argv.include? '--install-dir'
456
+ $logger.error 'The rubygems option --install-dir is not supported. Please use the --gem_path option'
457
+ return 1
458
+ else
459
+ argv.push '--install-dir'
460
+ argv.push ENV['GEM_PATH']
461
+ end
462
+ $logger.debug "GemInstall command: #{argv.inspect}"
463
+ $logger.debug "Invoking the GemRunner with argv: #{argv}"
464
+
465
+ begin
466
+ Gem::GemRunner.new.run argv
467
+ rescue => e
468
+ $logger.error "Error installing gem: #{e.message} in #{e.backtrace.join("\n")}"
469
+ exit e.exit_code
470
+ end
471
+
472
+ $logger.info 'The gem was successfully installed'
473
+
474
+ 0
475
+ end
476
+ end
477
+
478
+ # Class to update measures and compute arguments
479
+ class Measure
480
+ # Provides text for the main help functionality
481
+ def self.synopsis
482
+ 'Updates measures and compute arguments'
483
+ end
484
+
485
+ # Executes code to update and compute arguments for measures
486
+ #
487
+ # @param [Array] sub_argv Options passed to the e subcommand from the user input
488
+ # @return [Fixnum] Return status
489
+ # @todo (macumber) Add in the OpenStudio code to execute on measures
490
+ #
491
+ def execute(sub_argv)
492
+ options = {}
493
+ options[:check_for_update] = false
494
+ options[:update] = false
495
+ options[:compute_arguments] = nil
496
+
497
+ opts = OptionParser.new do |o|
498
+ o.banner = 'Usage: openstudio_cli measure [options] DIRECTORY'
499
+ o.separator ''
500
+ o.separator 'Options:'
501
+ o.separator ''
502
+
503
+ o.on('-c', '--check_for_updates', 'Check to see if the measure needs to be updated') do
504
+ options[:check_for_update] = workflow
505
+ end
506
+ o.on('-u', '--update', 'Update the measure.xml') do
507
+ options[:update] = true
508
+ end
509
+ o.on('-a', '--compute_arguments [MODEL]', 'Compute arguments for the given model') do |model_file|
510
+ options[:compute_arguments] = model_file
511
+ end
512
+ end
513
+
514
+ # Parse the options
515
+ argv = parse_options(opts, sub_argv)
516
+ $logger.error 'No directory provided' if argv == []
517
+ return 1 if argv == []
518
+ directory = argv[0]
519
+
520
+ $logger.debug("Measure command: #{argv.inspect} #{options.inspect}")
521
+ $logger.debug("Directory to examine is #{directory}")
522
+
523
+ $logger.error 'Code to be added here to operate on measures'
524
+
525
+ 1
526
+ end
527
+ end
528
+
529
+ # Class to execute a ruby script
530
+ class ExecuteRubyScript
531
+ # Provides text for the main help functionality
532
+ def self.synopsis
533
+ 'Executes a ruby file'
534
+ end
535
+
536
+ # Executes an arbitrary ruby script
537
+ #
538
+ # @param [Array] sub_argv Options passed to the e subcommand from the user input
539
+ # @return [Fixnum] Return status
540
+ #
541
+ def execute(sub_argv)
542
+ options = {}
543
+
544
+ opts = OptionParser.new do |o|
545
+ o.banner = 'Usage: openstudio_cli e [file]'
546
+ end
547
+
548
+ # Parse the options
549
+ argv = parse_options(opts, sub_argv)
550
+ return 0 if argv.nil?
551
+ return 1 unless argv
552
+ $logger.debug("ExecuteRubyScript command: #{argv.inspect} #{options.inspect}")
553
+ file_path = argv.shift.to_s
554
+ file_path = File.absolute_path(File.join(Dir.pwd, file_path)) unless Pathname.new(file_path).absolute?
555
+ $logger.debug "Path for the file to run: #{file_path}"
556
+
557
+ unless argv == []
558
+ $logger.error 'Extra arguments passed to the e command. Please refer to the help documentation.'
559
+ return 1
560
+ end
561
+
562
+ unless File.exist? file_path
563
+ $logger.error "Unable to find the file #{file_path} on the filesystem"
564
+ return 1
565
+ end
566
+
567
+ require file_path
568
+
569
+ 0
570
+ end
571
+ end
572
+
573
+ # Class to put the user into an irb shell
574
+ class InteractiveRubyShell
575
+ # Provides text for the main help functionality
576
+ def self.synopsis
577
+ 'Provides an interactive ruby shell'
578
+ end
579
+
580
+ # Executes the commands to get into an IRB prompt
581
+ #
582
+ # @param [Array] sub_argv Options passed to the i subcommand from the user input
583
+ # @return [Fixnum] Return status
584
+ #
585
+ def execute(sub_argv)
586
+ options = {}
587
+
588
+ opts = OptionParser.new do |o|
589
+ o.banner = 'Usage: openstudio_cli i'
590
+ end
591
+
592
+ # Parse the options
593
+ argv = parse_options(opts, sub_argv)
594
+ $logger.debug("InteractiveRubyShell command: #{argv.inspect} #{options.inspect}")
595
+ return 0 if argv.nil?
596
+
597
+ unless argv == []
598
+ $logger.error 'Extra arguments passed to the i command.'
599
+ return 1
600
+ end
601
+
602
+ IRB.start_session(binding)
603
+
604
+ 0
605
+ end
606
+ end
607
+
608
+ # Class to return the packaged OpenStudio version
609
+ class OpenStudioVersion
610
+ # Provides text for the main help functionality
611
+ def self.synopsis
612
+ 'Returns the OpenStudio version used by the CLI'
613
+ end
614
+
615
+ # Executes the OpenStudio commands to return the OpenStudio version
616
+ #
617
+ # @param [Array] sub_argv Options passed to the energyplus_version subcommand from the user input
618
+ # @return [Fixnum] Return status
619
+ #
620
+ def execute(sub_argv)
621
+ options = {}
622
+
623
+ opts = OptionParser.new do |o|
624
+ o.banner = 'Usage: openstudio_cli openstudio_version'
625
+ end
626
+
627
+ # Parse the options
628
+ argv = parse_options(opts, sub_argv)
629
+ $logger.debug("OpenStudioVersion command: #{argv.inspect} #{options.inspect}")
630
+ return 0 if argv.nil?
631
+
632
+ unless argv == []
633
+ $logger.error 'Extra arguments passed to the openstudio_version command.'
634
+ return 1
635
+ end
636
+
637
+ safe_puts OpenStudio.openStudioLongVersion
638
+
639
+ 0
640
+ end
641
+ end
642
+
643
+ # Class to return the EnergyPlus version
644
+ class EnergyPlusVersion
645
+ # Provides text for the main help functionality
646
+ def self.synopsis
647
+ 'Returns the EnergyPlus version used by the CLI'
648
+ end
649
+
650
+ # Executes the OpenStudio command to return the EnergyPlus version
651
+ #
652
+ # @param [Array] sub_argv Options passed to the openstudio_version subcommand from the user input
653
+ # @return [Fixnum] Return status
654
+ #
655
+ def execute(sub_argv)
656
+ options = {}
657
+
658
+ opts = OptionParser.new do |o|
659
+ o.banner = 'Usage: openstudio_cli energyplus_version'
660
+ end
661
+
662
+ # Parse the options
663
+ argv = parse_options(opts, sub_argv)
664
+ $logger.debug("EnergyPlusVersion command: #{argv.inspect} #{options.inspect}")
665
+ return 0 if argv.nil?
666
+
667
+ unless argv == []
668
+ $logger.error 'Arguments passed to the energyplus_version command.'
669
+ return 1
670
+ end
671
+
672
+ safe_puts OpenStudio.energyPlusVersion
673
+
674
+ 0
675
+ end
676
+ end
677
+
678
+ # Class to return the ruby version used by the packaged CLI
679
+ class RubyVersion
680
+ # Provides text for the main help functionality
681
+ def self.synopsis
682
+ 'Returns the Ruby version used by the CLI'
683
+ end
684
+
685
+ # Evaluates the RUBY_VERSION constant and returns it
686
+ #
687
+ # @param [Array] sub_argv Options passed to the ruby_version subcommand from the user input
688
+ # @return [Fixnum] Return status
689
+ #
690
+ def execute(sub_argv)
691
+ options = {}
692
+
693
+ opts = OptionParser.new do |o|
694
+ o.banner = 'Usage: openstudio_cli ruby_version'
695
+ end
696
+
697
+ # Parse the options
698
+ argv = parse_options(opts, sub_argv)
699
+ $logger.debug("RubyVersion command: #{argv.inspect} #{options.inspect}")
700
+ return 0 if argv.nil?
701
+
702
+ unless argv == []
703
+ $logger.error 'Arguments passed to the ruby_version command.'
704
+ return 1
705
+ end
706
+
707
+ safe_puts RUBY_VERSION
708
+
709
+ 0
710
+ end
711
+ end
712
+
713
+ # Class to return the full set of possible commands for the CLI
714
+ class ListCommands
715
+ # Provides text for the main help functionality
716
+ def self.synopsis
717
+ 'Lists the entire set of available commands for openstudio_cli'
718
+ end
719
+
720
+ # Executes the standard help method with the list_all attribute set to true
721
+ #
722
+ # @param [Array] sub_argv Options passed to the list_all subcommand from the user input
723
+ # @return [Fixnum] Return status
724
+ # @see #::CLI.help
725
+ #
726
+ def execute(sub_argv)
727
+ options = {}
728
+
729
+ opts = OptionParser.new do |o|
730
+ o.banner = 'Usage: openstudio_cli list_commands'
731
+ end
732
+
733
+ # Parse the options
734
+ argv = parse_options(opts, sub_argv)
735
+ $logger.debug("ListCommands command: #{argv.inspect} #{options.inspect}")
736
+ return 0 if argv.nil?
737
+
738
+ unless argv == []
739
+ $logger.error 'Arguments passed to the list_commands command.'
740
+ return 1
741
+ end
742
+
743
+ $logger.debug 'Creating a new CLI instance and calling help with list_all enabled'
744
+ ::CLI.new([]).help(true)
745
+
746
+ 0
747
+ end
748
+ end
749
+
750
+ # Set the logger level to DEBUG if the arguments include --verbose
751
+ $argv = ARGV.dup
752
+ if $argv.include? '--verbose'
753
+ $logger.level = Logger::DEBUG
754
+ $argv.delete '--verbose'
755
+ $logger.debug 'Set Logger log level to DEBUG'
756
+ end
757
+ $logger.debug "Input ARGV is #{$argv}"
758
+
759
+ # Operate on the gem_path option to set the gem search path
760
+ if $argv.include? '--gem_path'
761
+ $logger.info 'Setting gem path'
762
+ option_index = $argv.index '--gem_path'
763
+ path_index = option_index + 1
764
+ new_home = $argv[path_index]
765
+ $argv.slice! path_index
766
+ $argv.slice! $argv.index '--gem_path'
767
+ current_home = ENV['OPENSTUDIO_GEM_PATH']
768
+ $logger.warn "Overwriting previous OPENSTUDIO_GEM_PATH of #{current_home} to #{new_home} for this command" if current_home
769
+ $logger.info "No current gem path set in OPENSTUDIO_GEM_PATH, setting to #{new_home}" unless current_home
770
+ ENV['OPENSTUDIO_GEM_PATH'] = new_home
771
+ end
772
+
773
+ # Configure Gems to load the correct Gem files
774
+ # @see http://rubygems.rubyforge.org/rubygems-update/Gem.html
775
+ local_dir = ENV['OPENSTUDIO_GEM_PATH'] ? ENV['OPENSTUDIO_GEM_PATH'] : "~/OpenStudio/v#{OpenStudio.openStudioVersion}"
776
+ local_dir = File.absolute_path(local_dir)
777
+ ENV['GEM_PATH'] = OpenStudio::Workflow::Util::IO.is_windows? ? local_dir.tr('/', '\\') : local_dir
778
+ $logger.debug "Set environment variable GEM_PATH to #{ENV['GEM_PATH']}"
779
+ ENV['GEM_HOME'] = OpenStudio::Workflow::Util::IO.is_windows? ? '\\' : '/'
780
+ $logger.debug "Set environment variable GEM_HOME to #{ENV['GEM_HOME']}"
781
+ Gem.clear_paths
782
+ $logger.debug 'Reset Gem paths; openstudio_cli associated gems should load correctly'
783
+
784
+ # Execute the CLI interface, and exit with the proper error code
785
+ $logger.info "Executing argv: #{$argv}"
786
+ CLI.new($argv).execute