fragrant 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +6 -0
  3. data/bin/fragrant +14 -0
  4. data/lib/fragrant/address_manager.rb +80 -0
  5. data/lib/fragrant/vagrantfile_generator.rb +64 -0
  6. data/lib/fragrant.rb +323 -0
  7. data/spec/fragrant/environments_spec.rb +18 -0
  8. data/spec/fragrant/vagrantfile_generator_spec.rb +40 -0
  9. data/spec/fragrant/vms_spec.rb +26 -0
  10. data/spec/spec_helper.rb +15 -0
  11. data/vendor/grape/LICENSE +20 -0
  12. data/vendor/grape/lib/grape/api.rb +420 -0
  13. data/vendor/grape/lib/grape/cookies.rb +41 -0
  14. data/vendor/grape/lib/grape/endpoint.rb +377 -0
  15. data/vendor/grape/lib/grape/entity.rb +378 -0
  16. data/vendor/grape/lib/grape/exceptions/base.rb +17 -0
  17. data/vendor/grape/lib/grape/exceptions/validation_error.rb +10 -0
  18. data/vendor/grape/lib/grape/middleware/auth/basic.rb +30 -0
  19. data/vendor/grape/lib/grape/middleware/auth/digest.rb +30 -0
  20. data/vendor/grape/lib/grape/middleware/auth/oauth2.rb +72 -0
  21. data/vendor/grape/lib/grape/middleware/base.rb +154 -0
  22. data/vendor/grape/lib/grape/middleware/error.rb +87 -0
  23. data/vendor/grape/lib/grape/middleware/filter.rb +17 -0
  24. data/vendor/grape/lib/grape/middleware/formatter.rb +81 -0
  25. data/vendor/grape/lib/grape/middleware/prefixer.rb +21 -0
  26. data/vendor/grape/lib/grape/middleware/versioner/header.rb +59 -0
  27. data/vendor/grape/lib/grape/middleware/versioner/param.rb +44 -0
  28. data/vendor/grape/lib/grape/middleware/versioner/path.rb +42 -0
  29. data/vendor/grape/lib/grape/middleware/versioner.rb +29 -0
  30. data/vendor/grape/lib/grape/route.rb +23 -0
  31. data/vendor/grape/lib/grape/util/deep_merge.rb +23 -0
  32. data/vendor/grape/lib/grape/util/hash_stack.rb +100 -0
  33. data/vendor/grape/lib/grape/validations/coerce.rb +61 -0
  34. data/vendor/grape/lib/grape/validations/presence.rb +11 -0
  35. data/vendor/grape/lib/grape/validations/regexp.rb +13 -0
  36. data/vendor/grape/lib/grape/validations.rb +192 -0
  37. data/vendor/grape/lib/grape/version.rb +3 -0
  38. data/vendor/grape/lib/grape.rb +44 -0
  39. metadata +216 -0
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2012 Matt Whiteley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,6 @@
1
+ * Top notes
2
+ - Wrap Vagrant actions in HTTP so we can execute from VMs
3
+ * Middle notes
4
+ - Quick
5
+ * Base notes
6
+ - Dirty
data/bin/fragrant ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ lib_dir = File.expand_path("../../lib", __FILE__)
5
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
6
+ require 'fragrant'
7
+ require 'rack/handler/puma'
8
+ require 'vegas'
9
+
10
+ app = Fragrant::Frontend.new
11
+ def app.server
12
+ "puma"
13
+ end
14
+ Vegas::Runner.new(app, 'fragrant', {:skip_launch => true, :app_dir => Fragrant.env_dir})
@@ -0,0 +1,80 @@
1
+ require 'ipaddr'
2
+ require 'json'
3
+
4
+ module Fragrant
5
+ AddressRangeExhausted = Class.new(StandardError)
6
+
7
+ class AddressManager
8
+ attr_accessor :data_location, :allocated_addresses
9
+ attr_accessor :address_range, :address_map
10
+
11
+ def initialize(data_location, address_range)
12
+ self.data_location = data_location
13
+ self.address_range = address_range
14
+ self.address_map = {}
15
+ self.allocated_addresses = []
16
+ load_address_data
17
+ end
18
+
19
+ def load_address_data
20
+ return unless File.exist?(data_location)
21
+ unless File.writable?(data_location)
22
+ raise "Unable to access IP address config file at #{data_location}"
23
+ end
24
+ File.open(data_location, 'rb') do |f|
25
+ data = JSON.parse(f.read)
26
+ self.address_range = data['address_range']
27
+ self.address_map = data['address_map']
28
+ self.allocated_addresses = data['allocated_addresses']
29
+ end
30
+ end
31
+
32
+ def address_data
33
+ {:address_range => address_range,
34
+ :allocated_addresses => allocated_addresses,
35
+ :address_map => address_map}
36
+ end
37
+
38
+ def first_available_address
39
+ ip = IPAddr.new(address_range).to_range.detect do |ip|
40
+ !allocated_addresses.include?(ip.to_s)
41
+ end
42
+ return ip.to_s if ip
43
+ raise AddressRangeExhausted, "No more addresses available in range #{address_range}"
44
+ end
45
+
46
+ def persist
47
+ dir = File.dirname(data_location)
48
+ FileUtils.mkdir_p(dir) unless File.directory?(dir)
49
+ File.open(data_location, 'wb') do |f|
50
+ f.write(address_data.to_json)
51
+ end
52
+ end
53
+
54
+ def claim_address(environment_id)
55
+ if address_map.key?(environment_id)
56
+ raise "#{environment_id} already has an address"
57
+ end
58
+ address = first_available_address
59
+ address_map[environment_id] = address
60
+ allocated_addresses << address
61
+ persist
62
+ address
63
+ end
64
+
65
+ def release_address(environment_id, ip)
66
+ unless address_map.key?(environment_id)
67
+ raise "No addresses registered to environment #{environment_id}"
68
+ end
69
+
70
+ address = address_map[environment_id]
71
+ unless address == ip
72
+ raise "IP #{ip} is not currently assigned to environment #{environment_id} (#{address} is)"
73
+ end
74
+
75
+ address_map.delete environment_id
76
+ allocated_addresses.delete ip
77
+ persist
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,64 @@
1
+ require 'fileutils'
2
+ require 'erb'
3
+
4
+ module Fragrant
5
+ class VagrantfileGenerator
6
+
7
+ attr_accessor :addresses
8
+
9
+ def self.template_path
10
+ File.expand_path('../../templates/Vagrantfile', __FILE__)
11
+ end
12
+
13
+ def initialize(target_directory, opts={})
14
+ @target_directory = target_directory
15
+ @scripts = opts[:scripts] || []
16
+ @addresses = opts[:addresses] || []
17
+ @box_name = opts[:box_name]
18
+ @box_url = opts[:box_url]
19
+ @contents = opts[:contents]
20
+ end
21
+
22
+ def box_name
23
+ @box_name || "precise32"
24
+ end
25
+
26
+ def box_url
27
+ @box_url || "http://files.vagrantup.com/precise32.box"
28
+ end
29
+
30
+ def add_script(contents)
31
+ raise "body set, adding a script not supported" if @contents
32
+ @scripts << contents
33
+ true
34
+ end
35
+
36
+ def writeable_scripts
37
+ retval = {}
38
+ @scripts.each_with_index do |contents, i|
39
+ retval[sprintf("script%03d", i + 1)] = contents
40
+ end
41
+ retval
42
+ end
43
+
44
+ def write
45
+ FileUtils.mkdir_p(@target_directory)
46
+
47
+ writeable_scripts.each do |filename, script_body|
48
+ File.open(File.join(@target_directory, filename), 'w') do |f|
49
+ f.print script_body
50
+ f.chmod 0755
51
+ end
52
+ end
53
+
54
+ @contents ||= Vagrant::Util::TemplateRenderer.render(self.class.template_path,
55
+ :box_name => box_name,
56
+ :box_url => box_url,
57
+ :provision_script_paths => writeable_scripts.keys.sort,
58
+ :addresses => addresses)
59
+ File.open(File.join(@target_directory, 'Vagrantfile'), 'w') { |f| f.print @contents }
60
+
61
+ true
62
+ end
63
+ end
64
+ end
data/lib/fragrant.rb ADDED
@@ -0,0 +1,323 @@
1
+ vendor_dir = File.expand_path('../../vendor', __FILE__)
2
+ $LOAD_PATH.unshift File.join(vendor_dir, 'grape', 'lib')
3
+ require 'grape'
4
+ require 'thread'
5
+ require 'fileutils'
6
+ require 'uuid'
7
+ require 'vagrant'
8
+ require 'fragrant/vagrantfile_generator'
9
+ require 'fragrant/address_manager'
10
+
11
+ module Fragrant
12
+ def self.env_dir
13
+ @env_dir ||= begin
14
+ dir = ENV["FRAGRANT_ENV_DIR"] || File.expand_path("~/.fragrant")
15
+ FileUtils.mkdir_p(dir)
16
+ dir
17
+ end
18
+ end
19
+
20
+ def self.address_manager
21
+ data_location = File.join(Fragrant.env_dir, "addresses.json")
22
+ range = ENV["FRAGRANT_IP_RANGE"] || "172.24.24.128/25"
23
+ @address_manager ||= AddressManager.new(data_location, range)
24
+ end
25
+
26
+ def self.add_task(task)
27
+ background_worker
28
+ tasks.push(task)
29
+ end
30
+
31
+ # Tasks are two-element Arrays of a machine id and a set of vagrant args
32
+ def self.tasks
33
+ @tasks ||= Queue.new
34
+ end
35
+
36
+ def self.create_worker_thread
37
+ thread = Thread.new do
38
+ Thread.current.abort_on_exception = true
39
+ until Thread.current[:shutdown] do
40
+ unless Fragrant.tasks.empty?
41
+ task = Fragrant.tasks.pop
42
+ env = Vagrant::Environment.new({ :cwd => File.join(env_dir, task[:id]) })
43
+ env.cli(task[:args])
44
+ end
45
+ end
46
+ end
47
+
48
+ at_exit do
49
+ $stderr.puts "Waiting for any running Vagrant tasks to complete."
50
+ thread[:shutdown] = true
51
+ thread.join
52
+ end
53
+ thread
54
+ end
55
+
56
+ def self.background_worker
57
+ @background_worker ||= create_worker_thread
58
+ end
59
+
60
+ class Frontend < Grape::API
61
+ version 'v1', :using => :header, :vendor => 'fragrant'
62
+ format :json
63
+
64
+ ENV_REGEX = /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/
65
+
66
+ rescue_from :all do |e|
67
+ rack_response({ :message => "Encountered exception: #{e}", :backtrace => e.backtrace }, 500, {"Content-Type" => "application/json"})
68
+ end
69
+
70
+ helpers do
71
+ def add_task(task)
72
+ Fragrant.add_task(task)
73
+ end
74
+
75
+ def box_name
76
+ params[:box_name] || 'precise32'
77
+ end
78
+
79
+ def box_url
80
+ params[:box_url] || "http://files.vagrantup.com/precise32.box"
81
+ end
82
+
83
+ def user_script
84
+ params[:user_data_script]
85
+ end
86
+
87
+ def env_dir
88
+ Fragrant.env_dir
89
+ end
90
+
91
+ def env_glob
92
+ Dir.entries(env_dir).select do |d|
93
+ next if d.start_with?('.')
94
+ File.exists?(File.join(env_dir, d, 'Vagrantfile'))
95
+ end
96
+ end
97
+
98
+ def env_rand
99
+ UUID.generate
100
+ end
101
+
102
+ def v_action
103
+ route.route_path.split(/[\/\(]/)[2]
104
+ end
105
+
106
+ def v_env(id = params[:id])
107
+ Vagrant::Environment.new({ :cwd => File.join(env_dir, id) })
108
+ end
109
+
110
+ def allocate_address(env_id)
111
+ Fragrant.address_manager.claim_address(env_id)
112
+ end
113
+
114
+ def v_file(env_id, directory, contents = nil)
115
+ addresses = [allocate_address(env_id)] unless contents
116
+ VagrantfileGenerator.new(directory, :box_name => box_name,
117
+ :box_url => box_url,
118
+ :scripts => Array(user_script),
119
+ :addresses => addresses,
120
+ :contents => contents).write
121
+ Array(addresses)
122
+ end
123
+
124
+ def make_machine_dir(machine_id)
125
+ machine_dir = File.join(env_dir, machine_id)
126
+ begin
127
+ Dir.mkdir(machine_dir, 0755)
128
+ rescue Errno::EEXIST
129
+ error!({ "error" => "#{machine_dir} already exists!" }, 409)
130
+ end
131
+ machine_dir
132
+ end
133
+ end
134
+
135
+ get do
136
+ {}
137
+ end
138
+
139
+ resource :environments do
140
+
141
+ desc "Destroys a Vagrant environment"
142
+ params do
143
+ requires :id, :desc => "Vagrant environment id", :type => String, regexp: ENV_REGEX
144
+ optional :vm_name, :desc => 'single vm to act on'
145
+ end
146
+ delete '/destroy/:id' do
147
+ args = [v_action, params[:vm_name], '--force']
148
+ v_env.cli(args.compact)
149
+ {:id => params[:id]}
150
+ end
151
+
152
+ desc "Lists Vagrant environments"
153
+ get :list do
154
+ env_glob
155
+ end
156
+
157
+ desc "Halts a Vagrant environment"
158
+ params do
159
+ requires :id, :desc => "Vagrant environment id", :type => String, regexp: ENV_REGEX
160
+ optional :force, :desc => 'Force shut down (equivalent of pulling power)'
161
+ optional :vm_name, :desc => 'single vm to act on'
162
+ end
163
+ post '/halt/:id' do
164
+ force = params[:force] == true ? '--force' : nil
165
+ args = [v_action, params[:vm_name], force]
166
+ v_env.cli(args.compact)
167
+ {:id => params[:id]}
168
+ end
169
+
170
+ desc "Initializes a Vagrant environment"
171
+ params do
172
+ optional :vagrantfile, :desc => "Vagrant environment configuration", :type => String
173
+ end
174
+ post :init do
175
+ machine = env_rand
176
+ machine_dir = File.join(env_dir, machine)
177
+ begin
178
+ Dir.mkdir(machine_dir, 0755)
179
+ rescue Errno::EEXIST
180
+ error!({ "error" => "#{machine_dir} already exists!" }, 409)
181
+ end
182
+ if params[:vagrantfile].nil?
183
+ v_env(machine).cli(v_action, box_name, box_url)
184
+ else
185
+ File.open(File.join(machine_dir, 'Vagrantfile'), 'w') {|f| f.write(params[:vagrantfile])}
186
+ end
187
+ {:id => machine}
188
+ end
189
+
190
+ desc "Provisions a Vagrant environment"
191
+ params do
192
+ requires :id, :desc => "Vagrant environment id", :type => String, regexp: ENV_REGEX
193
+ optional :vm_name, :desc => 'single vm to act on'
194
+ end
195
+ post '/provision/:id' do
196
+ args = [v_action, params[:vm_name]]
197
+ v_env.cli(args.compact)
198
+ {:id => params[:id]}
199
+ end
200
+
201
+ desc "Initialize and provision an environment, returns the environment id"
202
+ params do
203
+ requires :box_name, :desc => 'Name for box, used to lookup already loaded box', :type => String, :regexp => /^[\w_-]+$/
204
+ optional :box_url, :desc => 'URL for box location, optional iff \'box_name\' exists', :type => String
205
+ optional :user_data_script, :desc => 'Script to invoke upon provisioning'
206
+ end
207
+ post :create do
208
+ machine_id = env_rand
209
+ machine_dir = make_machine_dir(machine_id)
210
+ addresses = v_file machine_id, machine_dir
211
+ args = 'up', '--provision'
212
+ add_task(:id => machine_id, :args => args)
213
+ {:id => machine_id, :ips => addresses}
214
+ end
215
+
216
+ desc "Initializes a Vagrant environment"
217
+ params do
218
+ optional :vagrantfile, :desc => "Vagrant environment configuration", :type => String
219
+ end
220
+ post :init do
221
+ machine_id = env_rand
222
+ machine_dir = make_machine_dir(machine_id)
223
+ if params[:vagrantfile].nil?
224
+ v_env(machine_id).cli(v_action, box_name, box_url)
225
+ else
226
+ v_file(machine_id, machine_dir, params[:vagrantfile])
227
+ end
228
+ {:id => machine_id}
229
+ end
230
+
231
+ desc "Purges a Vagrant environment"
232
+ params do
233
+ requires :id, :desc => "Vagrant environment id", :type => String, regexp: ENV_REGEX
234
+ end
235
+ post '/purge/:id' do
236
+ if v_env.vms.all? {|vm| vm.last.state == 'not_created'}
237
+ machine_dir = File.join(env_dir, params[:id])
238
+ FileUtils.remove_entry_secure(machine_dir)
239
+ else
240
+ error!({ "error" => "Environment contains undestroyed machines!" }, 409)
241
+ end
242
+ {:id => params[:id]}
243
+ end
244
+
245
+ desc "Reloads a Vagrant environment"
246
+ params do
247
+ requires :id, :desc => "Vagrant environment id", :type => String, regexp: ENV_REGEX
248
+ optional :no_provision, :desc => 'disable provisioning'
249
+ optional :vm_name, :desc => 'single vm to act on'
250
+ end
251
+ post '/reload/:id' do
252
+ provision = params[:no_provision] == true ? '--no-provision' : '--provision'
253
+ args = [v_action, params[:vm_name], provision]
254
+ v_env.cli(args.compact)
255
+ {:id => params[:id]}
256
+ end
257
+
258
+ desc "Resumes a Vagrant environment"
259
+ params do
260
+ requires :id, :desc => "Vagrant environment id", :type => String, regexp: ENV_REGEX
261
+ optional :vm_name, :desc => 'single vm to act on'
262
+ end
263
+ post '/resume/:id' do
264
+ args = [v_action, params[:vm_name]]
265
+ v_env.cli(args.compact)
266
+ {:id => params[:id]}
267
+ end
268
+
269
+ desc "Prints the status of a Vagrant environment"
270
+ params do
271
+ requires :id, :desc => "Vagrant environment id", :type => String, regexp: ENV_REGEX
272
+ end
273
+ get '/status/:id' do
274
+ state = {}
275
+ v_env.vms.each do |vm|
276
+ state[vm.first] = vm.last.state
277
+ end
278
+ {:status => state}
279
+ end
280
+
281
+ desc "Suspends a Vagrant environment"
282
+ params do
283
+ requires :id, :desc => "Vagrant environment id", :type => String, regexp: ENV_REGEX
284
+ optional :vm_name, :desc => 'single vm to act on'
285
+ end
286
+ post '/suspend/:id' do
287
+ args = [v_action, params[:vm_name]]
288
+ v_env.cli(args.compact)
289
+ {:id => params[:id]}
290
+ end
291
+
292
+ desc "Boots a Vagrant environment"
293
+ params do
294
+ requires :id, :desc => "Vagrant environment id", :type => String, regexp: ENV_REGEX
295
+ optional :no_provision, :desc => 'disable provisioning'
296
+ optional :vm_name, :desc => 'single vm to act on'
297
+ end
298
+ post '/up/:id' do
299
+ provision = params[:no_provision] == true ? '--no-provision' : '--provision'
300
+ args = [v_action, params[:vm_name], provision]
301
+ v_env.cli(args.compact)
302
+ {:id => params[:id]}
303
+ end
304
+
305
+ end
306
+
307
+ resource :vms do
308
+
309
+ desc "Lists registered virtual machines"
310
+ get :registered do
311
+ out = %x{VBoxManage list vms}
312
+ {:vms => out.split('\n')}
313
+ end
314
+
315
+ desc "Lists running virtual machines"
316
+ get :running do
317
+ out = %x{VBoxManage list runningvms}
318
+ {:vms => out.split('\n')}
319
+ end
320
+
321
+ end
322
+ end
323
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fragrant do
4
+ include Rack::Test::Methods
5
+
6
+ def app
7
+ Fragrant::Frontend
8
+ end
9
+
10
+ describe "GET /environments/list" do
11
+ it "returns an array of Vagrant environments" do
12
+ get "/environments/list"
13
+ last_response.status.should == 200
14
+ JSON.parse(last_response.body).should be_kind_of(Array)
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+ require 'tempfile'
4
+
5
+ describe Fragrant::VagrantfileGenerator do
6
+ before do
7
+ @original_pwd = Dir.pwd
8
+ @working_directory = Dir.mktmpdir('fragrant-')
9
+ Dir.chdir @working_directory
10
+ end
11
+
12
+ after do
13
+ Dir.chdir @original_pwd
14
+ FileUtils.rm_rf @working_directory
15
+ end
16
+
17
+ it 'should create a Vagrantfile' do
18
+ v = Fragrant::VagrantfileGenerator.new(Dir.pwd)
19
+ v.write
20
+ File.exist?(File.join(Dir.pwd, 'Vagrantfile')).should be_true
21
+ end
22
+
23
+ describe 'with a provisioning script passed as an option' do
24
+ before do
25
+ v = Fragrant::VagrantfileGenerator.new(Dir.pwd)
26
+ @custom_script = "#!/not/really/bin/bash\nDo this thing!"
27
+ v.add_script @custom_script
28
+ v.write
29
+ end
30
+
31
+ it 'should write the provisioning script as a separate file' do
32
+ File.read(File.join(Dir.pwd, 'script001')).should == @custom_script
33
+ end
34
+
35
+ it 'should refer to the provisioning script in the Vagrantfile' do
36
+ vagrantfile = File.read(File.join(Dir.pwd, 'Vagrantfile'))
37
+ vagrantfile.split("\n").grep(/provision.*script001/).should_not be_empty
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fragrant do
4
+ include Rack::Test::Methods
5
+
6
+ def app
7
+ Fragrant::Frontend
8
+ end
9
+
10
+ describe "GET /vms/registered" do
11
+ it "returns an array of registered vms" do
12
+ get "/vms/registered"
13
+ last_response.status.should == 200
14
+ JSON.parse(last_response.body).should be_kind_of(Array)
15
+ end
16
+ end
17
+
18
+ describe "GET /vms/running" do
19
+ it "returns an array of running vms" do
20
+ get "/vms/running"
21
+ last_response.status.should == 200
22
+ JSON.parse(last_response.body).should be_kind_of(Array)
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ Bundler.setup :default, :test
6
+ require 'fragrant'
7
+ require 'rack/test'
8
+ require 'fileutils'
9
+
10
+ RSpec.configure do |config|
11
+ config.include Rack::Test::Methods
12
+ config.before do
13
+ FileUtils.mkdir_p(Fragrant.env_dir)
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Michael Bleigh and Intridea, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.