Class: OpenStudio::Extension::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/openstudio/extension/runner.rb

Overview

The Runner class provides functionality to run various commands including calls to the OpenStudio CLI.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dirname = Dir.pwd, bundle_without = [], options = {}) ⇒ Runner

When initialized with a directory containing a Gemfile, the Runner will attempt to create a bundle compatible with the OpenStudio CLI.

@param [String] dirname Directory to run commands in, defaults to Dir.pwd. If directory includes a Gemfile then create a local bundle.
@param bundle_without [Array] List of strings of the groups to exclude when running the bundle command
@param options [Hash] Hash describing options for running the simulation. These are the defaults for all runs unless overriden within the run_* methods. Note if options is used, then a local runner.conf file will not be loaded.
@option options [String] :max_datapoints Max number of datapoints to run
@option options [String] :num_parallel Number of simulations to run in parallel at a time
@option options [String] :run_simulations Set to true to run the simulations
@option options [String] :verbose Set to true to receive extra information while running simulations
@option options [String] :gemfile_path Path to gemfile to use
@option options [String] :bundle_install_path Path where the bundle should be installed


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/openstudio/extension/runner.rb', line 37

def initialize(dirname = Dir.pwd, bundle_without = [], options = {})
  # DLM: I am not sure if we want to use the main root directory to create these bundles
  # had the idea of passing in a Gemfile name/alias and path to Gemfile, then doing the bundle
  # in ~/OpenStudio/#{alias} or something like that?

  # if the dirname contains a runner.conf file, then use the config file to specify the parameters

  @options = OpenStudio::Extension::RunnerConfig.default_config(dirname)
  # ORDER of PRECEDENCE: default config < runner.conf file < options passed in directly
  if File.exist?(File.join(dirname, OpenStudio::Extension::RunnerConfig::FILENAME))
    puts 'Using runner options from runner.conf file'
    runner_config = OpenStudio::Extension::RunnerConfig.new(dirname)
    # use the default values overriden with runner.conf values where not
    # nil nor empty strings
    @options = @options.merge(runner_config.options.reject{|k, v| v.nil? || (v.kind_of?(String) && v === '')})
  end

  if !options.empty?
    puts 'Merging in passed-in options'
    # use the passed values or defaults overriden by passed options
    @options = @options.merge(options)
  end

  puts "Initializing runner with dirname: '#{dirname}' and options: #{@options}"
  @dirname = File.absolute_path(dirname)

  # use passed options, otherwise assume @dirname
  @gemfile_path = !@options.key?(:gemfile_path) || @options[:gemfile_path] === '' ? File.join(@dirname, 'Gemfile') : @options[:gemfile_path]
  @bundle_install_path = !@options.key?(:bundle_install_path) || @options[:bundle_install_path] === '' ? File.join(@dirname, '.bundle/install/') : @options[:bundle_install_path]
  @original_dir = Dir.pwd

  # gemfile directory
  @gemfile_dir = File.dirname(@gemfile_path)

  # puts "DIRNAME: #{@dirname}"
  # puts "@gemfile_path set to: #{@gemfile_path}"
  # puts "@bundle_install_path set to: #{@bundle_install_path}"
  # puts "@gemfile directory: #{@gemfile_dir}"

  @bundle_without = bundle_without || []
  @bundle_without_string = @bundle_without.join(' ')
  puts "@bundle_without_string = '#{@bundle_without_string}'"

  raise "#{@dirname} does not exist" unless File.exist?(@dirname)
  raise "#{@dirname} is not a directory" unless File.directory?(@dirname)

  if !File.exist?(@gemfile_path)
    # if there is no gemfile set these to nil
    @gemfile_path = nil
    @bundle_install_path = nil
  else
    # there is a gemfile, attempt to create a bundle
    begin
      # go to the directory with the gemfile to run these commands
      Dir.chdir(@gemfile_dir)

      # test to see if bundle is installed
      check_bundle = run_command('bundle -v', get_clean_env)
      if !check_bundle && !File.exist?(@dirname)
        raise "Failed to run command 'bundle -v', check that bundle is installed"
      end

      # TODO: check that ruby version is correct

      # check existing config
      needs_config = true
      if conf_bpath = Bundler.configured_bundle_path.explicit_path
        puts 'bundler config exists'
        needs_config = false

        if conf_bpath != @bundle_install_path
          puts "Detected mismatch between bundle's configured path #{conf_bpath} and runner configuration #{@bundle_install_path}"
          needs_config = true
        end

        # if config['BUNDLE_WITHOUT'] != @bundle_without_string
        #  needs_config = true
        # end
      end

      # check existing platform
      needs_platform = true
      if File.exist?('Gemfile.lock') # checking wrt gemfile_dir
        puts 'Gemfile.lock exists'
        gemfile_lock = Bundler::LockfileParser.new(Bundler.read_file('Gemfile.lock'))
        if gemfile_lock.platforms.include?('ruby')
          # already been configured, might not be up to date
          needs_platform = false
        end
      end

      puts "needs_config = #{needs_config}"
      if needs_config
        run_command("bundle config --local path '#{@bundle_install_path}'", get_clean_env)
        # run_command("bundle config --local without '#{@bundle_without_string}'", get_clean_env)
      end

      puts "needs_platform = #{needs_platform}"
      if needs_platform
        run_command('bundle lock --add_platform ruby', get_clean_env)
      end

      needs_update = needs_config || needs_platform
      if !needs_update && (!File.exist?('Gemfile.lock') || File.mtime(@gemfile_path) > File.mtime('Gemfile.lock'))
        needs_update = true
      end

      puts "needs_update = #{needs_update}"
      if needs_update
        run_command('bundle update', get_clean_env)
      end
    ensure
      Dir.chdir(@original_dir)
    end
  end
