bcl 0.1.9 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/bcl.rb +2 -0
- data/lib/bcl/bcl_xml.rb +130 -0
- data/lib/bcl/component_methods.rb +25 -29
- data/lib/bcl/component_spreadsheet.rb +9 -1
- data/lib/bcl/component_xml.rb +17 -130
- data/lib/bcl/current_taxonomy.json +0 -0
- data/lib/bcl/current_taxonomy.xml +5699 -1283
- data/lib/bcl/master_taxonomy.rb +476 -476
- data/lib/bcl/measure_xml.rb +54 -0
- data/lib/bcl/tar_ball.rb +17 -20
- data/lib/bcl/version.rb +1 -1
- metadata +27 -11
data/lib/bcl.rb
CHANGED
data/lib/bcl/bcl_xml.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'uuid' # gem install uuid
|
2
|
+
|
3
|
+
module BCL
|
4
|
+
ProvStruct = Struct.new(:author, :datetime, :comment)
|
5
|
+
TagsStruct = Struct.new(:descriptor)
|
6
|
+
AttrStruct = Struct.new(:name, :value, :datatype, :units)
|
7
|
+
FileStruct = Struct.new(:version_software_program, :version_id, :fqp_file, :filename, :filetype, :usage_type, :checksum)
|
8
|
+
CostStruct = Struct.new(:cost_name, :cost_type, :category, :value, :interval,
|
9
|
+
:interval_units, :year, :location, :units, :currency, :source,
|
10
|
+
:reference_component_name, :reference_component_id)
|
11
|
+
|
12
|
+
ObjectStruct = Struct.new(:obj_type, :obj_instance)
|
13
|
+
|
14
|
+
class BaseXml
|
15
|
+
attr_accessor :name
|
16
|
+
attr_accessor :description
|
17
|
+
attr_accessor :uuid
|
18
|
+
attr_accessor :vuid
|
19
|
+
|
20
|
+
attr_accessor :attributes
|
21
|
+
attr_accessor :files
|
22
|
+
attr_accessor :costs
|
23
|
+
attr_accessor :tags
|
24
|
+
attr_accessor :provenances
|
25
|
+
|
26
|
+
def initialize(save_path)
|
27
|
+
@name = "" #this is also a unique identifier to the component...
|
28
|
+
@description = ""
|
29
|
+
|
30
|
+
@provenances = []
|
31
|
+
@tags = []
|
32
|
+
@attributes = []
|
33
|
+
@files = []
|
34
|
+
|
35
|
+
@schema_url = "schema.xsd"
|
36
|
+
end
|
37
|
+
|
38
|
+
def generate_uuid()
|
39
|
+
@uuid = UUID.new.generate
|
40
|
+
end
|
41
|
+
|
42
|
+
def generate_vuid()
|
43
|
+
@vuid = UUID.new.generate
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def add_provenance(author, datetime, comment)
|
48
|
+
prov = ProvStruct.new
|
49
|
+
prov.author = author
|
50
|
+
prov.datetime = datetime
|
51
|
+
prov.comment = comment
|
52
|
+
|
53
|
+
@provenances << prov
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_tag(tag_name)
|
57
|
+
tag = TagsStruct.new
|
58
|
+
tag.descriptor = tag_name
|
59
|
+
|
60
|
+
@tags << tag
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_attribute(name, value, units, datatype = nil)
|
64
|
+
attr = AttrStruct.new
|
65
|
+
attr.name = name
|
66
|
+
attr.value = value
|
67
|
+
|
68
|
+
if !datatype.nil?
|
69
|
+
attr.datatype = datatype
|
70
|
+
else
|
71
|
+
attr.datatype = get_datatype(value)
|
72
|
+
end
|
73
|
+
attr.units = units
|
74
|
+
|
75
|
+
@attributes << attr
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_file(version_sp, version_id, fqp_file, filename, filetype, usage_type = nil, checksum = nil)
|
79
|
+
fs = FileStruct.new
|
80
|
+
fs.version_software_program = version_sp
|
81
|
+
fs.version_id = version_id
|
82
|
+
fs.fqp_file = fqp_file
|
83
|
+
fs.filename = filename
|
84
|
+
fs.filetype = filetype
|
85
|
+
fs.usage_type = usage_type if usage_type != nil
|
86
|
+
fs.checksum = checksum if checksum != nil
|
87
|
+
|
88
|
+
@files << fs
|
89
|
+
end
|
90
|
+
|
91
|
+
#return the title case of the string
|
92
|
+
def tc(input)
|
93
|
+
val = input.gsub(/\b\w/){$&.upcase}
|
94
|
+
if val.downcase == "energyplus"
|
95
|
+
val = "EnergyPlus"
|
96
|
+
end
|
97
|
+
return val
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_attribute(attribute_name)
|
101
|
+
result = nil
|
102
|
+
@attributes.each do |attr|
|
103
|
+
if attr.name == attribute_name
|
104
|
+
result = attr
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
result
|
109
|
+
end
|
110
|
+
|
111
|
+
def get_datatype(input_value)
|
112
|
+
dt = 'undefined'
|
113
|
+
|
114
|
+
# simple method to test if the input_value is a string, float, or integer.
|
115
|
+
# First convert the value back to a string for testing (in case it was passed as a float/integer)
|
116
|
+
test = input_value.to_s
|
117
|
+
input_value = test.match('\.').nil? ? Integer(test) : Float(test) rescue test.to_s
|
118
|
+
|
119
|
+
if input_value.is_a?(Fixnum) || input_value.is_a?(Bignum)
|
120
|
+
dt = "int"
|
121
|
+
elsif input_value.is_a?(Float)
|
122
|
+
dt = "float"
|
123
|
+
else
|
124
|
+
dt = "string"
|
125
|
+
end
|
126
|
+
|
127
|
+
dt
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -39,6 +39,7 @@ module BCL
|
|
39
39
|
def initialize()
|
40
40
|
@config = nil
|
41
41
|
@session = nil
|
42
|
+
@api_version = 2.0
|
42
43
|
config_path = File.expand_path('~') + '/.bcl'
|
43
44
|
config_name = 'config.yml'
|
44
45
|
if File.exists?(config_path + "/" + config_name)
|
@@ -79,6 +80,7 @@ module BCL
|
|
79
80
|
session_name = res_j["session_name"]
|
80
81
|
|
81
82
|
@session = { session_name => sessid }
|
83
|
+
|
82
84
|
end
|
83
85
|
|
84
86
|
res
|
@@ -88,7 +90,7 @@ module BCL
|
|
88
90
|
# pushes component to the bcl and sets to published (for now). Username and password and
|
89
91
|
# set in ~/.bcl/config.yml file which determines the permissions and the group to which
|
90
92
|
# the component will be uploaded
|
91
|
-
def
|
93
|
+
def push_content(filename_and_path, write_receipt_file, content_type)
|
92
94
|
raise "Please login before pushing components" if @session.nil?
|
93
95
|
|
94
96
|
valid = false
|
@@ -96,36 +98,24 @@ module BCL
|
|
96
98
|
filename = File.basename(filename_and_path)
|
97
99
|
filepath = File.dirname(filename_and_path) + "/"
|
98
100
|
|
99
|
-
|
100
|
-
file = File.open(filename_and_path, 'r')
|
101
|
+
file = File.open(filename_and_path, 'rb')
|
101
102
|
file_b64 = Base64.encode64(file.read)
|
102
103
|
@data = {"file" =>
|
103
104
|
{
|
104
105
|
"file" => "#{file_b64}",
|
105
106
|
"filesize" => "#{File.size(filename_and_path)}",
|
106
107
|
"filename" => filename
|
107
|
-
}
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
if res.code == 200
|
113
|
-
fid = JSON.parse(res.body)["fid"]
|
114
|
-
|
115
|
-
#post the node now with reference to this fid
|
116
|
-
@data = {"node" =>
|
117
|
-
{"type" => "nrel_component",
|
118
|
-
"status" => 1, #NOTE THIS ONLY WORKS IF YOU ARE ADMIN
|
119
|
-
"field_tar_file" =>
|
120
|
-
{"und" => [
|
121
|
-
{"fid" => fid}
|
122
|
-
]
|
123
|
-
}
|
108
|
+
},
|
109
|
+
"node" =>
|
110
|
+
{
|
111
|
+
"type" => "#{content_type}"#,
|
112
|
+
#"status" => 1 #NOTE THIS ONLY WORKS IF YOU ARE ADMIN
|
124
113
|
}
|
125
|
-
|
126
|
-
|
127
|
-
res = RestClient.post "http://#{@config[:server][:url]}/api/node", @data.to_json, :content_type => :json, :cookies => @session, :accept => :json
|
114
|
+
}
|
128
115
|
|
116
|
+
res = RestClient.post "http://#{@config[:server][:url]}/api/content", @data.to_json, :content_type => :json, :cookies => @session, :accept => :json
|
117
|
+
|
118
|
+
if res.code == 200
|
129
119
|
res_j = JSON.parse(res.body)
|
130
120
|
|
131
121
|
if res.code == 200
|
@@ -153,7 +143,7 @@ module BCL
|
|
153
143
|
[valid, res_j]
|
154
144
|
end
|
155
145
|
|
156
|
-
def
|
146
|
+
def push_contents(array_of_components, skip_files_with_receipts, content_type)
|
157
147
|
logs = []
|
158
148
|
array_of_components.each do |comp|
|
159
149
|
receipt_file = File.dirname(comp) + "/" + File.basename(comp, '.tar.gz') + ".receipt"
|
@@ -163,23 +153,29 @@ module BCL
|
|
163
153
|
else
|
164
154
|
log_message = "pushing component #{comp}: "
|
165
155
|
puts log_message
|
166
|
-
valid, res =
|
156
|
+
valid, res = push_content(comp, true, content_type)
|
167
157
|
log_message += " #{valid} #{res.inspect.chomp}"
|
168
158
|
end
|
169
|
-
puts log_message
|
170
159
|
logs << log_message
|
171
160
|
end
|
172
161
|
|
173
162
|
logs
|
174
163
|
end
|
175
164
|
|
165
|
+
# Simple method to search bcl and return the result as an XML object
|
166
|
+
def search(search_str)
|
167
|
+
full_url = "http://#{@config[:server][:url]}/api/search/#{search_str}&api_version=#{@api_version}"
|
168
|
+
res = RestClient.get "#{full_url}"
|
169
|
+
xml = LibXML::XML::Document.string(res.body)
|
170
|
+
|
171
|
+
xml
|
172
|
+
end
|
173
|
+
|
176
174
|
end
|
177
175
|
|
178
176
|
# TODO make this extend the component_xml class (or create a super class around components)
|
179
177
|
|
180
|
-
|
181
|
-
|
182
|
-
def gather_components(component_dir, chunk_size = 0, delete_previous_gather = false)
|
178
|
+
def BCL.gather_components(component_dir, chunk_size = 0, delete_previous_gather = false)
|
183
179
|
@dest_filename = "components"
|
184
180
|
@dest_file_ext = "tar.gz"
|
185
181
|
|
@@ -178,6 +178,13 @@ end # if $have_win32ole
|
|
178
178
|
filename = values.delete_at(0)
|
179
179
|
filetype = values.delete_at(0)
|
180
180
|
filepath = values.delete_at(0)
|
181
|
+
#not all components(rows) have all files; skip if filename "" or nil
|
182
|
+
next if filename == "" or filename == nil
|
183
|
+
#skip the file if it doesn't exist at the specified location
|
184
|
+
if not File.exists?(filepath)
|
185
|
+
puts "[ComponentSpreadsheet] ERROR #{filepath} -> File does not exist, will not be included in component xml"
|
186
|
+
next #go to the next file
|
187
|
+
end
|
181
188
|
component_xml.add_file(software_program, version, filepath, filename, filetype)
|
182
189
|
|
183
190
|
else
|
@@ -270,7 +277,8 @@ end # if $have_win32ole
|
|
270
277
|
component.uid = xlsx_worksheet.Range("B#{i}").value
|
271
278
|
if component.uid.nil? or component.uid.empty?
|
272
279
|
component.uid = UUID.new.generate
|
273
|
-
xlsx_worksheet.Range("B#{i}").value = component.uid
|
280
|
+
xlsx_worksheet.Range("B#{i}").value = component.uid
|
281
|
+
exit
|
274
282
|
end
|
275
283
|
|
276
284
|
# always write new version id
|
data/lib/bcl/component_xml.rb
CHANGED
@@ -28,51 +28,25 @@ require 'csv'
|
|
28
28
|
|
29
29
|
# required gems
|
30
30
|
require 'builder' #gem install builder (creates xml files)
|
31
|
-
|
31
|
+
|
32
32
|
require 'bcl/tar_ball'
|
33
|
+
require 'bcl/bcl_xml'
|
33
34
|
|
34
35
|
|
35
36
|
module BCL
|
36
|
-
|
37
|
-
SCHEMA_LOCATION = "component.xsd"
|
38
|
-
|
39
|
-
ProvStruct = Struct.new(:author, :datetime, :comment)
|
40
|
-
TagsStruct = Struct.new(:descriptor)
|
41
|
-
AttrStruct = Struct.new(:name, :value, :datatype, :units)
|
42
|
-
FileStruct = Struct.new(:version_software_program, :version_id, :fqp_file, :filename, :filetype)
|
43
|
-
#cost_type is an enumeration (not enforced) of installation, material, operations and maintenance,
|
44
|
-
#variable operations and maintenance, salvage
|
45
|
-
CostStruct = Struct.new(:cost_name, :cost_type, :category, :value, :interval,
|
46
|
-
:interval_units, :year, :location, :units, :currency, :source,
|
47
|
-
:reference_component_name, :reference_component_id)
|
48
|
-
ObjectStruct = Struct.new(:obj_type, :obj_instance)
|
49
|
-
|
50
|
-
class Component
|
51
|
-
attr_accessor :name
|
52
|
-
attr_accessor :uid
|
53
|
-
attr_accessor :comp_version_id
|
54
|
-
attr_accessor :description
|
37
|
+
class Component < BaseXml
|
55
38
|
attr_accessor :comment
|
56
39
|
attr_accessor :source_manufacturer
|
57
40
|
attr_accessor :source_model
|
58
41
|
attr_accessor :source_serial_no
|
59
42
|
attr_accessor :source_year
|
60
43
|
attr_accessor :source_url
|
61
|
-
attr_accessor :tags
|
62
|
-
attr_accessor :provenance
|
63
|
-
attr_accessor :attributes
|
64
|
-
attr_accessor :files
|
65
|
-
attr_accessor :costs
|
66
44
|
attr_accessor :objects
|
67
45
|
|
68
|
-
public
|
69
|
-
|
70
46
|
#the save path is where the component will be saved
|
71
47
|
def initialize(save_path)
|
72
|
-
|
73
|
-
|
74
|
-
@comp_version_id = UUID.new.generate
|
75
|
-
@description = ""
|
48
|
+
super(save_path)
|
49
|
+
|
76
50
|
@comment = ""
|
77
51
|
@source_manufacturer = ""
|
78
52
|
@source_model = ""
|
@@ -81,23 +55,17 @@ module BCL
|
|
81
55
|
@source_url = ""
|
82
56
|
|
83
57
|
#these items have multiple instances
|
84
|
-
|
85
|
-
@tags = []
|
86
|
-
@attributes = []
|
87
|
-
@files = []
|
58
|
+
|
88
59
|
@costs = []
|
89
60
|
@objects = [] #container for saving the idf/osm snippets
|
90
61
|
|
91
62
|
@path = save_path
|
92
63
|
|
93
|
-
#puts "[ComponentXml] " + @path
|
94
|
-
#need to hit a webservice to validate which tags and attributes are
|
95
|
-
#available (including units?)
|
96
|
-
|
97
64
|
#todo: validate against master taxonomy
|
98
65
|
end
|
99
66
|
|
100
|
-
|
67
|
+
# TODO This isn't implemented at the moment
|
68
|
+
def open_component_xml(filename)
|
101
69
|
read_component_xml(filename)
|
102
70
|
end
|
103
71
|
|
@@ -152,49 +120,6 @@ module BCL
|
|
152
120
|
#puts "[ComponentXml] " + Dir.pwd
|
153
121
|
end
|
154
122
|
|
155
|
-
def add_provenance(author, datetime, comment)
|
156
|
-
prov = ProvStruct.new
|
157
|
-
prov.author = author
|
158
|
-
prov.datetime = datetime
|
159
|
-
prov.comment = comment
|
160
|
-
|
161
|
-
@provenance << prov
|
162
|
-
end
|
163
|
-
|
164
|
-
def add_tag(tag_name)
|
165
|
-
tag = TagsStruct.new
|
166
|
-
tag.descriptor = tag_name
|
167
|
-
|
168
|
-
@tags << tag
|
169
|
-
end
|
170
|
-
|
171
|
-
def add_attribute(name, value, units, datatype = nil)
|
172
|
-
attr = AttrStruct.new
|
173
|
-
attr.name = name
|
174
|
-
attr.value = value
|
175
|
-
|
176
|
-
if !datatype.nil?
|
177
|
-
attr.datatype = datatype
|
178
|
-
else
|
179
|
-
attr.datatype = get_datatype(value)
|
180
|
-
end
|
181
|
-
attr.units = units
|
182
|
-
|
183
|
-
@attributes << attr
|
184
|
-
end
|
185
|
-
|
186
|
-
def add_file(version_sp, version_id, fqp_file, filename, filetype)
|
187
|
-
fs = FileStruct.new
|
188
|
-
fs.version_software_program = version_sp
|
189
|
-
fs.version_id = version_id
|
190
|
-
fs.fqp_file = fqp_file
|
191
|
-
fs.filename = filename
|
192
|
-
fs.filetype = filetype
|
193
|
-
|
194
|
-
@files << fs
|
195
|
-
end
|
196
|
-
|
197
|
-
|
198
123
|
def add_cost(cost_name, cost_type, category, value, units, interval, interval_units, year, location, currency,
|
199
124
|
source, reference_component_name, reference_component_id)
|
200
125
|
cs = CostStruct.new
|
@@ -325,21 +250,26 @@ module BCL
|
|
325
250
|
end
|
326
251
|
|
327
252
|
def save_component_xml(dir_path = resolve_path)
|
253
|
+
FileUtils.mkpath(dir_path) if !File.exists?(dir_path)
|
254
|
+
|
255
|
+
generate_uuid() if @uuid.nil?
|
256
|
+
generate_vuid() if @vuid.nil?
|
257
|
+
|
328
258
|
xmlfile = File.new(dir_path + '/component.xml', 'w')
|
329
259
|
comp_xml = Builder::XmlMarkup.new(:target => xmlfile, :indent=>2)
|
330
260
|
|
331
261
|
#setup the xml file
|
332
262
|
comp_xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
333
263
|
comp_xml.component("xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
|
334
|
-
"xsi:noNamespaceSchemaLocation"=>"#{
|
264
|
+
"xsi:noNamespaceSchemaLocation"=>"#{@schema_url}") {
|
335
265
|
comp_xml.name @name
|
336
|
-
comp_xml.uid @
|
337
|
-
comp_xml.version_id @
|
266
|
+
comp_xml.uid @uuid
|
267
|
+
comp_xml.version_id @vuid
|
338
268
|
comp_xml.description @description if @description != ""
|
339
269
|
comp_xml.comment @comment if @comment != ""
|
340
270
|
|
341
271
|
comp_xml.provenances {
|
342
|
-
@
|
272
|
+
@provenances.each do |prov|
|
343
273
|
comp_xml.provenance {
|
344
274
|
comp_xml.author prov.author
|
345
275
|
comp_xml.datetime prov.datetime
|
@@ -428,49 +358,6 @@ module BCL
|
|
428
358
|
|
429
359
|
xmlfile.close
|
430
360
|
end
|
431
|
-
|
432
|
-
def get_attribute(attribute_name)
|
433
|
-
result = nil
|
434
|
-
@attributes.each do |attr|
|
435
|
-
if attr.name == attribute_name
|
436
|
-
result = attr
|
437
|
-
end
|
438
|
-
end
|
439
|
-
|
440
|
-
result
|
441
|
-
|
442
|
-
end
|
443
|
-
|
444
|
-
#return the title case of the string
|
445
|
-
def tc(input)
|
446
|
-
val = input.gsub(/\b\w/){$&.upcase}
|
447
|
-
if val.downcase == "energyplus"
|
448
|
-
val = "EnergyPlus"
|
449
|
-
end
|
450
|
-
return val
|
451
|
-
end
|
452
|
-
|
453
|
-
private
|
454
|
-
|
455
|
-
def get_datatype(input_value)
|
456
|
-
dt = 'undefined'
|
457
|
-
|
458
|
-
# simple method to test if the input_value is a string, float, or integer.
|
459
|
-
# First convert the value back to a string for testing (in case it was passed as a float/integer)
|
460
|
-
test = input_value.to_s
|
461
|
-
input_value = test.match('\.').nil? ? Integer(test) : Float(test) rescue test.to_s
|
462
|
-
|
463
|
-
if input_value.is_a?(Fixnum) || input_value.is_a?(Bignum)
|
464
|
-
dt = "int"
|
465
|
-
elsif input_value.is_a?(Float)
|
466
|
-
dt = "float"
|
467
|
-
else
|
468
|
-
dt = "string"
|
469
|
-
end
|
470
|
-
|
471
|
-
dt
|
472
|
-
end
|
473
|
-
|
474
361
|
end
|
475
362
|
|
476
363
|
end # module BCL
|