bcl 0.7.0 → 0.8.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/CHANGELOG.md +13 -0
- data/Gemfile +1 -9
- data/LICENSE.md +27 -0
- data/Rakefile +40 -232
- data/bcl.gemspec +26 -17
- data/lib/bcl/base_xml.rb +4 -18
- data/lib/bcl/component.rb +4 -18
- data/lib/bcl/component_from_spreadsheet.rb +4 -18
- data/lib/bcl/component_methods.rb +63 -427
- data/lib/bcl/core_ext.rb +4 -18
- data/lib/bcl/tar_ball.rb +4 -52
- data/lib/bcl/version.rb +5 -19
- data/lib/bcl.rb +4 -18
- data/schemas/v3/measure_v3.xsd +1 -6
- metadata +63 -18
- data/License.txt +0 -65
@@ -1,21 +1,7 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# This library is free software; you can redistribute it and/or
|
6
|
-
# modify it under the terms of the GNU Lesser General Public
|
7
|
-
# License as published by the Free Software Foundation; either
|
8
|
-
# version 2.1 of the License, or (at your option) any later version.
|
9
|
-
#
|
10
|
-
# This library is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
-
# Lesser General Public License for more details.
|
14
|
-
#
|
15
|
-
# You should have received a copy of the GNU Lesser General Public
|
16
|
-
# License along with this library; if not, write to the Free Software
|
17
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
-
######################################################################
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
+
# See also https://openstudio.net/license
|
4
|
+
# *******************************************************************************
|
19
5
|
|
20
6
|
module BCL
|
21
7
|
class ComponentMethods
|
@@ -28,121 +14,32 @@ module BCL
|
|
28
14
|
def initialize
|
29
15
|
@parsed_measures_path = './measures/parsed'
|
30
16
|
@config = nil
|
31
|
-
@session = nil
|
32
|
-
@access_token = nil
|
33
17
|
@http = nil
|
34
|
-
@api_version =
|
35
|
-
@group_id = nil
|
36
|
-
@logged_in = false
|
18
|
+
@api_version = nil
|
37
19
|
|
20
|
+
# load configs from file or default
|
38
21
|
load_config
|
39
|
-
end
|
40
22
|
|
41
|
-
|
42
|
-
|
43
|
-
if url.nil?
|
44
|
-
url = @config[:server][:url]
|
45
|
-
end
|
23
|
+
# configure connection
|
24
|
+
url = @config[:server][:url]
|
46
25
|
# look for http vs. https
|
47
26
|
if url.include? 'https'
|
48
27
|
port = 443
|
49
28
|
else
|
50
29
|
port = 80
|
51
30
|
end
|
31
|
+
|
52
32
|
# strip out http(s)
|
53
33
|
url = url.gsub('http://', '')
|
54
34
|
url = url.gsub('https://', '')
|
55
35
|
|
56
|
-
if username.nil? || password.nil?
|
57
|
-
# log in via cached credentials
|
58
|
-
username = @config[:server][:user][:username]
|
59
|
-
password = @config[:server][:user][:password]
|
60
|
-
@group_id = group_id || @config[:server][:user][:group]
|
61
|
-
puts "logging in using credentials in .bcl/config.yml: Connecting to #{url} on port #{port} as #{username} with group #{@group_id}"
|
62
|
-
else
|
63
|
-
@group_id = group_id || @config[:server][:user][:group]
|
64
|
-
puts "logging in using credentials in function arguments: Connecting to #{url} on port #{port} as #{username} with group #{@group_id}"
|
65
|
-
end
|
66
|
-
|
67
|
-
if @group_id.nil?
|
68
|
-
puts '[WARNING] You did not set a group ID in your config.yml file or pass in a group ID. 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.'
|
69
|
-
end
|
70
|
-
|
71
36
|
@http = Net::HTTP.new(url, port)
|
72
37
|
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
73
38
|
if port == 443
|
74
39
|
@http.use_ssl = true
|
75
40
|
end
|
76
41
|
|
77
|
-
|
78
|
-
|
79
|
-
login_path = '/api/user/login.json'
|
80
|
-
headers = { 'Content-Type' => 'application/json' }
|
81
|
-
|
82
|
-
res = @http.post(login_path, data, headers)
|
83
|
-
|
84
|
-
# for debugging:
|
85
|
-
# res.each do |key, value|
|
86
|
-
# puts "#{key}: #{value}"
|
87
|
-
# end
|
88
|
-
|
89
|
-
if res.code == '200'
|
90
|
-
puts 'Login Successful'
|
91
|
-
|
92
|
-
bnes = ''
|
93
|
-
bni = ''
|
94
|
-
junkout = res['set-cookie'].split(';')
|
95
|
-
junkout.each do |line|
|
96
|
-
if line.match?(/BNES_SESS/)
|
97
|
-
bnes = line.match(/(BNES_SESS.*)/)[0]
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
junkout.each do |line|
|
102
|
-
if line.match?(/BNI/)
|
103
|
-
bni = line.match(/(BNI.*)/)[0]
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# puts "DATA: #{data}"
|
108
|
-
session_name = ''
|
109
|
-
sessid = ''
|
110
|
-
json = JSON.parse(res.body)
|
111
|
-
json.each do |key, val|
|
112
|
-
if key == 'session_name'
|
113
|
-
session_name = val
|
114
|
-
elsif key == 'sessid'
|
115
|
-
sessid = val
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
@session = session_name + '=' + sessid + ';' + bni + ';' + bnes
|
120
|
-
|
121
|
-
# get access token
|
122
|
-
token_path = '/services/session/token'
|
123
|
-
token_headers = { 'Content-Type' => 'application/json', 'Cookie' => @session }
|
124
|
-
# puts "token_headers = #{token_headers.inspect}"
|
125
|
-
access_token = @http.post(token_path, '', token_headers)
|
126
|
-
if access_token.code == '200'
|
127
|
-
@access_token = access_token.body
|
128
|
-
else
|
129
|
-
puts 'Unable to get access token; uploads will not work'
|
130
|
-
puts "error code: #{access_token.code}"
|
131
|
-
puts "error info: #{access_token.body}"
|
132
|
-
end
|
133
|
-
|
134
|
-
# puts "access_token = *#{@access_token}*"
|
135
|
-
# puts "cookie = #{@session}"
|
136
|
-
|
137
|
-
res
|
138
|
-
else
|
139
|
-
|
140
|
-
puts "error code: #{res.code}"
|
141
|
-
puts "error info: #{res.body}"
|
142
|
-
puts 'continuing as unauthenticated sessions (you can still search and download)'
|
143
|
-
|
144
|
-
res
|
145
|
-
end
|
42
|
+
puts "Connecting to BCL at URL: #{@config[:server][:url]}"
|
146
43
|
end
|
147
44
|
|
148
45
|
# retrieve measures for parsing metadata.
|
@@ -153,10 +50,18 @@ module BCL
|
|
153
50
|
# raise "Please login before performing this action" if @session.nil?
|
154
51
|
|
155
52
|
# make sure filter_term includes bundle
|
156
|
-
if
|
157
|
-
filter_term
|
158
|
-
|
159
|
-
filter_term
|
53
|
+
if @api_version == 2.0
|
54
|
+
if filter_term.nil?
|
55
|
+
filter_term = 'fq[]=bundle%3Anrel_measure'
|
56
|
+
elsif !filter_term.include? 'bundle'
|
57
|
+
filter_term += '&fq[]=bundle%3Anrel_measure'
|
58
|
+
end
|
59
|
+
else
|
60
|
+
if filter_term.nil?
|
61
|
+
filter_term = 'fq=bundle%3Ameasure'
|
62
|
+
elsif !filter_term.include? 'bundle'
|
63
|
+
filter_term += '&fq=bundle%3Ameasure'
|
64
|
+
end
|
160
65
|
end
|
161
66
|
|
162
67
|
# use provided search term or nil.
|
@@ -170,183 +75,6 @@ module BCL
|
|
170
75
|
end
|
171
76
|
end
|
172
77
|
|
173
|
-
# evaluate the response from the API in a consistent manner
|
174
|
-
def evaluate_api_response(api_response)
|
175
|
-
valid = false
|
176
|
-
result = { error: 'could not get json from http post response' }
|
177
|
-
case api_response.code
|
178
|
-
when '200'
|
179
|
-
puts " Response Code: #{api_response.code}"
|
180
|
-
if api_response.body.empty?
|
181
|
-
puts ' 200 BUT ERROR: Returned body was empty. Possible causes:'
|
182
|
-
puts ' - BSD tar on Mac OSX vs gnutar'
|
183
|
-
result = { error: 'returned 200, but returned body was empty' }
|
184
|
-
valid = false
|
185
|
-
else
|
186
|
-
puts ' 200 - Successful Upload'
|
187
|
-
result = JSON.parse api_response.body
|
188
|
-
valid = true
|
189
|
-
end
|
190
|
-
when '404'
|
191
|
-
puts " Error Code: #{api_response.code} - #{api_response.body}"
|
192
|
-
puts ' - check these common causes first:'
|
193
|
-
puts " - you are trying to update content that doesn't exist"
|
194
|
-
puts " - you are not an 'administrator member' of the group you're trying to upload to"
|
195
|
-
result = JSON.parse api_response.body
|
196
|
-
valid = false
|
197
|
-
when '406'
|
198
|
-
puts " Error Code: #{api_response.code}"
|
199
|
-
# try to parse the response a bit
|
200
|
-
error = JSON.parse api_response.body
|
201
|
-
puts "temp error: #{error}"
|
202
|
-
if error.key?('form_errors')
|
203
|
-
if error['form_errors'].key?('field_tar_file')
|
204
|
-
result = { error: error['form_errors']['field_tar_file'] }
|
205
|
-
elsif error['form_errors'].key?('og_group_ref][und][0][default')
|
206
|
-
result = { error: error['form_errors']['og_group_ref][und][0][default'] }
|
207
|
-
end
|
208
|
-
else
|
209
|
-
result = error
|
210
|
-
end
|
211
|
-
valid = false
|
212
|
-
when '500'
|
213
|
-
puts " Error Code: #{api_response.code}"
|
214
|
-
result = { error: api_response.message }
|
215
|
-
# fail 'server exception'
|
216
|
-
valid = false
|
217
|
-
else
|
218
|
-
puts " Response: #{api_response.code} - #{api_response.body}"
|
219
|
-
valid = false
|
220
|
-
end
|
221
|
-
|
222
|
-
[valid, result]
|
223
|
-
end
|
224
|
-
|
225
|
-
# Construct the post parameter for the API content.json end point.
|
226
|
-
# param(@update) is a boolean that triggers whether to use content_type or uuid
|
227
|
-
def construct_post_data(filepath, update, content_type_or_uuid)
|
228
|
-
# TODO: remove special characters in the filename; they create firewall errors
|
229
|
-
# filename = filename.gsub(/\W/,'_').gsub(/___/,'_').gsub(/__/,'_').chomp('_').strip
|
230
|
-
|
231
|
-
file_b64 = Base64.encode64(File.binread(filepath))
|
232
|
-
|
233
|
-
data = {}
|
234
|
-
data['file'] = {
|
235
|
-
'file' => file_b64,
|
236
|
-
'filesize' => File.size(filepath).to_s,
|
237
|
-
'filename' => File.basename(filepath)
|
238
|
-
}
|
239
|
-
|
240
|
-
data['node'] = {}
|
241
|
-
|
242
|
-
# Only include the content type if this is an update
|
243
|
-
if update
|
244
|
-
data['node']['uuid'] = content_type_or_uuid
|
245
|
-
else
|
246
|
-
data['node']['type'] = content_type_or_uuid
|
247
|
-
end
|
248
|
-
|
249
|
-
# TODO: remove this field_component_tags once BCL is fixed
|
250
|
-
data['node']['field_component_tags'] = { 'und' => '1289' }
|
251
|
-
data['node']['og_group_ref'] = { 'und' => ['target_id' => @group_id] }
|
252
|
-
|
253
|
-
# NOTE THIS ONLY WORKS IF YOU ARE A BCL SITE ADMIN
|
254
|
-
data['node']['publish'] = '1'
|
255
|
-
|
256
|
-
data
|
257
|
-
end
|
258
|
-
|
259
|
-
# pushes component to the bcl and publishes them (if logged-in as BCL Website Admin user).
|
260
|
-
# username, password, and group_id are set in the ~/.bcl/config.yml file
|
261
|
-
def push_content(filename_and_path, write_receipt_file, content_type)
|
262
|
-
raise 'Please login before pushing components' if @session.nil?
|
263
|
-
raise 'Do not have a valid access token; try again' if @access_token.nil?
|
264
|
-
|
265
|
-
data = construct_post_data(filename_and_path, false, content_type)
|
266
|
-
|
267
|
-
path = '/api/content.json'
|
268
|
-
headers = { 'Content-Type' => 'application/json', 'X-CSRF-Token' => @access_token, 'Cookie' => @session }
|
269
|
-
|
270
|
-
res = @http.post(path, JSON.dump(data), headers)
|
271
|
-
|
272
|
-
valid, json = evaluate_api_response(res)
|
273
|
-
|
274
|
-
if valid
|
275
|
-
# write out a receipt file into the same directory of the component with the same file name as
|
276
|
-
# the component
|
277
|
-
if write_receipt_file
|
278
|
-
File.open("#{File.dirname(filename_and_path)}/#{File.basename(filename_and_path, '.tar.gz')}.receipt", 'w') do |file|
|
279
|
-
file << Time.now.to_s
|
280
|
-
end
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
[valid, json]
|
285
|
-
end
|
286
|
-
|
287
|
-
# pushes updated content to the bcl and publishes it (if logged-in as BCL Website Admin user).
|
288
|
-
# username and password set in ~/.bcl/config.yml file
|
289
|
-
def update_content(filename_and_path, write_receipt_file, uuid = nil)
|
290
|
-
raise 'Please login before pushing components' unless @session
|
291
|
-
|
292
|
-
# get the UUID if zip or xml file
|
293
|
-
version_id = nil
|
294
|
-
if uuid.nil?
|
295
|
-
puts File.extname(filename_and_path).downcase
|
296
|
-
if filename_and_path.match?(/^.*.tar.gz$/i)
|
297
|
-
uuid, version_id = uuid_vid_from_tarball(filename_and_path)
|
298
|
-
puts "Parsed uuid out of tar.gz file with value #{uuid}"
|
299
|
-
end
|
300
|
-
else
|
301
|
-
# verify the uuid via regex
|
302
|
-
unless uuid.match?(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/)
|
303
|
-
raise "uuid of #{uuid} is invalid"
|
304
|
-
end
|
305
|
-
end
|
306
|
-
raise 'Please pass in a tar.gz file or pass in the uuid' unless uuid
|
307
|
-
|
308
|
-
data = construct_post_data(filename_and_path, true, uuid)
|
309
|
-
|
310
|
-
path = '/api/content.json'
|
311
|
-
headers = { 'Content-Type' => 'application/json', 'X-CSRF-Token' => @access_token, 'Cookie' => @session }
|
312
|
-
|
313
|
-
res = @http.post(path, JSON.dump(data), headers)
|
314
|
-
|
315
|
-
valid, json = evaluate_api_response(res)
|
316
|
-
|
317
|
-
if valid
|
318
|
-
# write out a receipt file into the same directory of the component with the same file name as
|
319
|
-
# the component
|
320
|
-
if write_receipt_file
|
321
|
-
File.open("#{File.dirname(filename_and_path)}/#{File.basename(filename_and_path, '.tar.gz')}.receipt", 'w') do |file|
|
322
|
-
file << Time.now.to_s
|
323
|
-
end
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
[valid, json]
|
328
|
-
end
|
329
|
-
|
330
|
-
def push_contents(array_of_components, skip_files_with_receipts, content_type)
|
331
|
-
logs = []
|
332
|
-
array_of_components.each do |comp|
|
333
|
-
receipt_file = File.dirname(comp) + '/' + File.basename(comp, '.tar.gz') + '.receipt'
|
334
|
-
log_message = ''
|
335
|
-
if skip_files_with_receipts && File.exist?(receipt_file)
|
336
|
-
log_message = "skipping because found receipt #{comp}"
|
337
|
-
puts log_message
|
338
|
-
else
|
339
|
-
log_message = "pushing content #{File.basename(comp, '.tar.gz')}"
|
340
|
-
puts log_message
|
341
|
-
valid, res = push_content(comp, true, content_type)
|
342
|
-
log_message += " #{valid} #{res.inspect.chomp}"
|
343
|
-
end
|
344
|
-
logs << log_message
|
345
|
-
end
|
346
|
-
|
347
|
-
logs
|
348
|
-
end
|
349
|
-
|
350
78
|
# Unpack the tarball in memory and extract the XML file to read the UUID and Version ID
|
351
79
|
def uuid_vid_from_tarball(path_to_tarball)
|
352
80
|
uuid = nil
|
@@ -406,43 +134,18 @@ module BCL
|
|
406
134
|
[uuid, vid]
|
407
135
|
end
|
408
136
|
|
409
|
-
def update_contents(array_of_tarball_components, skip_files_with_receipts)
|
410
|
-
logs = []
|
411
|
-
array_of_tarball_components.each do |comp|
|
412
|
-
receipt_file = File.dirname(comp) + '/' + File.basename(comp, '.tar.gz') + '.receipt'
|
413
|
-
log_message = ''
|
414
|
-
if skip_files_with_receipts && File.exist?(receipt_file)
|
415
|
-
log_message = "skipping update because found receipt #{File.basename(comp)}"
|
416
|
-
puts log_message
|
417
|
-
else
|
418
|
-
uuid, vid = uuid_vid_from_tarball(comp)
|
419
|
-
if uuid.nil?
|
420
|
-
log_message = "ERROR: uuid not found for #{File.basename(comp)}"
|
421
|
-
puts log_message
|
422
|
-
else
|
423
|
-
log_message = "pushing updated content #{File.basename(comp)}"
|
424
|
-
puts log_message
|
425
|
-
valid, res = update_content(comp, true, uuid)
|
426
|
-
log_message += " #{valid} #{res.inspect.chomp}"
|
427
|
-
end
|
428
|
-
end
|
429
|
-
logs << log_message
|
430
|
-
end
|
431
|
-
logs
|
432
|
-
end
|
433
|
-
|
434
137
|
def search_by_uuid(uuid, vid = nil)
|
435
138
|
full_url = '/api/search.json'
|
436
|
-
action = nil
|
437
139
|
|
438
140
|
# add api_version
|
439
|
-
if @api_version
|
440
|
-
|
141
|
+
if @api_version == 2.0
|
142
|
+
# uuid
|
143
|
+
full_url += "?api_version=#{@api_version}"
|
144
|
+
full_url += "&fq[]=ss_uuid:#{uuid}"
|
145
|
+
else
|
146
|
+
# uuid
|
147
|
+
full_url += "&fq=uuid:#{uuid}"
|
441
148
|
end
|
442
|
-
full_url += "?api_version=#{@api_version}"
|
443
|
-
|
444
|
-
# uuid
|
445
|
-
full_url += "&fq[]=ss_uuid:#{uuid}"
|
446
149
|
|
447
150
|
res = @http.get(full_url)
|
448
151
|
res = JSON.parse res.body
|
@@ -458,20 +161,9 @@ module BCL
|
|
458
161
|
else
|
459
162
|
content = content['component']
|
460
163
|
end
|
461
|
-
|
462
|
-
# TODO: check version_modified date if it exists?
|
463
|
-
if !vid.nil? && content['vuuid'] == vid
|
464
|
-
# no update needed
|
465
|
-
action = 'noop'
|
466
|
-
else
|
467
|
-
# vid doesn't match: update existing
|
468
|
-
action = 'update'
|
469
|
-
end
|
470
|
-
else
|
471
|
-
# no uuid found: push new
|
472
|
-
action = 'push'
|
473
164
|
end
|
474
|
-
|
165
|
+
|
166
|
+
content
|
475
167
|
end
|
476
168
|
|
477
169
|
# Simple method to search bcl and return the result as hash with symbols
|
@@ -492,22 +184,30 @@ module BCL
|
|
492
184
|
full_url += '*.json'
|
493
185
|
end
|
494
186
|
|
495
|
-
# add api_version
|
496
|
-
if @api_version
|
497
|
-
|
187
|
+
# add api_version (legacy NREL is 2.0, otherwise use new syntax and ignore version)
|
188
|
+
if @api_version.nil?
|
189
|
+
# see if we can extract it from filter_str:
|
190
|
+
tmp = filter_str.match(/api_version=\d{1,}.\d{1,}/)
|
191
|
+
if tmp
|
192
|
+
@api_version = tmp.to_s.gsub(/api_version=/, '').to_f
|
193
|
+
puts "@api_version from filter_str: #{@api_version}"
|
194
|
+
end
|
498
195
|
end
|
499
|
-
|
196
|
+
|
197
|
+
if @api_version == 2.0
|
198
|
+
full_url += "?api_version=#{@api_version}"
|
199
|
+
end
|
200
|
+
puts "@api_version: #{@api_version}"
|
500
201
|
|
501
202
|
# add filters
|
502
|
-
|
503
|
-
# strip out api_version from filters, if included
|
504
|
-
if filter_str.include? 'api_version='
|
505
|
-
filter_str = filter_str.gsub(
|
506
|
-
filter_str = filter_str.gsub(
|
203
|
+
if !filter_str.nil?
|
204
|
+
# strip out api_version from filters, if included & @api_version is defined
|
205
|
+
if (filter_str.include? 'api_version=')
|
206
|
+
filter_str = filter_str.gsub(/&api_version=\d{1,}.\d{1,}/, '')
|
207
|
+
filter_str = filter_str.gsub(/api_version=\d{1,}.\d{1,}/, '')
|
507
208
|
end
|
508
209
|
full_url = full_url + '&' + filter_str
|
509
210
|
end
|
510
|
-
|
511
211
|
# simple search vs. all results
|
512
212
|
if !all
|
513
213
|
puts "search url: #{full_url}"
|
@@ -556,14 +256,16 @@ module BCL
|
|
556
256
|
receipt_file = File.dirname(comp) + '/' + File.basename(comp, '.tar.gz') + '.receipt'
|
557
257
|
if File.exist?(receipt_file)
|
558
258
|
FileUtils.remove_file(receipt_file)
|
559
|
-
|
560
259
|
end
|
561
260
|
end
|
562
261
|
end
|
563
262
|
|
564
263
|
def list_all_measures
|
565
|
-
|
566
|
-
|
264
|
+
if @api_version == 2.0
|
265
|
+
json = search(nil, 'fq[]=bundle%3Anrel_measure&show_rows=100')
|
266
|
+
else
|
267
|
+
json = search(nil, 'fq=bundle%3Ameasure&show_rows=100')
|
268
|
+
end
|
567
269
|
json
|
568
270
|
end
|
569
271
|
|
@@ -591,93 +293,27 @@ module BCL
|
|
591
293
|
config_filename = File.expand_path('~/.bcl/config.yml')
|
592
294
|
|
593
295
|
if File.exist?(config_filename)
|
594
|
-
puts "loading config
|
296
|
+
puts "loading URL config from #{config_filename}"
|
595
297
|
@config = YAML.load_file(config_filename)
|
596
298
|
else
|
597
|
-
#
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
@config = YAML.load_file(config_filename)
|
299
|
+
# use default URL
|
300
|
+
@config = {
|
301
|
+
server: {
|
302
|
+
url: 'https://bcl.nrel.gov'
|
303
|
+
}
|
304
|
+
}
|
604
305
|
end
|
605
306
|
end
|
606
307
|
|
308
|
+
# unused
|
607
309
|
def default_yaml
|
608
310
|
settings = {
|
609
311
|
server: {
|
610
|
-
url: 'https://bcl.nrel.gov'
|
611
|
-
user: {
|
612
|
-
username: 'ENTER_BCL_USERNAME',
|
613
|
-
password: 'ENTER_BCL_PASSWORD',
|
614
|
-
group: 'ENTER_GROUP_ID'
|
615
|
-
}
|
312
|
+
url: 'https://bcl.nrel.gov'
|
616
313
|
}
|
617
314
|
}
|
618
315
|
|
619
316
|
settings
|
620
317
|
end
|
621
318
|
end
|
622
|
-
|
623
|
-
# TODO: make this extend the component_xml class (or create a super class around components)
|
624
|
-
|
625
|
-
def self.gather_components(component_dir, chunk_size = 0, delete_previousgather = false, destination = nil)
|
626
|
-
if destination.nil?
|
627
|
-
@dest_filename = 'components'
|
628
|
-
else
|
629
|
-
@dest_filename = destination
|
630
|
-
end
|
631
|
-
@dest_file_ext = 'tar.gz'
|
632
|
-
|
633
|
-
# store the starting directory
|
634
|
-
current_dir = Dir.pwd
|
635
|
-
|
636
|
-
# an array to hold reporting info about the batches
|
637
|
-
gather_components_report = []
|
638
|
-
|
639
|
-
# go to the directory containing the components
|
640
|
-
Dir.chdir(component_dir)
|
641
|
-
|
642
|
-
# delete any old versions of the component chunks
|
643
|
-
FileUtils.rm_rf('./gather') if delete_previousgather
|
644
|
-
|
645
|
-
# gather all the components into array
|
646
|
-
targzs = Pathname.glob('./**/*.tar.gz')
|
647
|
-
tar_cnt = 0
|
648
|
-
chunk_cnt = 0
|
649
|
-
targzs.each do |targz|
|
650
|
-
if chunk_size != 0 && (tar_cnt % chunk_size) == 0
|
651
|
-
chunk_cnt += 1
|
652
|
-
end
|
653
|
-
tar_cnt += 1
|
654
|
-
|
655
|
-
destination_path = "./gather/#{chunk_cnt}"
|
656
|
-
FileUtils.mkdir_p(destination_path)
|
657
|
-
destination_file = "#{destination_path}/#{File.basename(targz.to_s)}"
|
658
|
-
# puts "copying #{targz.to_s} to #{destination_file}"
|
659
|
-
FileUtils.cp(targz.to_s, destination_file)
|
660
|
-
end
|
661
|
-
|
662
|
-
# gather all the .tar.gz files into a single tar.gz
|
663
|
-
(1..chunk_cnt).each do |cnt|
|
664
|
-
currentdir = Dir.pwd
|
665
|
-
|
666
|
-
paths = []
|
667
|
-
Pathname.glob("./gather/#{cnt}/*.tar.gz").each do |pt|
|
668
|
-
paths << File.basename(pt.to_s)
|
669
|
-
end
|
670
|
-
|
671
|
-
Dir.chdir("./gather/#{cnt}")
|
672
|
-
destination = "#{@dest_filename}_#{cnt}.#{@dest_file_ext}"
|
673
|
-
puts "tarring batch #{cnt} of #{chunk_cnt} to #{@dest_filename}_#{cnt}.#{@dest_file_ext}"
|
674
|
-
BCL.tarball(destination, paths)
|
675
|
-
Dir.chdir(currentdir)
|
676
|
-
|
677
|
-
# move the tarball back a directory
|
678
|
-
FileUtils.move("./gather/#{cnt}/#{destination}", "./gather/#{destination}")
|
679
|
-
end
|
680
|
-
|
681
|
-
Dir.chdir(current_dir)
|
682
|
-
end
|
683
319
|
end
|
data/lib/bcl/core_ext.rb
CHANGED
@@ -1,21 +1,7 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# This library is free software; you can redistribute it and/or
|
6
|
-
# modify it under the terms of the GNU Lesser General Public
|
7
|
-
# License as published by the Free Software Foundation; either
|
8
|
-
# version 2.1 of the License, or (at your option) any later version.
|
9
|
-
#
|
10
|
-
# This library is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
-
# Lesser General Public License for more details.
|
14
|
-
#
|
15
|
-
# You should have received a copy of the GNU Lesser General Public
|
16
|
-
# License along with this library; if not, write to the Free Software
|
17
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
-
######################################################################
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
+
# See also https://openstudio.net/license
|
4
|
+
# *******************************************************************************
|
19
5
|
|
20
6
|
class String
|
21
7
|
def to_underscore
|
data/lib/bcl/tar_ball.rb
CHANGED
@@ -1,65 +1,17 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# This library is free software; you can redistribute it and/or
|
6
|
-
# modify it under the terms of the GNU Lesser General Public
|
7
|
-
# License as published by the Free Software Foundation; either
|
8
|
-
# version 2.1 of the License, or (at your option) any later version.
|
9
|
-
#
|
10
|
-
# This library is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
-
# Lesser General Public License for more details.
|
14
|
-
#
|
15
|
-
# You should have received a copy of the GNU Lesser General Public
|
16
|
-
# License along with this library; if not, write to the Free Software
|
17
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
-
######################################################################
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
+
# See also https://openstudio.net/license
|
4
|
+
# *******************************************************************************
|
19
5
|
|
20
6
|
module BCL
|
21
7
|
module_function
|
22
8
|
|
23
|
-
# tarball multiple paths recursively to destination
|
24
|
-
def tarball(destination, paths)
|
25
|
-
# check for filepath length limit
|
26
|
-
full_destination = File.expand_path(destination)
|
27
|
-
if full_destination.length > 259 # 256 chars max; "C:\" doesn't count
|
28
|
-
puts "[TarBall] ERROR cannot generate #{destination} because path exceeds 256 char limit. shorten component name by at least by #{full_destination.length - 259} chars"
|
29
|
-
return
|
30
|
-
end
|
31
|
-
|
32
|
-
Zlib::GzipWriter.open(destination) do |gzip|
|
33
|
-
out = Archive::Tar::Minitar::Output.new(gzip)
|
34
|
-
|
35
|
-
paths.each do |fi|
|
36
|
-
if File.exist?(fi)
|
37
|
-
Archive::Tar::Minitar.pack_file(fi, out)
|
38
|
-
else
|
39
|
-
puts "[TarBall] ERROR Could not file file: #{fi}"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
out.close
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
9
|
def extract_tarball(filename, destination)
|
47
10
|
Zlib::GzipReader.open(filename) do |gz|
|
48
11
|
Archive::Tar::Minitar.unpack(gz, destination)
|
49
12
|
end
|
50
13
|
end
|
51
14
|
|
52
|
-
def create_zip(_destination, paths)
|
53
|
-
Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
|
54
|
-
paths.each do |fi|
|
55
|
-
# Two arguments:
|
56
|
-
# - The name of the file as it will appear in the archive
|
57
|
-
# - The original file, including the path to find it
|
58
|
-
zipfile.add(fi.basename, fi)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
15
|
def extract_zip(filename, destination, delete_zip = false)
|
64
16
|
Zip::File.open(filename) do |zip_file|
|
65
17
|
zip_file.each do |f|
|