end

Instance Attribute Details

#bundle_install_pathObject (readonly)

Returns the value of attribute bundle_install_path.



22
23
24
# File 'lib/openstudio/extension/runner.rb', line 22

def bundle_install_path
  @bundle_install_path
end

#gemfile_pathObject (readonly)

Returns the value of attribute gemfile_path.



22
23
24
# File 'lib/openstudio/extension/runner.rb', line 22

def gemfile_path
  @gemfile_path
end

#optionsObject (readonly)

Returns the value of attribute options.



22
23
24
# File 'lib/openstudio/extension/runner.rb', line 22

def options
  @options
end

Instance Method Details

#add_measure_license(measures_dir, doc_templates_dir) ⇒ Object

Update measures by adding license file measures_dir and doc_templates_dir configured in rake_task Returns true if the command completes successfully, false otherwise.

@return [Boolean]


421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
# File 'lib/openstudio/extension/runner.rb', line 421

def add_measure_license(measures_dir, doc_templates_dir)
  puts 'Adding measure licenses'
  if measures_dir.nil? || measures_dir.empty?
    puts 'Measures dir is nil or empty'
    return true
  elsif doc_templates_dir.nil? || doc_templates_dir.empty?
    puts 'Doc templates dir is nil or empty'
    return false
  end

  result = false
  license_file = File.join(doc_templates_dir, 'LICENSE.md')
  puts "License file path: #{license_file}"

  raise "License file not found '#{license_file}'" if !File.exist?(license_file)

  measures = Dir["#{measures_dir}/**/measure.rb"]
  if measures.empty?
    # also try nested 2-deep to support openstudio-measures
    measures = Dir["#{measures_dir}/**/**/measure.rb"]
  end
  measures.each do |measure|
    FileUtils.cp(license_file, "#{File.dirname(measure)}/LICENSE.md")
  end
  result = true
  return result
end

#add_measure_readme(measures_dir, doc_templates_dir) ⇒ Object

Update measures by adding license file measures_dir and doc_templates_dir configured in rake_task Returns true if the command completes successfully, false otherwise.

@return [Boolean]


454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
# File 'lib/openstudio/extension/runner.rb', line 454

def add_measure_readme(measures_dir, doc_templates_dir)
  puts 'Adding measure readmes'
  if measures_dir.nil? || measures_dir.empty?
    puts 'Measures dir is nil or empty'
    return true
  elsif doc_templates_dir.nil? || doc_templates_dir.empty?
    puts 'Measures files dir is nil or empty'
    return false
  end

  result = false
  readme_file = File.join(doc_templates_dir, 'README.md.erb')
  puts "Readme file path: #{readme_file}"

  raise "Readme file not found '#{readme_file}'" if !File.exist?(readme_file)

  measures = Dir["#{measures_dir}/**/measure.rb"]
  if measures.empty?
    # also try nested 2-deep to support openstudio-measures
    measures = Dir["#{measures_dir}/**/**/measure.rb"]
  end
  measures.each do |measure|
    next if File.exist?("#{File.dirname(measure)}/README.md.erb")
    next if File.exist?("#{File.dirname(measure)}/README.md")

    puts "adding template README to #{measure}"
    FileUtils.cp(readme_file, "#{File.dirname(measure)}/README.md.erb")
  end
  result = true
  return result
