cloud_powers 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -228,24 +228,102 @@ module Smash
228
228
  def self.storage_stub(opts = {})
229
229
  {
230
230
  stub_responses: {
231
- head_bucket: {
232
-
231
+ head_bucket: {},
232
+ get_object: {
233
+ body: "require 'cloud_powers'\nclass Testinz; end\n"
233
234
  },
234
235
  list_objects: {
235
236
  is_truncated: false,
236
237
  contents: [
237
- key: 'testinz',
238
- last_modified: Time.now,
239
- etag: 'asdf1234',
240
- size: 123,
241
- storage_class: 'STANDARD',
242
- owner: {display_name: 'snargle', id: 'id-bargle132'}
238
+ {
239
+ key: 'testinz.rb',
240
+ last_modified: Time.now,
241
+ etag: 'asdf1234',
242
+ size: 123,
243
+ storage_class: 'STANDARD',
244
+ owner: { display_name: 'snargle', id: 'id-bargle132' }
245
+ },
246
+ {
247
+ key: 'file1',
248
+ last_modified: Time.now,
249
+ etag: 'etagerino1',
250
+ size: 1231,
251
+ storage_class: 'STANDARD',
252
+ },
253
+ {
254
+ key: 'file2',
255
+ last_modified: Time.now,
256
+ etag: 'etagerino2',
257
+ size: 1232,
258
+ storage_class: 'STANDARD'
259
+ },
260
+ {
261
+ key: 'file3',
262
+ last_modified: Time.now,
263
+ etag: 'etagerino3',
264
+ size: 1233,
265
+ storage_class: 'STANDARD'
266
+ }
243
267
  ],
244
268
  name: 'testFile',
245
269
  prefix: 'test',
246
- delimiter: ' ',
270
+ delimiter: '/',
247
271
  max_keys: 1234,
248
- common_prefixes: [{ prefix: 'test' }]
272
+ common_prefixes: [{ prefix: 'test' }, { prefix: '/' }, { prefix: ''}]
273
+ },
274
+ list_buckets: {
275
+ buckets: [
276
+ { creation_date: Time.now, name: (opts[:bucket] || 'test') },
277
+ { creation_date: Time.now, name: (opts[:bucket1] || 'test_bucket1') },
278
+ { creation_date: Time.now, name: (opts[:bucket2] || 'jobs') },
279
+ { creation_date: Time.now, name: (opts[:bucket3] || 'workflows') },
280
+ { creation_date: Time.now, name: (opts[:bucket4] || 'results') },
281
+ { creation_date: Time.now, name: (opts[:bucket5] || 'cloudPowers') },
282
+ { creation_date: Time.now, name: (opts[:bucket6] || 'cloud_powers') },
283
+ { creation_date: Time.now, name: (opts[:bucket7] || 'testBucket') },
284
+ { creation_date: Time.now, name: (opts[:bucket8] || 'zlib') }
285
+ ],
286
+ owner: {display_name: 'snargle', id: 'id-bargle132'}
287
+ },
288
+ list_objects_v2: {
289
+ is_truncated: false,
290
+ contents: [
291
+ { key: 'file1',
292
+ last_modified: Time.now,
293
+ etag: 'etagerino1',
294
+ size: 1231,
295
+ storage_class: 'STANDARD'
296
+ },
297
+ { key: 'file2',
298
+ last_modified: Time.now,
299
+ etag: 'etagerino2',
300
+ size: 1232,
301
+ storage_class: 'STANDARD'
302
+ },
303
+ { key: 'file3',
304
+ last_modified: Time.now,
305
+ etag: 'etagerino3',
306
+ size: 1233,
307
+ storage_class: 'STANDARD'
308
+ },
309
+ {
310
+ key: 'testinz',
311
+ last_modified: Time.now,
312
+ etag: 'asdf1234',
313
+ size: 123,
314
+ storage_class: 'STANDARD',
315
+ owner: { display_name: 'snargle', id: 'id-bargle132' }
316
+ }
317
+ ],
318
+ name: 'name-what?',
319
+ prefix: opts[:prefix] || '/',
320
+ delimiter: opts[:delimiter] || '/',
321
+ max_keys: 9999999999,
322
+ encoding_type: 'String',
323
+ key_count: 3,
324
+ continuation_token: 'continuation-token-12345',
325
+ next_continuation_token: 'continuation-token-12346',
326
+ start_after: '0'
249
327
  }
250
328
  }
251
329
  }
@@ -17,17 +17,15 @@ module Smash
17
17
  @response = kinesis.create_stream(config)
18
18
  kinesis.wait_until(:stream_exists, stream_name: config[:stream_name])
19
19
  @response.successful? # (http request successful && stream created)?
20
- rescue Exception => e
21
- if e.kind_of? Aws::Kinesis::Errors::ResourceInUseException
22
- logger.info "#{name} already created"
23
- return if stream_status == 'ACTIVE'
24
- logger.info "Not ready for traffic. Wait for 30 seconds..."
25
- sleep 1
26
- @saved = true # acts like it would if it had to create the stream
27
- @linked = true
28
- else
29
- raise
30
- end
20
+ rescue Aws::Kinesis::Errors::ResourceInUseException => e
21
+ # TODO: write way more specs for these create methods.
22
+ # all of this logic is suspicious.
23
+ logger.info "#{name} already created"
24
+ return if stream_status == 'ACTIVE'
25
+ logger.info "Not ready for traffic..."
26
+ sleep 1
27
+ @saved = true # acts like it would if it had to create the stream
28
+ @linked = true
31
29
  end
32
30
  end
33
31
 
@@ -12,8 +12,9 @@ module Smash
12
12
  # It is basically just an abstraction to make using SQS simpler
13
13
  class Board < Smash::CloudPowers::Resource
14
14
  include Smash::CloudPowers::AwsResources
15
- include Smash::CloudPowers::Synapse::Queue
16
15
  include Smash::CloudPowers::Helpers
16
+ include Smash::CloudPowers::Storage
17
+ include Smash::CloudPowers::Synapse::Queue
17
18
  include Smash::CloudPowers::Zenv
18
19
 
19
20
  # The URL the Aws::SQS::Queue uses
@@ -84,6 +84,31 @@ module Smash
84
84
  %r{_board$} =~ base_name ? base_name : "#{base_name}_board"
85
85
  end
86
86
 
87
+ # Build a Smash::CloudPowers::Synapse::Queue and the getter and setter
88
+ # methods. This method uses the Creatable and Resource interface for
89
+ # consistency throughout CloudPowers.
90
+ #
91
+ # Parameters
92
+ # * +:name+ +String+ - the name of the Queue will be used to create
93
+ # a getter and setter. Please see <tt>CloudPowers::Creatable</tt>
94
+ # * +type+ +String+|+Symbol+ - Default is
95
+ # <tt>Smash::CloudPowers::Synapse::Queue::Board</tt>. As long as the
96
+ # type you request exists, you can use it but only the Classes that
97
+ # use <tt>CloudPowers::Creatable</tt> and extend from
98
+ # <tt>CloudPowers::Resource</tt> are supported. Please see
99
+ # <tt>CloudPowers::Creatable</tt> and <tt>CloudPowers::Resource</tt>
100
+ # * config +KeywordArgument+s - any config you want to pass along.
101
+ #
102
+ # Returns
103
+ # <tt>Smash::CloudPowers::Synapse::Queue[::?]</tt>
104
+ #
105
+ # Notes:
106
+ # * See <tt>create_queue</tt> to create the real object; e.g. an
107
+ # <tt>AWS::SQS::Queue</tt>. This method just creates a representation
108
+ # of that object in memory. It can be linked up to a real Object or
109
+ # left as is and used later.
110
+ # * See <tt>CloudPowers::Creatable</tt>
111
+ # * See <tt>CloudPowers::Resource</tt>
87
112
  def build_queue(name:, type: :board, **config)
88
113
  build_method_name = "build_#{type}"
89
114
  if self.respond_to? build_method_name
@@ -93,6 +118,34 @@ module Smash
93
118
  end
94
119
  end
95
120
 
121
+ # Create a <tt>Smash::CloudPowers::Synapse::Queue</tt>, the getter
122
+ # and setter methods and the real object, either out in the wild or right
123
+ # here, on disk; e.g. create an <tt>Aws::SQS::Queue</tt> in AWS and the
124
+ # appropriately mapped <tt>Smash::CloudPowers::Synapse::Queue[::?]</tt>
125
+ # object, locally to use in other methods, etc. This method uses the
126
+ # Creatable and Resource interface for consistency throughout CloudPowers.
127
+ #
128
+ # Parameters
129
+ # * +:name+ +String+ - the name of the Queue will be used to create
130
+ # a getter and setter. Please see <tt>CloudPowers::Creatable</tt>
131
+ # * +type+ +String+|+Symbol+ - Default is
132
+ # <tt>Smash::CloudPowers::Synapse::Queue::Board</tt>. As long as the
133
+ # type you request exists, you can use it but only the Classes that
134
+ # use <tt>CloudPowers::Creatable</tt> and extend from
135
+ # <tt>CloudPowers::Resource</tt> are supported. Please see
136
+ # <tt>CloudPowers::Creatable</tt> and <tt>CloudPowers::Resource</tt>
137
+ # * config +KeywordArgument+s - any config you want to pass along.
138
+ #
139
+ # Returns
140
+ # <tt>Smash::CloudPowers::Synapse::Queue[::?]</tt>
141
+ #
142
+ # Notes:
143
+ # * See <tt>build_queue</tt> to create the real object; e.g. an
144
+ # <tt>AWS::SQS::Queue</tt>. This method just creates a representation
145
+ # of that object in memory. It can be linked up to a real Object or
146
+ # left as is and used later.
147
+ # * See <tt>CloudPowers::Creatable</tt>
148
+ # * See <tt>CloudPowers::Resource</tt>
96
149
  def create_queue(name:, type: :board, **config)
97
150
  create_method_name = "build_#{type}"
98
151
  if self.respond_to? create_method_name
@@ -118,7 +171,7 @@ module Smash
118
171
  # => https://sqs.us-west-2.amazonaws.com/81234567/exampleQueue
119
172
  def build_board(name:, client: sqs, **config)
120
173
  board_resource = Smash::CloudPowers::Synapse::Queue::Board.build(
121
- name: to_camel(name), client: sqs
174
+ name: to_camel(name), client: client, **config
122
175
  )
123
176
 
124
177
  attr_map(board_resource.call_name => board_resource) do |attribute, resource|
@@ -324,6 +377,10 @@ module Smash
324
377
  # results.first =~ /exampleQueue/ # regex match against the URL
325
378
  def queue_search(name)
326
379
  urls = sqs.list_queues(queue_name_prefix: name).queue_urls
380
+ # TODO: allow a collection of blocks to be itterated through. Each one
381
+ # would be able to further scope down a set of previous results then
382
+ # pass it to the next. When there are no scoping blocks left, build
383
+ # the boards and return them. Saves a TON on memory and time
327
384
  urls.map do |url|
328
385
  build_board(name: queue_name(url), client: sqs) do |board|
329
386
  board.instance_attr_accessor :url
@@ -1,3 +1,3 @@
1
1
  module CloudPowers
2
- VERSION = '1.0.1'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -11,27 +11,6 @@ module Smash
11
11
  module Zenv
12
12
  include Smash::CloudPowers::Helpers
13
13
 
14
- # Attempts to find a file by searching the current directory for the file
15
- # then walking up the file tree and searching at each stop all the way up
16
- # to the root directory
17
- #
18
- # Parameters
19
- # * name +String+ - name of the file or directory to find
20
- #
21
- # Returns
22
- # +Pathname+ - path to the file or directory given as the +name+ parameter
23
- def file_tree_search(name)
24
- next_dir = Pathname.new(`pwd`.strip).parent
25
- current_dir = Pathname.new(`pwd`.strip)
26
- until(next_dir == current_dir) do
27
- path = Dir.glob("#{current_dir}/#{name}").first
28
- return current_dir unless path.nil?
29
- current_dir = next_dir
30
- next_dir = next_dir.parent
31
- end
32
- return nil
33
- end
34
-
35
14
  # Search through the {Dotenv}[https://github.com/bkeepers/dotenv]
36
15
  # variables for a key or if no key is given, return all the .env-vars
37
16
  # and their values
@@ -39,7 +18,7 @@ module Smash
39
18
  # Parameters
40
19
  # * key +String+ -
41
20
  def env_vars(key = '')
42
- return ENV if key.empty?
21
+ return ENV if key.empty? || key.nil?
43
22
  ENV[to_snake(key).upcase]
44
23
  end
45
24
 
@@ -54,18 +33,91 @@ module Smash
54
33
  name = to_i_var(key)
55
34
 
56
35
  # if no key is given, return a +Hash+ of all i-var/value pairs
57
- if key.empty?
58
- return self.instance_variables.inject({}) do |r, v|
59
- r.tap { |h| h[name] = self.instance_variable_get(name) }
36
+ if key.empty? || key.nil?
37
+ self.instance_variables.inject({}) do |r, v|
38
+ r.tap { |h| h[to_i_var(v)] = self.instance_variable_get(v.to_s) }
60
39
  end
40
+ else
41
+ self.instance_variable_get(name)
61
42
  end
43
+ end
62
44
 
63
- self.instance_variable_get(name)
45
+ # Get the PID for the current process
46
+ #
47
+ # Returns
48
+ # * +String+
49
+ #
50
+ # Notes
51
+ # * See <tt>::Process#pid()</tt>
52
+ def pid
53
+ Process.pid
54
+ end
55
+
56
+ def lsof_cwd
57
+ to_realpath((`lsof -p #{Process.pid} | grep cwd`).split(' ').last.strip)
64
58
  end
65
59
 
66
- # PROJECT_ROOT should be set as early as possible in this Node's initilize
67
- # method. This method tries to search for it, using #zfind() and if a `nil`
68
- # result is returned from that search, `pwd` is used as the PROJECT_ROOT.
60
+ def process_search
61
+ search_results = proc_cwd || lsof_cwd || ps_cwd || nil
62
+ paths_lcd(search_results, called_from)
63
+ end
64
+
65
+ # # Search the output of <tt>`ps ...`</tt> to find this process' working
66
+ # # directory
67
+ # #
68
+ # # Returns
69
+ # # * +Pathname+
70
+ # def path_resolution(one, two)
71
+ # logger.debug("path_resolution request from #{caller.first} as #{proc_cwd}")
72
+ # Pathname.new(sys_command_output).realpath
73
+ # end
74
+
75
+ # Ask <i>Linux</i> systems what directory the process is running from.
76
+ #
77
+ # Returns
78
+ # * +Pathname+ - the lcoation containing the file that was called to run
79
+ # this program
80
+ # * +nil+ - if the OS doesn't support the proc methods, +nil+ is returned
81
+ def proc_cwd
82
+ begin
83
+ to_realpath(`ls -l /proc/#{pid}/cwd`.split(/\->\s?/).last.strip)
84
+ rescue NoMethodError => e
85
+ logger.debug('this system does not support /proc files system queries')
86
+ nil
87
+ end
88
+ end
89
+
90
+ # Get the location of the current working directory for the project that
91
+ # is calling this method.
92
+ #
93
+ # Returns
94
+ # * +Pathname+
95
+ #
96
+ # Notes:
97
+ # * Tested on Ubuntu, Mac and Centos 7
98
+ # * Similar methods:
99
+ # * * <tt>proc_cwd</tt>
100
+ # * * <tt>called_from</tt>
101
+ def ps_cwd
102
+ begin
103
+ ef = `ps -ef | grep #{pid}`.split("\n").first.split(' ').last
104
+ aux = `ps aux | grep #{pid}`.split("\n").first.split(' ').last
105
+ Pathname.new(/[A-Za-z]*\.[A-Za-z]+$/ =~ ef ? ef : aux).realpath
106
+ rescue Exception => e
107
+ if e.nil?
108
+ logger.debug('This system does not support ps functionality')
109
+ nil
110
+ else
111
+ super
112
+ end
113
+ end
114
+ end
115
+
116
+ # <tt>PROJECT_ROOT</tt>, <tt>project_root= your_project_root</tt> or
117
+ # <tt>@project_root</tt> should be set as early as possible in this
118
+ # Node's initilize process. This method tries to search for it, using
119
+ # <tt>Zenv#zfind</tt> and if that fails, another search through system
120
+ # tools is run to make a best attempt at finding the lowest common path.
69
121
  #
70
122
  # Returns
71
123
  # +Pathname+ - path to the project root or where ever <tt>`pwd`</tt> resolves
@@ -76,21 +128,35 @@ module Smash
76
128
  # root or at least the gem's method's caller's file's location.
77
129
  #
78
130
  # Example
79
- # # called from cerebrum/cerebrum.rb in /home/ubuntu
80
- # project_root
131
+ # /home/ubuntu/cerebrum$ ruby -e cerebrum.rb 'Cerebrum.new.project_root'
81
132
  # # => '/home/ubuntu/cerebrum/'
82
- # # or
83
- # # called from go_nuts.rb#begin_going_crazy():(line -999999999.9) in /Users/crazyman/.ssh/why/all/the/madness/
133
+ # or
134
+ # <tt>project_root</tt> invoked from somewhere in
135
+ # <tt>/Users/crazyman/.ssh/why/all/the/wasted_time</tt>
136
+ # <tt>called_from</tt> is
137
+ # <tt>/Users/crazyman/.ssh/why/all/the/insanity/go_nuts.rb#ok():(line -999999999.9)</tt>
138
+ # and
139
+ # <tt>/proc/<pid>/cwd</tt> is /Users/crazyman/.ssh/why/all/the/madness/
140
+ # and
141
+ # # caller is
142
+ # [
143
+ # ... , /Users/crazyman/.rbenv/versions/2.4.0/lib/ruby/
144
+ # gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/hooks.rb, ...]</tt>
145
+ # and
146
+ # <tt>ps -ef | grep #{pid}...</tt> is <tt>[
147
+ # ..., /Users/crazyman/.rbenv/versions/2.4.0/lib/ruby/
148
+ # gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/hooks.rb, ...]</tt>
149
+ # then
84
150
  # project_root
85
- # # => '/Users/crazyman/.ssh/why/all/the/madness/'
151
+ # # => '/Users/crazyman/.ssh/why/all/the'
86
152
  def project_root
87
153
  if @project_root.nil?
88
- file_home = Pathname.new(
89
- caller_locations.first.path.strip.split(/\//).last).realdirpath.parent
90
- # path = (zfind('PROJECT_ROOT') or file_home)
91
- @project_root = Pathname.new(file_home)
154
+ new_root = to_realpath(zfind('project root') || process_search)
155
+ logger.info("project root set to:#{new_root} by:#{called_from}")
156
+ @project_root = new_root
157
+ else
158
+ @project_root
92
159
  end
93
- @project_root
94
160
  end
95
161
 
96
162
  # Manually set the +@project_root+ i-var as a +Pathname+ object.
@@ -99,7 +165,7 @@ module Smash
99
165
  # * +String+|+Pathname+ - new path to the project root
100
166
  #
101
167
  # Returns
102
- # +Pathname+ - +@project_root+
168
+ # +@project_root+ [+Pathname+]
103
169
  #
104
170
  # Example
105
171
  # project_root
@@ -107,8 +173,8 @@ module Smash
107
173
  # project_root = Pathname.new(`pwd`)
108
174
  # project_root == `pwd`
109
175
  # # => true
110
- def project_root=(var)
111
- @project_root = Pathname.new(var)
176
+ def project_root=(path)
177
+ @project_root = to_pathname(path).realpath
112
178
  end
113
179
 
114
180
  # Search through the system environment variables for a key or if no key
@@ -123,21 +189,7 @@ module Smash
123
189
  # with this structure +{ key => value, ... }+ is returned for all keys with a value.
124
190
  # Keys with no value are ommitted from the result.
125
191
  def system_vars(key = '')
126
- name = to_snake(key).upcase
127
- if key.empty?
128
- # Separate key-value pairs from the large string received by `ENV`
129
- separate_pairs = `ENV`.split(/\n/).map do |string_pair|
130
- string_pair.split('=')
131
- end
132
- # Separate key-value pairs from each other into a hash of
133
- # { key => value, other_key => other_value }
134
- # * keys with no value are removed
135
- separate_pairs.inject({}) do |res, pair|
136
- res.tap { |h_res| h_res[pair.first] = pair.last unless (pair.first == pair.last) }
137
- end
138
- else
139
- Object::ENV.has_key?(name) ? Object::ENV.fetch(name) : nil
140
- end
192
+ (key.empty? || key.nil?) ? ::ENV.to_h : ::ENV[to_snake(key).upcase]
141
193
  end
142
194
 
143
195
  # ZFind looks for the key in a preditermined order of importance:
@@ -152,14 +204,27 @@ module Smash
152
204
  # * key +String+|+Symbol+ - the key to search for
153
205
  #
154
206
  # Returns
155
- # * +String+
207
+ # * +Object+ - whatever type you were looking for, storing or accidentally
208
+ # now dealing with is what can be returned
156
209
  #
157
210
  # Notes
158
211
  # * TODO: implement a search for all 3 that can find close matches
159
- def zfind(key)
160
- project_root if @project_root.nil?
212
+ def zfind(key = '')
161
213
  i_vars(key) || env_vars(key) || system_vars(key)
162
214
  end
215
+
216
+ # Get anything that matches, within the same area that <tt>#zfind</tt>
217
+ # can search through. This has the feel of <tt>Hash#select</tt>./
218
+ def zselect(key = '')
219
+ vars = system_vars.merge(env_vars).merge(i_vars)
220
+ if (key.empty? || key.nil?)
221
+ vars.values
222
+ else
223
+ vars.select { |k,v| %r"#{to_snake(key)}" =~ to_snake(k) }.values
224
+ # results = vars.select { |k,v| %r"#{to_snake(key)}" =~ to_snake(k) }
225
+ # (results.count == 1) ? results.values.first : results
226
+ end
227
+ end
163
228
  end
164
229
  end
165
230
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloud_powers
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Phillipps
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2017-02-08 00:00:00.000000000 Z
13
+ date: 2017-03-18 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport-core-ext
@@ -100,30 +100,30 @@ dependencies:
100
100
  name: websocket-eventmachine-server
101
101
  requirement: !ruby/object:Gem::Requirement
102
102
  requirements:
103
- - - ">="
103
+ - - "~>"
104
104
  - !ruby/object:Gem::Version
105
- version: '0'
105
+ version: 1.0.1
106
106
  type: :runtime
107
107
  prerelease: false
108
108
  version_requirements: !ruby/object:Gem::Requirement
109
109
  requirements:
110
- - - ">="
110
+ - - "~>"
111
111
  - !ruby/object:Gem::Version
112
- version: '0'
112
+ version: 1.0.1
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: websocket-eventmachine-client
115
115
  requirement: !ruby/object:Gem::Requirement
116
116
  requirements:
117
- - - ">="
117
+ - - "~>"
118
118
  - !ruby/object:Gem::Version
119
- version: '0'
119
+ version: 1.2.0
120
120
  type: :runtime
121
121
  prerelease: false
122
122
  version_requirements: !ruby/object:Gem::Requirement
123
123
  requirements:
124
- - - ">="
124
+ - - "~>"
125
125
  - !ruby/object:Gem::Version
126
- version: '0'
126
+ version: 1.2.0
127
127
  - !ruby/object:Gem::Dependency
128
128
  name: workflow
129
129
  requirement: !ruby/object:Gem::Requirement
@@ -236,6 +236,7 @@ files:
236
236
  - lib/cloud_powers/auth.rb
237
237
  - lib/cloud_powers/aws_resources.rb
238
238
  - lib/cloud_powers/creatable.rb
239
+ - lib/cloud_powers/example_objects.rb
239
240
  - lib/cloud_powers/helpers.rb
240
241
  - lib/cloud_powers/helpers/lang_help.rb
241
242
  - lib/cloud_powers/helpers/logic_help.rb
@@ -246,9 +247,10 @@ files:
246
247
  - lib/cloud_powers/self_awareness.rb
247
248
  - lib/cloud_powers/smash_error.rb
248
249
  - lib/cloud_powers/storage.rb
250
+ - lib/cloud_powers/storage/bucket.rb
251
+ - lib/cloud_powers/storage/local.rb
249
252
  - lib/cloud_powers/stubs/aws_stubs.rb
250
253
  - lib/cloud_powers/synapse/broadcast.rb
251
- - lib/cloud_powers/synapse/broadcast/broadcast.rb
252
254
  - lib/cloud_powers/synapse/broadcast/channel.rb
253
255
  - lib/cloud_powers/synapse/pipe.rb
254
256
  - lib/cloud_powers/synapse/pipe/pipe.rb