bcl 0.4.1 → 0.5.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.
- checksums.yaml +4 -4
- data/lib/bcl/component_methods.rb +56 -60
- data/lib/bcl/component_spreadsheet.rb +254 -265
- data/lib/bcl/component_xml.rb +0 -12
- data/lib/bcl/master_taxonomy.rb +1 -8
- data/lib/bcl/measure_xml.rb +0 -13
- data/lib/bcl/tar_ball.rb +2 -7
- data/lib/bcl/version.rb +1 -1
- data/lib/bcl.rb +13 -1
- metadata +17 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0102b8e0a960be6a451282df54e0085e1f5f0326
|
4
|
+
data.tar.gz: 3c2782995b885b716a487e7cdf1ea4065ae9c550
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aeb50fb46e7813091e870a957d1b80d74c33759fad953e1fba1430b27c9bb6a33eba385ea063414407b6d8bc754135e9ab07a559618be794a6e2a15dca5f5d99
|
7
|
+
data.tar.gz: b31c0c600958f41b85f15c442f0a59930bc524e84b4da699be82c305856906db5e6fde8acd134bf2903d2327de4cbe06a450c4e00a3166cf0bcfebda127ba1b9
|
@@ -17,19 +17,9 @@
|
|
17
17
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
18
|
######################################################################
|
19
19
|
|
20
|
-
require 'rubygems'
|
21
|
-
require 'pathname'
|
22
|
-
require 'fileutils'
|
23
|
-
require 'enumerator'
|
24
|
-
require 'yaml'
|
25
|
-
require 'base64'
|
26
20
|
|
27
21
|
# required gems
|
28
|
-
require 'json/pure'
|
29
|
-
require 'bcl/tar_ball'
|
30
|
-
#require 'rest-client'
|
31
22
|
require 'net/https'
|
32
|
-
require 'libxml'
|
33
23
|
|
34
24
|
module BCL
|
35
25
|
|
@@ -41,13 +31,13 @@ module BCL
|
|
41
31
|
attr_accessor :parsed_measures_path
|
42
32
|
|
43
33
|
def initialize()
|
44
|
-
@parsed_measures_path = './measures/parsed
|
34
|
+
@parsed_measures_path = './measures/parsed'
|
45
35
|
@config = nil
|
46
36
|
@session = nil
|
47
37
|
@access_token = nil
|
48
38
|
@http = nil
|
49
39
|
@api_version = 2.0
|
50
|
-
@group_id = nil
|
40
|
+
@group_id = nil
|
51
41
|
|
52
42
|
load_config
|
53
43
|
end
|
@@ -81,7 +71,7 @@ module BCL
|
|
81
71
|
if @group_id.nil?
|
82
72
|
puts "[WARNING] You did not set a group ID in your config.yml file. You can retrieve your group ID from the node number of your group page (e.g., https://bcl.nrel.gov/node/32). Will continue, but you will not be able to upload content."
|
83
73
|
end
|
84
|
-
|
74
|
+
|
85
75
|
@http = Net::HTTP.new(url, port)
|
86
76
|
if port == 443
|
87
77
|
@http.use_ssl = true
|
@@ -100,8 +90,6 @@ module BCL
|
|
100
90
|
# puts "#{key}: #{value}"
|
101
91
|
#end
|
102
92
|
|
103
|
-
#restClient wasn't working
|
104
|
-
#res = RestClient.post "#{@config[:server][:url]}/api/user/login", data.to_json, :content_type => :json, :accept => :json
|
105
93
|
if res.code == '200'
|
106
94
|
puts "Login Successful"
|
107
95
|
|
@@ -123,7 +111,7 @@ module BCL
|
|
123
111
|
#puts "DATA: #{data}"
|
124
112
|
session_name = ""
|
125
113
|
sessid = ""
|
126
|
-
json =
|
114
|
+
json = MultiJson.load(res.body)
|
127
115
|
json.each do |key, val|
|
128
116
|
if key == 'session_name'
|
129
117
|
session_name = val
|
@@ -175,14 +163,15 @@ module BCL
|
|
175
163
|
retrieve_measures(search_term, filter_term, return_all_pages) do |measure|
|
176
164
|
#parse and save
|
177
165
|
parse_measure_metadata(measure)
|
178
|
-
|
179
166
|
end
|
180
167
|
|
181
168
|
return true
|
182
|
-
|
183
169
|
end
|
184
170
|
|
185
|
-
|
171
|
+
|
172
|
+
# Read the measure's information to pull out the metadata and to move into a more
|
173
|
+
# friendly directory name.
|
174
|
+
# option measure is a JSON
|
186
175
|
def parse_measure_metadata(measure)
|
187
176
|
|
188
177
|
#check for valid measure
|
@@ -191,7 +180,7 @@ module BCL
|
|
191
180
|
file_data = download_component(measure[:measure][:uuid])
|
192
181
|
|
193
182
|
if file_data
|
194
|
-
save_file = File.expand_path("@
|
183
|
+
save_file = File.expand_path("#{@parsed_measures_path}/#{measure[:measure][:name].downcase.gsub(" ", "_")}.zip")
|
195
184
|
File.open(save_file, 'wb') { |f| f << file_data }
|
196
185
|
|
197
186
|
#unzip file and delete zip.
|
@@ -201,13 +190,13 @@ module BCL
|
|
201
190
|
|
202
191
|
# catch a weird case where there is an extra space in an unzip file structure but not in the measure.name
|
203
192
|
if measure[:measure][:name] == "Add Daylight Sensor at Center of Spaces with a Specified Space Type Assigned"
|
204
|
-
if !File.exists? "#{@parsed_measures_path}
|
205
|
-
temp_dir_name = "#{@parsed_measures_path}Add Daylight Sensor at Center of Spaces with a Specified Space Type Assigned"
|
206
|
-
FileUtils.move(temp_dir_name, "#{@parsed_measures_path}
|
193
|
+
if !File.exists? "#{@parsed_measures_path}/#{measure[:measure][:name]}"
|
194
|
+
temp_dir_name = "#{@parsed_measures_path}/Add Daylight Sensor at Center of Spaces with a Specified Space Type Assigned"
|
195
|
+
FileUtils.move(temp_dir_name, "#{@parsed_measures_path}/#{measure[:measure][:name]}")
|
207
196
|
end
|
208
197
|
end
|
209
198
|
|
210
|
-
temp_dir_name = "#{@parsed_measures_path}
|
199
|
+
temp_dir_name = "#{@parsed_measures_path}/#{measure[:measure][:name]}"
|
211
200
|
|
212
201
|
# Read the measure.rb file
|
213
202
|
#puts "save dir name #{temp_dir_name}"
|
@@ -218,7 +207,7 @@ module BCL
|
|
218
207
|
measure_string = File.read(measure_filename)
|
219
208
|
|
220
209
|
measure_hash[:classname] = measure_string.match(/class (.*) </)[1]
|
221
|
-
measure_hash[:path] = "#{@parsed_measures_path}
|
210
|
+
measure_hash[:path] = "#{@parsed_measures_path}/#{measure_hash[:classname]}"
|
222
211
|
measure_hash[:name] = measure[:measure][:name]
|
223
212
|
if measure_string =~ /OpenStudio::Ruleset::WorkspaceUserScript/
|
224
213
|
measure_hash[:measure_type] = "EnergyPlusMeasure"
|
@@ -244,7 +233,7 @@ module BCL
|
|
244
233
|
new_arg[:variable_type] = arg[1]
|
245
234
|
arg_params = arg[2].split(",")
|
246
235
|
new_arg[:name] = arg_params[0].gsub(/"|'/, "")
|
247
|
-
choice_vector = arg_params[1]
|
236
|
+
choice_vector = arg_params[1].strip
|
248
237
|
|
249
238
|
# local variable name to get other attributes
|
250
239
|
new_arg[:display_name] = measure_string.match(/#{new_arg[:local_variable]}.setDisplayName\((.*)\)/)[1]
|
@@ -252,40 +241,52 @@ module BCL
|
|
252
241
|
|
253
242
|
if measure_string =~ /#{new_arg[:local_variable]}.setDefaultValue/
|
254
243
|
new_arg[:default_value] = measure_string.match(/#{new_arg[:local_variable]}.setDefaultValue\((.*)\)/)[1]
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
new_arg[:default_value].gsub!(/"|'/, "")
|
244
|
+
else
|
245
|
+
puts "[WARNING] #{measure_hash[:name]}:#{new_arg[:name]} has no default value... will try to continue"
|
246
|
+
end
|
259
247
|
|
260
|
-
|
261
|
-
|
248
|
+
case new_arg[:variable_type]
|
249
|
+
when "Choice"
|
250
|
+
# Choices to appear to only be strings?
|
251
|
+
puts "Choice vector appears to be #{choice_vector}"
|
252
|
+
new_arg[:default_value].gsub!(/"|'/, "") if new_arg[:default_value]
|
262
253
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
new_arg[:
|
269
|
-
when "Bool"
|
270
|
-
new_arg[:default_value] = new_arg[:default_value].downcase == "true" ? true : false
|
271
|
-
when "Integer"
|
272
|
-
new_arg[:default_value] = new_arg[:default_value].to_i
|
273
|
-
when "Double"
|
274
|
-
new_arg[:default_value] = new_arg[:default_value].to_f
|
254
|
+
# parse the choices from the measure
|
255
|
+
possible_choices = measure_string.scan(/#{choice_vector}.*<<.*("|')(.*)("|')/)
|
256
|
+
puts "Possible choices are #{possible_choices}"
|
257
|
+
|
258
|
+
if possible_choices.empty?
|
259
|
+
new_arg[:choices] = []
|
275
260
|
else
|
276
|
-
|
277
|
-
|
261
|
+
new_arg[:choices] = possible_choices.map { |c| c[1] }
|
262
|
+
end
|
263
|
+
|
264
|
+
# if the choices are inherited from the model, then need to just display the default value which
|
265
|
+
# somehow magically works because that is the display name
|
266
|
+
if new_arg[:default_value]
|
267
|
+
new_arg[:choices] << new_arg[:default_value] unless new_arg[:choices].include?(new_arg[:default_value])
|
268
|
+
end
|
269
|
+
when "String"
|
270
|
+
new_arg[:default_value].gsub!(/"|'/, "") if new_arg[:default_value]
|
271
|
+
when "Bool"
|
272
|
+
new_arg[:default_value] = new_arg[:default_value].downcase == "true" ? true : false
|
273
|
+
when "Integer"
|
274
|
+
new_arg[:default_value] = new_arg[:default_value].to_i if new_arg[:default_value]
|
275
|
+
when "Double"
|
276
|
+
new_arg[:default_value] = new_arg[:default_value].to_f if new_arg[:default_value]
|
277
|
+
else
|
278
|
+
raise "unknown variable type of #{new_arg[:variable_type]}"
|
278
279
|
end
|
279
280
|
|
280
281
|
measure_hash[:arguments] << new_arg
|
281
282
|
end
|
282
283
|
|
283
284
|
# create a new measure.json file for parsing later if need be
|
284
|
-
File.open("#{measure_hash[:path]}/measure.json", 'w') { |f| f <<
|
285
|
+
File.open("#{measure_hash[:path]}/measure.json", 'w') { |f| f << MultiJson.dump(measure_hash, :pretty => true) }
|
285
286
|
|
286
287
|
end
|
287
288
|
else
|
288
|
-
puts "Problems downloading #{measure[:measure][:name]}...moving on"
|
289
|
+
puts "Problems downloading #{measure[:measure][:name]}... moving on"
|
289
290
|
end
|
290
291
|
end
|
291
292
|
end
|
@@ -355,19 +356,17 @@ module BCL
|
|
355
356
|
}
|
356
357
|
|
357
358
|
}
|
358
|
-
#restclient not working
|
359
|
-
#res = RestClient.post "#{@config[:server][:url]}/api/content.json", @data.to_json, :content_type => :json, :cookies => @session
|
360
359
|
|
361
360
|
path = "/api/content.json"
|
362
361
|
headers = {'Content-Type' => 'application/json', 'X-CSRF-Token' => @access_token, 'Cookie' => @session}
|
363
362
|
|
364
363
|
|
365
|
-
res = @http.post(path, @data
|
364
|
+
res = @http.post(path, MultiJson.dump(@data), headers)
|
366
365
|
|
367
366
|
res_j = "could not get json from http post response"
|
368
367
|
if res.code == '200'
|
369
368
|
puts "200"
|
370
|
-
res_j =
|
369
|
+
res_j = MultiJson.load(res.body)
|
371
370
|
puts " 200 - Successful Upload"
|
372
371
|
valid = true
|
373
372
|
|
@@ -455,9 +454,6 @@ module BCL
|
|
455
454
|
}
|
456
455
|
}
|
457
456
|
|
458
|
-
#restclient not working
|
459
|
-
#res = RestClient.post "#{@config[:server][:url]}/api/content", @data.to_json, :content_type => :json, :cookies => @session, :accept => :json
|
460
|
-
|
461
457
|
path = "/api/content.json"
|
462
458
|
headers = {'Content-Type' => 'application/json', 'Cookie' => @session, 'X-CSRF-Token' => @access_token}
|
463
459
|
|
@@ -465,7 +461,7 @@ module BCL
|
|
465
461
|
|
466
462
|
res_j = "could not get json from http post response"
|
467
463
|
if res.code == '200'
|
468
|
-
res_j =
|
464
|
+
res_j = MultiJson.load(res.body)
|
469
465
|
puts " 200 - Successful Upload"
|
470
466
|
valid = true
|
471
467
|
elsif res.code == '404'
|
@@ -572,7 +568,7 @@ module BCL
|
|
572
568
|
puts "search url: #{full_url}"
|
573
569
|
res = @http.get(full_url)
|
574
570
|
#return unparsed
|
575
|
-
|
571
|
+
MultiJson.load(res.body, :symbolize_keys => true)
|
576
572
|
else
|
577
573
|
#iterate over result pages
|
578
574
|
#modify filter_str for show_rows=200 for maximum returns
|
@@ -586,14 +582,14 @@ module BCL
|
|
586
582
|
|
587
583
|
pagecnt = 0
|
588
584
|
continue = 1
|
589
|
-
results =
|
585
|
+
results = []
|
590
586
|
while continue == 1
|
591
587
|
#retrieve current page
|
592
588
|
full_url_all = full_url + "&page=#{pagecnt}"
|
593
589
|
puts "search url: #{full_url_all}"
|
594
590
|
response = @http.get(full_url_all)
|
595
591
|
#parse here so you can build results array
|
596
|
-
res =
|
592
|
+
res = MultiJson.load(response.body)
|
597
593
|
|
598
594
|
if res["result"].count > 0
|
599
595
|
pagecnt += 1
|
@@ -606,7 +602,7 @@ module BCL
|
|
606
602
|
end
|
607
603
|
#return unparsed b/c that is what is expected
|
608
604
|
formatted_results = {"result" => results}
|
609
|
-
results_to_return =
|
605
|
+
results_to_return = MultiJson.load(MultiJson.dump(formatted_results), :symbolize_keys => true)
|
610
606
|
end
|
611
607
|
end
|
612
608
|
|
@@ -20,20 +20,9 @@
|
|
20
20
|
# Converts a custom Excel spreadsheet format to BCL components for upload
|
21
21
|
# Format of the Excel spreadsheet is documented in /doc/ComponentSpreadsheet.docx
|
22
22
|
|
23
|
-
|
24
|
-
require 'pathname'
|
25
|
-
require 'fileutils'
|
26
|
-
require 'date'
|
27
|
-
|
28
|
-
# required gems
|
29
|
-
require 'uuid' # gem install uuid
|
30
|
-
require 'bcl/component_xml'
|
31
|
-
require 'bcl/component_methods'
|
32
|
-
require 'bcl/master_taxonomy'
|
33
|
-
|
34
|
-
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
23
|
+
if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
|
35
24
|
begin
|
36
|
-
# apparently this is not a gem
|
25
|
+
# apparently this is not a gem (todo: need to remove and replace with roo)
|
37
26
|
require 'win32ole'
|
38
27
|
mod = WIN32OLE
|
39
28
|
$have_win32ole = true
|
@@ -44,277 +33,277 @@ end
|
|
44
33
|
|
45
34
|
module BCL
|
46
35
|
|
47
|
-
WorksheetStruct = Struct.new(:name, :components)
|
48
|
-
HeaderStruct = Struct.new(:name, :children)
|
49
|
-
ComponentStruct = Struct.new(:row, :name, :uid, :version_id, :headers, :values)
|
50
|
-
|
51
|
-
class ComponentSpreadsheet
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
# WINDOWS ONLY SECTION BECAUSE THIS USES WIN32OLE
|
56
|
-
if $have_win32ole
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
36
|
+
WorksheetStruct = Struct.new(:name, :components)
|
37
|
+
HeaderStruct = Struct.new(:name, :children)
|
38
|
+
ComponentStruct = Struct.new(:row, :name, :uid, :version_id, :headers, :values)
|
39
|
+
|
40
|
+
class ComponentSpreadsheet
|
41
|
+
|
42
|
+
public
|
43
|
+
|
44
|
+
# WINDOWS ONLY SECTION BECAUSE THIS USES WIN32OLE
|
45
|
+
if $have_win32ole
|
46
|
+
|
47
|
+
#initialize with Excel spreadsheet to read
|
48
|
+
def initialize(xlsx_path, worksheet_names =["all"])
|
49
|
+
|
50
|
+
@xlsx_path = Pathname.new(xlsx_path).realpath.to_s
|
51
|
+
@worksheets = []
|
52
|
+
|
53
|
+
begin
|
54
|
+
|
55
|
+
excel = WIN32OLE::new('Excel.Application')
|
56
|
+
|
57
|
+
xlsx = excel.Workbooks.Open(@xlsx_path)
|
58
|
+
|
59
|
+
#by default, operate on all worksheets
|
60
|
+
if worksheet_names == ["all"]
|
61
|
+
xlsx.Worksheets.each do |xlsx_worksheet|
|
62
|
+
parse_xlsx_worksheet(xlsx_worksheet)
|
63
|
+
end
|
64
|
+
else #if specific worksheets are specified, operate on them
|
65
|
+
worksheet_names.each do |worksheet_name|
|
66
|
+
parse_xlsx_worksheet(xlsx.Worksheets(worksheet_name))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#save spreadsheet if changes have been made
|
71
|
+
if xlsx.saved == true
|
72
|
+
#puts "[ComponentSpreadsheet] Spreadsheet unchanged; not saving"
|
73
|
+
else
|
74
|
+
xlsx.Save
|
75
|
+
puts "[ComponentSpreadsheet] Spreadsheet changes saved"
|
76
|
+
end
|
77
|
+
|
78
|
+
ensure
|
79
|
+
|
80
|
+
excel.Quit
|
81
|
+
WIN32OLE.ole_free(excel)
|
82
|
+
excel.ole_free
|
83
|
+
xlsx=nil
|
84
|
+
excel=nil
|
85
|
+
GC.start
|
86
|
+
|
74
87
|
end
|
75
|
-
|
76
|
-
worksheet_names.each do |worksheet_name|
|
77
|
-
parse_xlsx_worksheet(xlsx.Worksheets(worksheet_name))
|
78
|
-
end
|
88
|
+
|
79
89
|
end
|
80
90
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
puts "
|
91
|
+
else # if $have_win32ole
|
92
|
+
|
93
|
+
# parse the master taxonomy document
|
94
|
+
def initialize(xlsx_path)
|
95
|
+
puts "ComponentSpreadsheet class requires 'win32ole' to parse the component spreadsheet."
|
96
|
+
puts "ComponentSpreadsheet may also be stored and loaded from JSON if your platform does not support win32ole."
|
87
97
|
end
|
88
|
-
|
89
|
-
ensure
|
90
|
-
|
91
|
-
excel.Quit
|
92
|
-
WIN32OLE.ole_free(excel)
|
93
|
-
excel.ole_free
|
94
|
-
xlsx=nil
|
95
|
-
excel=nil
|
96
|
-
GC.start
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
end
|
101
|
-
|
102
|
-
else # if $have_win32ole
|
103
98
|
|
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
|
-
datetime
|
99
|
+
end # if $have_win32ole
|
100
|
+
|
101
|
+
def save(save_path, chunk_size = 1000, delete_old_gather = false)
|
102
|
+
|
103
|
+
# load master taxonomy to validate components
|
104
|
+
taxonomy = BCL::MasterTaxonomy.new
|
105
|
+
|
106
|
+
#FileUtils.rm_rf(save_path) if File.exists?(save_path) and File.directory?(save_path)
|
107
|
+
|
108
|
+
@worksheets.each do |worksheet|
|
109
|
+
worksheet.components.each do |component|
|
110
|
+
|
111
|
+
component_xml = Component.new("#{save_path}/components")
|
112
|
+
component_xml.name = component.name
|
113
|
+
component_xml.uid = component.uid
|
114
|
+
component_xml.comp_version_id = component.version_id
|
115
|
+
|
116
|
+
# this tag is how we know where this goes in the taxonomy
|
117
|
+
component_xml.add_tag(worksheet.name)
|
118
|
+
|
119
|
+
values = component.values[0]
|
120
|
+
component.headers.each do |header|
|
121
|
+
|
122
|
+
if /description/i.match(header.name)
|
123
|
+
|
124
|
+
name = values.delete_at(0)
|
125
|
+
uid = values.delete_at(0)
|
126
|
+
version_id = values.delete_at(0)
|
127
|
+
description = values.delete_at(0)
|
128
|
+
fidelity_level = values.delete_at(0).to_int
|
129
|
+
# name, uid, and version_id already processed
|
130
|
+
component_xml.description = description
|
131
|
+
component_xml.fidelity_level = fidelity_level
|
132
|
+
|
133
|
+
elsif /provenance/i.match(header.name)
|
134
|
+
|
135
|
+
author = values.delete_at(0)
|
136
|
+
datetime = values.delete_at(0)
|
137
|
+
if datetime.nil?
|
138
|
+
puts "[ComponentSpreadsheet] WARNING missing the date in the datetime column in the spreadsheet - assuming today"
|
139
|
+
datetime = DateTime.new
|
140
|
+
else
|
141
|
+
datetime = DateTime.parse(datetime)
|
142
|
+
end
|
143
|
+
|
144
|
+
comment = values.delete_at(0)
|
145
|
+
component_xml.add_provenance(author.to_s, datetime.to_s, comment.to_s)
|
146
|
+
|
147
|
+
elsif /tag/i.match(header.name)
|
148
|
+
|
149
|
+
value = values.delete_at(0)
|
150
|
+
component_xml.add_tag(value)
|
151
|
+
|
152
|
+
elsif /attribute/i.match(header.name)
|
153
|
+
|
154
|
+
value = values.delete_at(0)
|
155
|
+
name = header.children[0]
|
156
|
+
units = ""
|
157
|
+
if match_data = /(.*)\((.*)\)/.match(name)
|
158
|
+
name = match_data[1].strip
|
159
|
+
units = match_data[2].strip
|
160
|
+
end
|
161
|
+
component_xml.add_attribute(name, value, units)
|
162
|
+
|
163
|
+
elsif /source/i.match(header.name)
|
164
|
+
|
165
|
+
manufacturer = values.delete_at(0)
|
166
|
+
model = values.delete_at(0)
|
167
|
+
serial_no = values.delete_at(0)
|
168
|
+
year = values.delete_at(0)
|
169
|
+
url = values.delete_at(0)
|
170
|
+
component_xml.source_manufacturer = manufacturer
|
171
|
+
component_xml.source_model = model
|
172
|
+
component_xml.source_serial_no = serial_no
|
173
|
+
component_xml.source_year = year
|
174
|
+
component_xml.source_url = url
|
175
|
+
|
176
|
+
elsif /file/i.match(header.name)
|
177
|
+
|
178
|
+
software_program = values.delete_at(0)
|
179
|
+
version = values.delete_at(0)
|
180
|
+
filename = values.delete_at(0)
|
181
|
+
filetype = values.delete_at(0)
|
182
|
+
filepath = values.delete_at(0)
|
183
|
+
#not all components(rows) have all files; skip if filename "" or nil
|
184
|
+
next if filename == "" or filename == nil
|
185
|
+
#skip the file if it doesn't exist at the specified location
|
186
|
+
if not File.exists?(filepath)
|
187
|
+
puts "[ComponentSpreadsheet] ERROR #{filepath} -> File does not exist, will not be included in component xml"
|
188
|
+
next #go to the next file
|
189
|
+
end
|
190
|
+
component_xml.add_file(software_program, version, filepath, filename, filetype)
|
191
|
+
|
151
192
|
else
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
comment = values.delete_at(0)
|
156
|
-
component_xml.add_provenance(author.to_s, datetime.to_s, comment.to_s)
|
157
|
-
|
158
|
-
elsif /tag/i.match(header.name)
|
159
|
-
|
160
|
-
value = values.delete_at(0)
|
161
|
-
component_xml.add_tag(value)
|
162
|
-
|
163
|
-
elsif /attribute/i.match(header.name)
|
164
|
-
|
165
|
-
value = values.delete_at(0)
|
166
|
-
name = header.children[0]
|
167
|
-
units = ""
|
168
|
-
if match_data = /(.*)\((.*)\)/.match(name)
|
169
|
-
name = match_data[1].strip
|
170
|
-
units = match_data[2].strip
|
171
|
-
end
|
172
|
-
component_xml.add_attribute(name, value, units)
|
173
|
-
|
174
|
-
elsif /source/i.match(header.name)
|
175
|
-
|
176
|
-
manufacturer = values.delete_at(0)
|
177
|
-
model = values.delete_at(0)
|
178
|
-
serial_no = values.delete_at(0)
|
179
|
-
year = values.delete_at(0)
|
180
|
-
url = values.delete_at(0)
|
181
|
-
component_xml.source_manufacturer = manufacturer
|
182
|
-
component_xml.source_model = model
|
183
|
-
component_xml.source_serial_no = serial_no
|
184
|
-
component_xml.source_year = year
|
185
|
-
component_xml.source_url = url
|
186
|
-
|
187
|
-
elsif /file/i.match(header.name)
|
188
|
-
|
189
|
-
software_program = values.delete_at(0)
|
190
|
-
version = values.delete_at(0)
|
191
|
-
filename = values.delete_at(0)
|
192
|
-
filetype = values.delete_at(0)
|
193
|
-
filepath = values.delete_at(0)
|
194
|
-
#not all components(rows) have all files; skip if filename "" or nil
|
195
|
-
next if filename == "" or filename == nil
|
196
|
-
#skip the file if it doesn't exist at the specified location
|
197
|
-
if not File.exists?(filepath)
|
198
|
-
puts "[ComponentSpreadsheet] ERROR #{filepath} -> File does not exist, will not be included in component xml"
|
199
|
-
next #go to the next file
|
193
|
+
raise "Unknown section #{header.name}"
|
194
|
+
|
200
195
|
end
|
201
|
-
|
202
|
-
|
203
|
-
else
|
204
|
-
raise "Unknown section #{header.name}"
|
205
|
-
|
196
|
+
|
206
197
|
end
|
207
198
|
|
199
|
+
taxonomy.check_component(component_xml)
|
200
|
+
|
201
|
+
component_xml.save_tar_gz(false)
|
202
|
+
|
208
203
|
end
|
209
|
-
|
210
|
-
taxonomy.check_component(component_xml)
|
211
|
-
|
212
|
-
component_xml.save_tar_gz(false)
|
213
|
-
|
214
|
-
end
|
215
|
-
|
216
|
-
end
|
217
|
-
|
218
|
-
BCL.gather_components(save_path,chunk_size,delete_old_gather)
|
219
|
-
|
220
|
-
end
|
221
|
-
|
222
|
-
private
|
223
|
-
|
224
|
-
def parse_xlsx_worksheet(xlsx_worksheet)
|
225
|
-
|
226
|
-
worksheet = WorksheetStruct.new
|
227
|
-
worksheet.name = xlsx_worksheet.Range("A1").Value
|
228
|
-
worksheet.components = []
|
229
|
-
puts "[ComponentSpreadsheet] Starting parsing components of type #{worksheet.name}"
|
230
|
-
|
231
|
-
# find number of rows, first column should be name, should not be empty
|
232
|
-
num_rows = 1
|
233
|
-
while true do
|
234
|
-
test = xlsx_worksheet.Range("A#{num_rows}").Value
|
235
|
-
if test.nil? or test.empty?
|
236
|
-
num_rows -= 1
|
237
|
-
break
|
204
|
+
|
238
205
|
end
|
239
|
-
|
206
|
+
|
207
|
+
BCL.gather_components(save_path, chunk_size, delete_old_gather)
|
208
|
+
|
240
209
|
end
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
210
|
+
|
211
|
+
private
|
212
|
+
|
213
|
+
def parse_xlsx_worksheet(xlsx_worksheet)
|
214
|
+
|
215
|
+
worksheet = WorksheetStruct.new
|
216
|
+
worksheet.name = xlsx_worksheet.Range("A1").Value
|
217
|
+
worksheet.components = []
|
218
|
+
puts "[ComponentSpreadsheet] Starting parsing components of type #{worksheet.name}"
|
219
|
+
|
220
|
+
# find number of rows, first column should be name, should not be empty
|
221
|
+
num_rows = 1
|
222
|
+
while true do
|
223
|
+
test = xlsx_worksheet.Range("A#{num_rows}").Value
|
224
|
+
if test.nil? or test.empty?
|
225
|
+
num_rows -= 1
|
226
|
+
break
|
253
227
|
end
|
254
|
-
|
255
|
-
header.name = value1
|
256
|
-
header.children = []
|
228
|
+
num_rows += 1
|
257
229
|
end
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
230
|
+
|
231
|
+
# scan number of columns
|
232
|
+
headers = []
|
233
|
+
header = nil
|
234
|
+
max_col = nil
|
235
|
+
xlsx_worksheet.Columns.each do |col|
|
236
|
+
value1 = col.Rows("1").Value
|
237
|
+
value2 = col.Rows("2").Value
|
238
|
+
|
239
|
+
if not value1.nil? and not value1.empty?
|
240
|
+
if not header.nil?
|
241
|
+
headers << header
|
242
|
+
end
|
243
|
+
header = HeaderStruct.new
|
244
|
+
header.name = value1
|
245
|
+
header.children = []
|
246
|
+
end
|
247
|
+
|
248
|
+
if not value2.nil? and not value2.empty?
|
249
|
+
if not header.nil?
|
250
|
+
header.children << value2
|
251
|
+
end
|
262
252
|
end
|
253
|
+
|
254
|
+
if (value1.nil? or value1.empty?) and (value2.nil? or value2.empty?)
|
255
|
+
break
|
256
|
+
end
|
257
|
+
|
258
|
+
matchdata = /^\$(.+):/.match(col.Address)
|
259
|
+
max_col = matchdata[1]
|
263
260
|
end
|
264
|
-
|
265
|
-
if
|
266
|
-
|
261
|
+
|
262
|
+
if not header.nil?
|
263
|
+
headers << header
|
267
264
|
end
|
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
|
-
|
265
|
+
|
266
|
+
if not headers.empty?
|
267
|
+
headers[0].name = "description"
|
268
|
+
end
|
269
|
+
|
270
|
+
puts " Found #{num_rows - 2} components"
|
271
|
+
|
272
|
+
components = []
|
273
|
+
for i in 3..num_rows do
|
274
|
+
component = ComponentStruct.new
|
275
|
+
component.row = i
|
276
|
+
|
277
|
+
# get name
|
278
|
+
component.name = xlsx_worksheet.Range("A#{i}").value
|
279
|
+
|
280
|
+
# get uid, if empty set it
|
281
|
+
component.uid = xlsx_worksheet.Range("B#{i}").value
|
282
|
+
if component.uid.nil? or component.uid.empty?
|
283
|
+
component.uid = UUID.new.generate
|
284
|
+
puts "#{component.name} uid missing; creating new one"
|
285
|
+
xlsx_worksheet.Range("B#{i}").value = component.uid
|
286
|
+
end
|
287
|
+
|
288
|
+
# get version_id, if empty set it
|
289
|
+
component.version_id = xlsx_worksheet.Range("C#{i}").value
|
290
|
+
if component.version_id.nil? or component.version_id.empty?
|
291
|
+
component.version_id = UUID.new.generate
|
292
|
+
puts "#{component.name} version id missing; creating new one"
|
293
|
+
xlsx_worksheet.Range("C#{i}").value = component.version_id
|
294
|
+
end
|
295
|
+
|
296
|
+
component.headers = headers
|
297
|
+
component.values = xlsx_worksheet.Range("A#{i}:#{max_col}#{i}").value
|
298
|
+
worksheet.components << component
|
297
299
|
end
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
puts "#{component.name} version id missing; creating new one"
|
304
|
-
xlsx_worksheet.Range("C#{i}").value = component.version_id
|
305
|
-
end
|
306
|
-
|
307
|
-
component.headers = headers
|
308
|
-
component.values = xlsx_worksheet.Range("A#{i}:#{max_col}#{i}").value
|
309
|
-
worksheet.components << component
|
300
|
+
|
301
|
+
@worksheets << worksheet
|
302
|
+
|
303
|
+
puts "[ComponentSpreadsheet] Finished parsing components of type #{worksheet.name}"
|
304
|
+
|
310
305
|
end
|
311
|
-
|
312
|
-
@worksheets << worksheet
|
313
|
-
|
314
|
-
puts "[ComponentSpreadsheet] Finished parsing components of type #{worksheet.name}"
|
315
|
-
|
306
|
+
|
316
307
|
end
|
317
|
-
|
318
|
-
end
|
319
308
|
|
320
309
|
end # module BCL
|
data/lib/bcl/component_xml.rb
CHANGED
@@ -21,18 +21,6 @@
|
|
21
21
|
# generating the component information that will be uploaded to
|
22
22
|
# the Building Component Library.
|
23
23
|
|
24
|
-
require 'rubygems'
|
25
|
-
require 'pathname'
|
26
|
-
require 'fileutils'
|
27
|
-
require 'csv'
|
28
|
-
|
29
|
-
# required gems
|
30
|
-
require 'builder' #gem install builder (creates xml files)
|
31
|
-
|
32
|
-
require 'bcl/tar_ball'
|
33
|
-
require 'bcl/bcl_xml'
|
34
|
-
|
35
|
-
|
36
24
|
module BCL
|
37
25
|
class Component < BaseXml
|
38
26
|
attr_accessor :comment
|
data/lib/bcl/master_taxonomy.rb
CHANGED
@@ -17,16 +17,9 @@
|
|
17
17
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
18
|
######################################################################
|
19
19
|
|
20
|
-
require 'rubygems'
|
21
|
-
require 'pathname'
|
22
|
-
require 'fileutils'
|
23
|
-
require 'rbconfig'
|
24
|
-
|
25
|
-
#require gems
|
26
|
-
require 'builder' #gem install builder (creates xml files)
|
27
20
|
$have_win32ole = false
|
28
21
|
|
29
|
-
if
|
22
|
+
if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
|
30
23
|
begin
|
31
24
|
# apparently this is not a gem
|
32
25
|
require 'win32ole'
|
data/lib/bcl/measure_xml.rb
CHANGED
@@ -21,15 +21,6 @@
|
|
21
21
|
# generating the component information that will be uploaded to
|
22
22
|
# the Building Component Library.
|
23
23
|
|
24
|
-
require 'rubygems'
|
25
|
-
require 'pathname'
|
26
|
-
require 'fileutils'
|
27
|
-
require 'csv'
|
28
|
-
|
29
|
-
# required gems
|
30
|
-
require 'bcl/tar_ball'
|
31
|
-
require 'bcl/bcl_xml'
|
32
|
-
|
33
24
|
module BCL
|
34
25
|
class Measure
|
35
26
|
def initialize(save_path)
|
@@ -42,9 +33,5 @@ module BCL
|
|
42
33
|
|
43
34
|
@xml = LibXML::XML::Document.string(xmlfile)
|
44
35
|
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
36
|
end
|
49
|
-
|
50
37
|
end
|
data/lib/bcl/tar_ball.rb
CHANGED
@@ -17,11 +17,6 @@
|
|
17
17
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
18
|
######################################################################
|
19
19
|
|
20
|
-
require 'rubygems'
|
21
|
-
|
22
|
-
require 'archive/tar/minitar' #gem install archive-tar-minitar
|
23
|
-
require 'zip/zip' #gem install rubyzip -v 0.9.9
|
24
|
-
|
25
20
|
module BCL
|
26
21
|
|
27
22
|
module_function
|
@@ -57,7 +52,7 @@ module BCL
|
|
57
52
|
|
58
53
|
def create_zip(destination, paths)
|
59
54
|
|
60
|
-
Zip::
|
55
|
+
Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
|
61
56
|
paths.each do |fi|
|
62
57
|
# Two arguments:
|
63
58
|
# - The name of the file as it will appear in the archive
|
@@ -69,7 +64,7 @@ module BCL
|
|
69
64
|
end
|
70
65
|
|
71
66
|
def extract_zip(filename, destination, delete_zip = false)
|
72
|
-
Zip::
|
67
|
+
Zip::File.open(filename) { |zip_file|
|
73
68
|
zip_file.each { |f|
|
74
69
|
f_path=File.join(destination, f.name)
|
75
70
|
FileUtils.mkdir_p(File.dirname(f_path))
|
data/lib/bcl/version.rb
CHANGED
data/lib/bcl.rb
CHANGED
@@ -1,11 +1,23 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
# file formatters
|
5
|
+
require 'yaml'
|
6
|
+
require 'multi_json'
|
7
|
+
require 'libxml'
|
1
8
|
require 'builder'
|
9
|
+
|
10
|
+
# todo: can we condense these into one?
|
11
|
+
require 'archive/tar/minitar'
|
2
12
|
require 'zlib'
|
13
|
+
require 'zip'
|
3
14
|
|
15
|
+
require 'bcl/bcl_xml'
|
4
16
|
require 'bcl/component_spreadsheet'
|
5
17
|
require 'bcl/component_xml'
|
6
18
|
require 'bcl/component_methods'
|
7
19
|
require 'bcl/measure_xml'
|
8
|
-
require 'bcl/bcl_xml'
|
9
20
|
require 'bcl/tar_ball'
|
10
21
|
require 'bcl/master_taxonomy'
|
11
22
|
require 'bcl/version'
|
23
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bcl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Macumber
|
@@ -70,7 +70,7 @@ dependencies:
|
|
70
70
|
- !ruby/object:Gem::Version
|
71
71
|
version: '0'
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
|
-
name:
|
73
|
+
name: multi_json
|
74
74
|
requirement: !ruby/object:Gem::Requirement
|
75
75
|
requirements:
|
76
76
|
- - '>='
|
@@ -84,7 +84,7 @@ dependencies:
|
|
84
84
|
- !ruby/object:Gem::Version
|
85
85
|
version: '0'
|
86
86
|
- !ruby/object:Gem::Dependency
|
87
|
-
name:
|
87
|
+
name: libxml-ruby
|
88
88
|
requirement: !ruby/object:Gem::Requirement
|
89
89
|
requirements:
|
90
90
|
- - '>='
|
@@ -98,7 +98,7 @@ dependencies:
|
|
98
98
|
- !ruby/object:Gem::Version
|
99
99
|
version: '0'
|
100
100
|
- !ruby/object:Gem::Dependency
|
101
|
-
name:
|
101
|
+
name: yamler
|
102
102
|
requirement: !ruby/object:Gem::Requirement
|
103
103
|
requirements:
|
104
104
|
- - '>='
|
@@ -112,7 +112,7 @@ dependencies:
|
|
112
112
|
- !ruby/object:Gem::Version
|
113
113
|
version: '0'
|
114
114
|
- !ruby/object:Gem::Dependency
|
115
|
-
name:
|
115
|
+
name: faraday
|
116
116
|
requirement: !ruby/object:Gem::Requirement
|
117
117
|
requirements:
|
118
118
|
- - '>='
|
@@ -126,7 +126,7 @@ dependencies:
|
|
126
126
|
- !ruby/object:Gem::Version
|
127
127
|
version: '0'
|
128
128
|
- !ruby/object:Gem::Dependency
|
129
|
-
name:
|
129
|
+
name: roo
|
130
130
|
requirement: !ruby/object:Gem::Requirement
|
131
131
|
requirements:
|
132
132
|
- - '>='
|
@@ -140,61 +140,33 @@ dependencies:
|
|
140
140
|
- !ruby/object:Gem::Version
|
141
141
|
version: '0'
|
142
142
|
- !ruby/object:Gem::Dependency
|
143
|
-
name:
|
144
|
-
requirement: !ruby/object:Gem::Requirement
|
145
|
-
requirements:
|
146
|
-
- - ~>
|
147
|
-
- !ruby/object:Gem::Version
|
148
|
-
version: 0.9.9
|
149
|
-
type: :runtime
|
150
|
-
prerelease: false
|
151
|
-
version_requirements: !ruby/object:Gem::Requirement
|
152
|
-
requirements:
|
153
|
-
- - ~>
|
154
|
-
- !ruby/object:Gem::Version
|
155
|
-
version: 0.9.9
|
156
|
-
- !ruby/object:Gem::Dependency
|
157
|
-
name: mime-types
|
158
|
-
requirement: !ruby/object:Gem::Requirement
|
159
|
-
requirements:
|
160
|
-
- - ~>
|
161
|
-
- !ruby/object:Gem::Version
|
162
|
-
version: 1.25.1
|
163
|
-
type: :runtime
|
164
|
-
prerelease: false
|
165
|
-
version_requirements: !ruby/object:Gem::Requirement
|
166
|
-
requirements:
|
167
|
-
- - ~>
|
168
|
-
- !ruby/object:Gem::Version
|
169
|
-
version: 1.25.1
|
170
|
-
- !ruby/object:Gem::Dependency
|
171
|
-
name: roo
|
143
|
+
name: nokogiri
|
172
144
|
requirement: !ruby/object:Gem::Requirement
|
173
145
|
requirements:
|
174
|
-
- -
|
146
|
+
- - '>='
|
175
147
|
- !ruby/object:Gem::Version
|
176
|
-
version:
|
148
|
+
version: '0'
|
177
149
|
type: :runtime
|
178
150
|
prerelease: false
|
179
151
|
version_requirements: !ruby/object:Gem::Requirement
|
180
152
|
requirements:
|
181
|
-
- -
|
153
|
+
- - '>='
|
182
154
|
- !ruby/object:Gem::Version
|
183
|
-
version:
|
155
|
+
version: '0'
|
184
156
|
- !ruby/object:Gem::Dependency
|
185
|
-
name:
|
157
|
+
name: rubyzip
|
186
158
|
requirement: !ruby/object:Gem::Requirement
|
187
159
|
requirements:
|
188
|
-
- -
|
160
|
+
- - '>='
|
189
161
|
- !ruby/object:Gem::Version
|
190
|
-
version:
|
162
|
+
version: '0'
|
191
163
|
type: :runtime
|
192
164
|
prerelease: false
|
193
165
|
version_requirements: !ruby/object:Gem::Requirement
|
194
166
|
requirements:
|
195
|
-
- -
|
167
|
+
- - '>='
|
196
168
|
- !ruby/object:Gem::Version
|
197
|
-
version:
|
169
|
+
version: '0'
|
198
170
|
description: This gem contains helper methods for generating the Component XML file
|
199
171
|
needed to upload files to the Building Component Library. It also contains the classes
|
200
172
|
needed for logging in via the api and uploading generating components
|
@@ -226,7 +198,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
226
198
|
requirements:
|
227
199
|
- - '>='
|
228
200
|
- !ruby/object:Gem::Version
|
229
|
-
version:
|
201
|
+
version: 1.9.2
|
230
202
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
231
203
|
requirements:
|
232
204
|
- - '>='
|