end

#copy_core_files(measures_dir, core_dir) ⇒ Boolean

Update measures by copying in the latest resource files from the Extension gem into the measures’ respective resources folders. measures_dir and core_dir configured in rake_task Returns true if the command completes successfully, false otherwise.

Returns:

  • (Boolean)


375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
# File 'lib/openstudio/extension/runner.rb', line 375

def copy_core_files(measures_dir, core_dir)
  puts 'Copying measure resources'
  if measures_dir.nil? || measures_dir.empty?
    puts 'Measures dir is nil or empty'
    return true
  end

  result = false
  puts 'Copying updated resource files from extension core directory to individual measures.'
  puts 'Only files that have actually been changed will be listed.'

  # get all resource files in the core dir
  resource_files = Dir.glob(File.join(core_dir, '/*.*'))

  # this is to accommodate a single measures dir (like most gems)
  # or a repo with multiple directories fo measures (like OpenStudio-measures)
  measures = Dir.glob(File.join(measures_dir, '**/resources/*.rb'))
  if measures.empty?
    # also try nested 2-deep to support openstudio-measures
    measures = Dir.glob(File.join(measures_dir, '**/**/resources/*.rb'))
  end

  # NOTE: some older measures like AEDG use 'OsLib_SomeName' instead of 'os_lib_some_name'
  # this script isn't replacing those copies

  # loop through resource files
  resource_files.each do |resource_file|
    # loop through measure dirs looking for matching file
    measures.each do |measure|
      next unless File.basename(measure) == File.basename(resource_file)
      next if FileUtils.identical?(resource_file, File.path(measure))

      puts "Replacing #{measure} with #{resource_file}."
      FileUtils.cp(resource_file, File.path(measure))
    end
  end
  result = true

  return result
end

#get_clean_envObject

Returns a hash of environment variables that can be merged with the current environment to prevent automatic bundle activation.

DLM: should this be a module or class method?

@return [Hash]


160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/openstudio/extension/runner.rb', line 160

def get_clean_env
  # blank out bundler and gem path modifications, will be re-setup by new call
  new_env = {}
  new_env['BUNDLER_ORIG_MANPATH'] = nil
  new_env['BUNDLER_ORIG_PATH'] = nil
  new_env['BUNDLER_VERSION'] = nil
  new_env['BUNDLE_BIN_PATH'] = nil
  new_env['RUBYLIB'] = nil
  new_env['RUBYOPT'] = nil

  # DLM: preserve GEM_HOME and GEM_PATH set by current bundle because we are not supporting bundle
  # requires to ruby gems will work, will fail if we require a native gem
  new_env['GEM_PATH'] = nil
  new_env['GEM_HOME'] = nil

  # DLM: for now, ignore current bundle in case it has binary dependencies in it
  # bundle_gemfile = ENV['BUNDLE_GEMFILE']
  # bundle_path = ENV['BUNDLE_PATH']
  # if bundle_gemfile.nil? || bundle_path.nil?
  new_env['BUNDLE_GEMFILE'] = nil
  new_env['BUNDLE_PATH'] = nil
  new_env['BUNDLE_WITHOUT'] = nil
  # else
  #  new_env['BUNDLE_GEMFILE'] = bundle_gemfile
  #  new_env['BUNDLE_PATH'] = bundle_path
  # end

  return new_env
end

#get_measure_dirs_in_dir(measures_dir) ⇒ Object

Get path to all measures dirs found under measure dir.

@param [String] measures_dir Measures directory

@return [Array] returns path to all directories containing measures found under measure dir


247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/openstudio/extension/runner.rb', line 247

def get_measure_dirs_in_dir(measures_dir)
  measures = Dir.glob(File.join(measures_dir, '**/measure.rb'))
  if measures.empty?
    # also try nested 2-deep to support openstudio-measures
    measures = Dir.glob(File.join(measures_dir, '**/**/measure.rb'))
  end

  result = []
  measures.each { |m| result << File.dirname(File.dirname(m)) }

  return result.uniq
