bcl 0.1.9 → 0.2.2

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.
data/lib/bcl.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'bcl/component_spreadsheet'
2
2
  require 'bcl/component_xml'
3
3
  require 'bcl/component_methods'
4
+ require 'bcl/measure_xml'
5
+ require 'bcl/bcl_xml'
4
6
  require 'bcl/tar_ball'
5
7
  require 'bcl/master_taxonomy'
6
8
  require 'bcl/mongo_to_component'
@@ -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 push_component(filename_and_path, write_receipt_file)
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
- # TODO: BCL will be moving over to single endpoint to manage the file upload and node creation (update eventually)
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
- res = RestClient.post "http://#{@config[:server][:url]}/api/file", @data.to_json, :content_type => :json, :cookies => @session, :accept => :json
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 push_components(array_of_components, skip_files_with_receipts)
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 = push_component(comp, true)
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
- module_function
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
@@ -28,51 +28,25 @@ require 'csv'
28
28
 
29
29
  # required gems
30
30
  require 'builder' #gem install builder (creates xml files)
31
- require 'uuid' # gem install uuid
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
- @name = "" #this is also a unique identifier to the component...
73
- @uid = UUID.new.generate
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
- @provenance = []
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
- def open_component(filename)
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"=>"#{SCHEMA_LOCATION}") {
264
+ "xsi:noNamespaceSchemaLocation"=>"#{@schema_url}") {
335
265
  comp_xml.name @name
336
- comp_xml.uid @uid
337
- comp_xml.version_id @comp_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
- @provenance.each do |prov|
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