end

#get_measures_in_dir(measures_dir) ⇒ Object

Get path to all measures found under measure dir.

@param [String] measures_dir Measures directory

@return [Array] returns path to all measure directories found under measure dir


229
230
231
232
233
234
235
236
237
238
239
# File 'lib/openstudio/extension/runner.rb', line 229

def get_measures_in_dir(measures_dir)
  measures = Dir.glob(File.join(measures_dir, '**/measure.rb'))
  if measures.empty?
    # also try nested 2-deep to support openstudio-measures
    measures = Dir.glob(File.join(measures_dir, '**/**/measure.rb'))
  end

  result = []
  measures.each { |m| result << File.dirname(m) }
  return result
end

#list_measures(measures_dir) ⇒ Object



346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/openstudio/extension/runner.rb', line 346

def list_measures(measures_dir)
  puts 'Listing measures'
  if measures_dir.nil? || measures_dir.empty?
    puts 'Measures dir is nil or empty'
    return true
  end

  puts "measures path: #{measures_dir}"

  # this is to accommodate a single measures dir (like most gems)
  # or a repo with multiple directories fo measures (like OpenStudio-measures)
  measures = Dir.glob(File.join(measures_dir, '**/measure.rb'))
  if measures.empty?
    # also try nested 2-deep to support openstudio-measures
    measures = Dir.glob(File.join(measures_dir, '**/**/measure.rb'))
  end
  puts "#{measures.length} MEASURES FOUND"
  measures.each do |measure|
    name = measure.split('/')[-2]
    puts name.to_s
  end
end

#run_command(command, env = {}) ⇒ Object

Run a command after merging the current environment with env. Command is run in @dirname, returns to Dir.pwd after completion. Returns true if the command completes successfully, false otherwise. Standard Out, Standard Error, and Status Code are collected and printed, but not returned.

@return [Boolean]


196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/openstudio/extension/runner.rb', line 196

def run_command(command, env = {})
  result = false
  original_dir = Dir.pwd
  begin
    Dir.chdir(@gemfile_dir)
    # DLM: using popen3 here can result in deadlocks
    stdout_str, stderr_str, status = Open3.capture3(env, command)
    if status.success?
      # puts "Command completed successfully"
      # puts "stdout: #{stdout_str}"
      # puts "stderr: #{stderr_str}"
      # STDOUT.flush
      result = true
    else
      puts "Error running command: '#{command}'"
      puts "stdout: #{stdout_str}"
      puts "stderr: #{stderr_str}"
      $stdout.flush
      result = false
    end
  ensure
    Dir.chdir(original_dir)
  end

  return result
end

#run_osw(in_osw, run_dir) ⇒ Object

Run the OpenStudio CLI on an OSW. The OSW is configured to include measure and file locations for all loaded OpenStudio Extensions.

@param [String, Hash] in_osw If string this is the path to an OSW file on disk, if Hash it is loaded JSON with symbolized keys
@param [String] run_dir Directory to run the OSW in, will be created if does not exist

@return [Boolean] True if command succeeded, false otherwise # DLM: should this return path to out.osw instead?


579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
# File 'lib/openstudio/extension/runner.rb', line 579

def run_osw(in_osw, run_dir)
  run_dir = File.absolute_path(run_dir)

  if in_osw.is_a?(String)
    in_osw_path = in_osw
    raise "'#{in_osw_path}' does not exist" if !File.exist?(in_osw_path)

    in_osw = {}
    File.open(in_osw_path, 'r') do |file|
      in_osw = JSON.parse(file.read, symbolize_names: true)
    end
  end

  osw = OpenStudio::Extension.configure_osw(in_osw)
  osw[:run_directory] = run_dir

  FileUtils.mkdir_p(run_dir)

  run_osw_path = File.join(run_dir, 'in.osw')
  File.open(run_osw_path, 'w') do |file|
    file.puts JSON.pretty_generate(osw)
  end

  if @options[:run_simulations]
    cli = OpenStudio.getOpenStudioCLI
    out_log = "#{run_osw_path}.log"
    # if Gem.win_platform?
    #   # out_log = "nul"
    # else
    #   # out_log = "/dev/null"
    # end

    the_call = ''
    verbose_string = ''
    if @options[:verbose]
      verbose_string = ' --verbose'
    end
    if @gemfile_path
      if @bundle_without_string.empty?
        the_call = "#{cli}#{verbose_string} --bundle '#{@gemfile_path}' --bundle_path '#{@bundle_install_path}' run -w '#{run_osw_path}' 2>&1 > \"#{out_log}\""
      else
        the_call = "#{cli}#{verbose_string} --bundle '#{@gemfile_path}' --bundle_path '#{@bundle_install_path}' --bundle_without '#{@bundle_without_string}' run -w '#{run_osw_path}' 2>&1 > \"#{out_log}\""
      end
    else
      the_call = "#{cli}#{verbose_string} run -w '#{run_osw_path}' 2>&1 > \"#{out_log}\""
    end

    puts 'SYSTEM CALL:'
    puts the_call
    $stdout.flush
    result = run_command(the_call, get_clean_env)
    puts "DONE, result = #{result}"
    $stdout.flush
  else
    puts 'simulations are not performed, since to the @options[:run_simulations] is set to false'
  end

  if @options[:run_simulations]
    # Additional checks for failed CLI
    if File.exist?(File.join(run_dir, 'failed.job'))
      result = false
    end

    if !File.exist?(File.join(run_dir, 'finished.job'))
      result = false
    end
  end

  return result
end

#run_osws(osw_files, num_parallel = , max_to_run = ) ⇒ Object

run osws, return any failure messages



651
652
653
654
655
656
657
658
659
660
661
662
663
# File 'lib/openstudio/extension/runner.rb', line 651

def run_osws(osw_files, num_parallel = @options[:num_parallel], max_to_run = @options[:max_datapoints])
  failures = []
  osw_files = osw_files.slice(0, [osw_files.size, max_to_run].min)

  Parallel.each(osw_files, in_threads: num_parallel) do |osw|
    result = run_osw(osw, File.dirname(osw))
    if !result
      failures << "Failed to run OSW '#{osw}'"
    end
  end

  return failures
end

#test_measures_with_cli(measures_dir) ⇒ Object

Run the OpenStudio CLI command to test measures on given directory Returns true if the command completes successfully, false otherwise. measures_dir configured in rake_task

@return [Boolean]


266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/openstudio/extension/runner.rb', line 266

def test_measures_with_cli(measures_dir)
  puts 'Testing measures with CLI system call'
  if measures_dir.nil? || measures_dir.empty?
    puts 'Measures dir is nil or empty'
    return true
  end

  puts "measures path: #{measures_dir}"

  cli = OpenStudio.getOpenStudioCLI

  the_call = ''
  if @gemfile_path
    if @bundle_without_string.empty?
      the_call = "#{cli} --verbose --bundle '#{@gemfile_path}' --bundle_path '#{@bundle_install_path}' measure -r '#{measures_dir}'"
    else
      the_call = "#{cli} --verbose --bundle '#{@gemfile_path}' --bundle_path '#{@bundle_install_path}' --bundle_without '#{@bundle_without_string}' measure -r '#{measures_dir}'"
    end
  else
    the_call = "#{cli} --verbose measure -r #{measures_dir}"
  end

  puts 'SYSTEM CALL:'
  puts the_call
  $stdout.flush
  result = run_command(the_call, get_clean_env)
  puts "DONE, result = #{result}"
  $stdout.flush

  return result
end


486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
# File 'lib/openstudio/extension/runner.rb', line 486

def update_copyright(root_dir, doc_templates_dir)
  if root_dir.nil? || root_dir.empty?
    puts 'Root dir is nil or empty'
    return false
  elsif doc_templates_dir.nil? || doc_templates_dir.empty?
    puts 'Doc templates dir is nil or empty'
    return false
  end

  if File.exist?(File.join(doc_templates_dir, 'LICENSE.md')) && File.exist?(File.join(root_dir, 'LICENSE.md'))
    puts 'updating LICENSE.md in root dir'
    FileUtils.cp(File.join(doc_templates_dir, 'LICENSE.md'), File.join(root_dir, 'LICENSE.md'))
  end

  ruby_regex = /^\#\s?[\#\*]{12,}.*copyright.*?\#\s?[\#\*]{12,}\s*$/mi
  erb_regex = /^<%\s*\#\s?[\#\*]{12,}.*copyright.*?\#\s?[\#\*]{12,}\s*%>$/mi
  js_regex = /^\/\* @preserve.*copyright.*?\*\//mi

  filename = File.join(doc_templates_dir, 'copyright_ruby.txt')
  puts "Copyright file path: #{filename}"
  raise "Copyright file not found '#{filename}'" if !File.exist?(filename)

  file = File.open(filename, 'r')
  ruby_header_text = file.read
  file.close
  ruby_header_text.strip!
  ruby_header_text += "\n"

  filename = File.join(doc_templates_dir, 'copyright_erb.txt')
  puts "Copyright file path: #{filename}"
  raise "Copyright file not found '#{filename}'" if !File.exist?(filename)

  file = File.open(filename, 'r')
  erb_header_text = file.read
  file.close
  erb_header_text.strip!
  erb_header_text += "\n"

  filename = File.join(doc_templates_dir, 'copyright_js.txt')
  puts "Copyright file path: #{filename}"
  raise "Copyright file not found '#{filename}'" if !File.exist?(filename)

  file = File.open(filename, 'r')
  js_header_text = file.read
  file.close
  js_header_text.strip!
  js_header_text += "\n"

  raise 'bad copyright_ruby.txt' if ruby_header_text !~ ruby_regex
  raise 'bad copyright_erb.txt' if erb_header_text !~ erb_regex
  raise 'bad copyright_js.txt' if js_header_text !~ js_regex

  # look for .rb, .html.erb, and .js.erb
  paths = [
    { glob: "#{root_dir}/**/*.rb", license: ruby_header_text, regex: ruby_regex },
    { glob: "#{root_dir}/**/*.html.erb", license: erb_header_text, regex: erb_regex },
    { glob: "#{root_dir}/**/*.js.erb", license: js_header_text, regex: js_regex }
  ]
  # This is the bundle deployment folder
  excluded_subfolders = ['vendor'].map{|d| "#{root_dir}/vendor/bundle"}


  puts "Encoding.default_external = #{Encoding.default_external}"
  puts "Encoding.default_internal = #{Encoding.default_internal}"

  paths.each do |path|
    Dir[path[:glob]].reject{|f| excluded_subfolders.any?{|d| f[d]} }.each do |dir_file|
      puts "Updating license in file #{dir_file}"
      f = File.read(dir_file)
      if f.match?(path[:regex])
        puts '  License found -- updating'
        File.open(dir_file, 'w') { |write| write << f.gsub(path[:regex], path[:license]) }
      elsif f =~ /\(C\)/i || f =~ /\(Copyright\)/i
        puts '  File already has copyright -- skipping'
      else
        puts '  No license found -- adding'
        if f.match?(/#!/)
          puts '  CANNOT add license to file automatically, add it manually and it will update automatically in the future'
          next
        end
        File.open(dir_file, 'w') { |write| write << f.insert(0, "#{path[:license]}\n") }
      end
    end
  end
end

#update_measures(measures_dir) ⇒ Object

Run the OpenStudio CLI command to update measures on given directory Returns true if the command completes successfully, false otherwise.

@return [Boolean]


303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/openstudio/extension/runner.rb', line 303

def update_measures(measures_dir)
  puts 'Updating measures with CLI system call'
  if measures_dir.nil? || measures_dir.empty?
    puts 'Measures dir is nil or empty'
    return true
  end

  result = true
  # DLM: this is a temporary workaround to handle OpenStudio-Measures
  get_measure_dirs_in_dir(measures_dir).each do |m_dir|
    puts "measures path: #{m_dir}"

    cli = OpenStudio.getOpenStudioCLI

    the_call = ''
    if @gemfile_path
      if @bundle_without_string.empty?
        the_call = "#{cli} --verbose --bundle '#{@gemfile_path}' --bundle_path '#{@bundle_install_path}' measure -t '#{m_dir}'"
      else
        the_call = "#{cli} --verbose --bundle '#{@gemfile_path}' --bundle_path '#{@bundle_install_path}' --bundle_without '#{@bundle_without_string}' measure -t '#{m_dir}'"
      end
    else
      the_call = "#{cli} --verbose measure -t '#{m_dir}'"
    end

    puts 'SYSTEM CALL:'
    puts the_call
    $stdout.flush
    result &&= run_command(the_call, get_clean_env)
    puts "DONE, result = #{result}"
    $stdout.flush
  end

  return result
end