chef-encrypted-attributes 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9152cd93c8d694d37df7659cae3d93bf00ae85f0
4
- data.tar.gz: 539393acaeef1511dd82dc035a38365ec012b043
3
+ metadata.gz: 9cdea59e2de10064ea5d0e3bc56bc81ceead120e
4
+ data.tar.gz: 0deb1f801ae0bf42f7f85b34f42240d213a45802
5
5
  SHA512:
6
- metadata.gz: 5a943ad2d06b15cd9d39a00c81da3907ecbf42e7e3a9c506db815296b32245203a3d1bd3e7076a4afd0aefb06576a43c34524abc938b61965c86c10c663f3b65
7
- data.tar.gz: 1f11c694453b7fc80717808159e81c242909fe2b18b271a45400d1bfd11c21fb696155978a5604eba048a5d6795caa70102f37ad9803de26f068fbd5a9b9667f
6
+ metadata.gz: 6c0cc800e8252f437349d0970b82182756bab2394f20de1504b8c5bd939cd692cb410b7435a9f3a139d334692fe204754eca21458002d793f1936a2b30f593f9
7
+ data.tar.gz: e2d69beb84580fb66183615c247a32035a872d62c74de1ca9ec313e87b50922defe13d2c71f84e7ac4f125f30d6cf036124f6da88f38dd0f11a3776e37d59fb2
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  This file is used to list changes made in each version of `chef-encrypted-attributes`.
4
4
 
5
+ ## 0.7.0 (2015-05-20)
6
+
7
+ * Move chef to dev dependency and remove dynamic dependency installation extension (related to [cookbook issue #2](https://github.com/onddo/encrypted_attributes-cookbook/pull/2#issuecomment-101454221) and [issue #2](https://github.com/onddo/chef-encrypted-attributes/pull/2), thanks [Lisa Danz](https://github.com/ldanz) for reporting).
8
+ * Fix search by node name to prevent returning incorrect nodes ([issue #3](https://github.com/onddo/chef-encrypted-attributes/pull/3), thanks [Crystal Hsiung](https://github.com/chhsiung) for the help).
9
+ * RuboCop update to `0.31.0`.
10
+ * README: Add a link to the cookbook helper libraries.
11
+
5
12
  ## 0.6.0 (2015-05-08)
6
13
 
7
14
  * Conditional gem dependency installation within a gemspec ([issue #2](https://github.com/onddo/chef-encrypted-attributes/pull/2), thanks [@chhsiung](https://github.com/chhsiung) for the help).
data/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
  [![Gem Version](http://img.shields.io/gem/v/chef-encrypted-attributes.svg?style=flat)](http://badge.fury.io/rb/chef-encrypted-attributes)
3
3
  [![Dependency Status](http://img.shields.io/gemnasium/onddo/chef-encrypted-attributes.svg?style=flat)](https://gemnasium.com/onddo/chef-encrypted-attributes)
4
4
  [![Code Climate](http://img.shields.io/codeclimate/github/onddo/chef-encrypted-attributes.svg?style=flat)](https://codeclimate.com/github/onddo/chef-encrypted-attributes)
5
- [![Build Status](http://img.shields.io/travis/onddo/chef-encrypted-attributes/0.6.0.svg?style=flat)](https://travis-ci.org/onddo/chef-encrypted-attributes)
6
- [![Coverage Status](http://img.shields.io/coveralls/onddo/chef-encrypted-attributes/0.6.0.svg?style=flat)](https://coveralls.io/r/onddo/chef-encrypted-attributes?branch=0.6.0)
5
+ [![Build Status](http://img.shields.io/travis/onddo/chef-encrypted-attributes/0.7.0.svg?style=flat)](https://travis-ci.org/onddo/chef-encrypted-attributes)
6
+ [![Coverage Status](http://img.shields.io/coveralls/onddo/chef-encrypted-attributes/0.7.0.svg?style=flat)](https://coveralls.io/r/onddo/chef-encrypted-attributes?branch=0.7.0)
7
7
  [![Inline docs](http://inch-ci.org/github/onddo/chef-encrypted-attributes.svg?branch=master&style=flat)](http://inch-ci.org/github/onddo/chef-encrypted-attributes)
8
8
 
9
9
  [Chef](https://www.chef.io/) plugin to add Node encrypted attributes support using client keys.
@@ -27,6 +27,8 @@ Node attributes are encrypted using chef client and user keys with public key in
27
27
 
28
28
  ## Usage in Recipes
29
29
 
30
+ Before reading all the documentation below, we recommend you take a look at the [`encrypted_attributes` cookbook's helper libraries](https://github.com/onddo/encrypted_attributes-cookbook#helper-libraries). Those libraries are easier to use than the underlying API and cover the most common use cases.
31
+
30
32
  ### Installing and Including the Gem
31
33
 
32
34
  You need to install and include the `chef-encrypted-attributes` gem before using encrypted attributes inside a cookbook.
@@ -79,7 +81,7 @@ Chef::Config[:encrypted_attributes][:client_search] = 'admin:true'
79
81
  Chef::Config[:encrypted_attributes][:node_search] = 'role:webapp'
80
82
 
81
83
  if Chef::EncryptedAttribute.exist?(node['myapp']['encrypted_data'])
82
- # when can used #load here as above if we need the `encrypted_data` outside
84
+ # we can used #load here as above if we need the `encrypted_data` outside
83
85
  # this `if`
84
86
 
85
87
  # update with the new keys
@@ -242,7 +244,7 @@ See [TODO.md](https://github.com/onddo/chef-encrypted-attributes/blob/master/TOD
242
244
  |:---------------------|:-----------------------------------------|
243
245
  | **Author:** | [Xabier de Zuazo](https://github.com/zuazo) (<xabier@onddo.com>)
244
246
  | **Contributor:** | [Josh Kalderimis](https://github.com/joshk)
245
- | **Contributor:** | [@chhsiung](https://github.com/chhsiung)
247
+ | **Contributor:** | [Crystal Hsiung](https://github.com/chhsiung)
246
248
  | **Contributor:** | [Lisa Danz](https://github.com/ldanz)
247
249
  | **Copyright:** | Copyright (c) 2014-2015 Onddo Labs, SL. (www.onddo.com)
248
250
  | **License:** | Apache License, Version 2.0
data/TODO.md CHANGED
@@ -1,6 +1,7 @@
1
1
  TODO
2
2
  ====
3
3
 
4
+ * Refactor `SearchHelper` class.
4
5
  * Fix all RuboCop offenses.
5
6
  * knife encrypted attribute create/edit from file.
6
7
  * Save config inside encrypted data: `:client_search`, `:node_search` and `:keys` (including user keys).
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
  #
3
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
4
- # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
4
+ # Copyright:: Copyright (c) 2014-2015 Onddo Labs, SL. (www.onddo.com)
5
5
  # License:: Apache License, Version 2.0
6
6
  #
7
7
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -76,7 +76,7 @@ class Chef
76
76
  cache_key = cache_key(name, attr_ary)
77
77
  return self.class.cache[cache_key] if self.class.cache.key?(cache_key)
78
78
  keys = { 'value' => attr_ary }
79
- res = search(:node, "name:#{@name}", keys, 1, partial_search)
79
+ res = search_by_name(:node, @name, keys, 1, partial_search)
80
80
  self.class.cache[cache_key] = parse_search_result(res)
81
81
  end
82
82
 
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
  #
3
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
4
- # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
4
+ # Copyright:: Copyright (c) 2014-2015 Onddo Labs, SL. (www.onddo.com)
5
5
  # License:: Apache License, Version 2.0
6
6
  #
7
7
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -119,6 +119,22 @@ class Chef
119
119
  query.is_a?(Array) && query.count == 0
120
120
  end
121
121
 
122
+ # Translates Chef HTTP exceptions to search exceptions.
123
+ #
124
+ # @yield [] the block doing the Chef Search.
125
+ # @return [Mixed] the value returned by the block.
126
+ # @api private
127
+ def catch_search_exceptions(&block)
128
+ block.call
129
+ rescue Net::HTTPServerException => e
130
+ unless e.response.is_a?(Net::HTTPResponse) && e.response.code == '404'
131
+ raise SearchFailure, "Search exception #{e.class}: #{e}"
132
+ end
133
+ return []
134
+ rescue Net::HTTPFatalError => e
135
+ raise SearchFailure, "Search exception #{e.class}: #{e}"
136
+ end
137
+
122
138
  # Does a search in the Chef Server.
123
139
  #
124
140
  # @param type [Symbol] search index to use. See [Chef Search Indexes]
@@ -138,14 +154,30 @@ class Chef
138
154
  def search(type, query, keys, rows = 1000, partial_search = true)
139
155
  return [] if empty_search?(query) # avoid empty searches
140
156
  search_method = partial_search ? :partial_search : :normal_search
141
- send(search_method, type, query, keys, rows)
142
- rescue Net::HTTPServerException => e
143
- unless e.response.is_a?(Net::HTTPResponse) && e.response.code == '404'
144
- raise SearchFailure, "Search exception #{e.class}: #{e}"
157
+ catch_search_exceptions do
158
+ send(search_method, type, nil, query, keys, rows)
159
+ end
160
+ end
161
+
162
+ # Does a search in the Chef Server by node or client name.
163
+ #
164
+ # @param type [Symbol] search index to use. See [Chef Search Indexes]
165
+ # (http://docs.getchef.com/chef_search.html#search-indexes).
166
+ # @param name [String] node name to search.
167
+ # @param keys [Hash] search keys structure. For example:
168
+ # `{ipaddress: %w(ipaddress), mysql_version: %w(mysql version) }`.
169
+ # @param rows [Fixnum, String] maximum number of rows to return.
170
+ # @param partial_search [Boolean] whether to use partial search.
171
+ # @return [Array<Hash>] An array with the response, for example:
172
+ # `[{ 'ipaddress' => '192.168.1.1' }]`
173
+ # @raise [SearchFailure] if there is a Chef search error.
174
+ # @raise [SearchFatalError] if the Chef search response is wrong.
175
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
176
+ def search_by_name(type, name, keys, rows = 1000, partial_search = true)
177
+ search_method = partial_search ? :partial_search : :normal_search
178
+ catch_search_exceptions do
179
+ send(search_method, type, name, "name:#{name}", keys, rows)
145
180
  end
146
- return []
147
- rescue Net::HTTPFatalError => e
148
- raise SearchFailure, "Search exception #{e.class}: #{e}"
149
181
  end
150
182
 
151
183
  # Assert that the normal (no partial) search response is correct.
@@ -177,16 +209,39 @@ class Chef
177
209
  end
178
210
  end
179
211
 
212
+ # Filters normal search results that do not correspond to the searched
213
+ # node.
214
+ #
215
+ # Used when searching by node name.
216
+ #
217
+ # @param resp [Array] normal search result.
218
+ # @param name [String, nil] searched node name.
219
+ # @return [Array] The search result removing the filtered results.
220
+ # @raise [SearchFatalError] if more than one result is returned when
221
+ # searching by node name.
222
+ # @api private
223
+ def filter_normal_search_response(resp, name)
224
+ return resp if name.nil?
225
+ resp.select { |row| row.name == name }.tap do |r|
226
+ fail SearchFatalError,
227
+ 'Multiple responses received from Partial Search:'\
228
+ " #{r.inspect}" if r.count > 1
229
+ end
230
+ end
231
+
180
232
  # Parses a normal (no partial) full search search response.
181
233
  #
182
234
  # @param resp [Array] normal search result.
183
235
  # @param keys [Hash] search keys structure. For example:
184
236
  # `{ipaddress: %w(ipaddress), mysql_version: %w(mysql version) }`.
237
+ # @param name [String, nil] searched node name.
185
238
  # @return [Array<Hash>] An array with the response, for example:
186
239
  # `[{ 'ipaddress' => '192.168.1.1' }]`
240
+ # @raise [SearchFatalError] if more than one result is returned when
241
+ # searching by node name.
187
242
  # @api private
188
- def parse_normal_search_response(resp, keys)
189
- resp.map do |row|
243
+ def parse_normal_search_response(resp, keys, name)
244
+ filter_normal_search_response(resp, name).map do |row|
190
245
  Hash[keys.map do |key_name, attr_ary|
191
246
  value = parse_normal_search_row_attribute(row, attr_ary)
192
247
  [key_name, value]
@@ -198,6 +253,7 @@ class Chef
198
253
  #
199
254
  # @param type [Symbol] search index to use. See [Chef Search Indexes]
200
255
  # (http://docs.getchef.com/chef_search.html#search-indexes).
256
+ # @param name [String, nil] searched node name.
201
257
  # @param query [String, Array<String>] search query. For example:
202
258
  # `%w(admin:true)`. Results will be *OR*-ed when multiple string queries
203
259
  # are provided.
@@ -207,7 +263,9 @@ class Chef
207
263
  # @return [Array<Hash>] An array with the response, for example:
208
264
  # `[{ 'ipaddress' => '192.168.1.1' }]`
209
265
  # @raise [InvalidSearchKeys] if search keys structure is wrong.
210
- def normal_search(type, query, keys, rows = 1000)
266
+ # @raise [SearchFatalError] if more than one result is returned when
267
+ # searching by node name.
268
+ def normal_search(type, name, query, keys, rows = 1000)
211
269
  escaped_query = escape_query(query)
212
270
  Chef::Log.info(
213
271
  "Normal Search query: #{escaped_query}, keys: #{keys.inspect}"
@@ -216,7 +274,7 @@ class Chef
216
274
 
217
275
  resp = self.query.search(type, escaped_query, nil, 0, rows)[0]
218
276
  assert_normal_search_response(resp)
219
- parse_normal_search_response(resp, keys)
277
+ parse_normal_search_response(resp, keys, name)
220
278
  end
221
279
 
222
280
  # Assert that the partial search response is correct.
@@ -233,18 +291,60 @@ class Chef
233
291
  "Wrong response received from Partial Search: #{resp.inspect}"
234
292
  end
235
293
 
294
+ # Adds the `name` key to the search keys structure.
295
+ #
296
+ # Used to get the node name when searching nodes by name.
297
+ #
298
+ # @param keys [Hash] search keys structure. For example:
299
+ # `{ipaddress: %w(ipaddress), mysql_version: %w(mysql version) }`.
300
+ # @return [Hash] the search keys structure including the `name` key. For
301
+ # example:
302
+ # `{ipaddress: %w(ipaddress), mysql_version: %w(mysql version),
303
+ # name: %w(name) }`.
304
+ # @api private
305
+ def generate_partial_search_keys(keys)
306
+ keys.merge('name' => %w(name))
307
+ end
308
+
309
+ # Filters partial search results that do not correspond to the searched
310
+ # node.
311
+ #
312
+ # Used when searching by node name.
313
+ #
314
+ # @param resp [Hash] partial search result. For example:
315
+ # `{ 'rows' => [ 'data' => { 'ipaddress' => '192.168.1.1' } }] }`.
316
+ # @param name [String, nil] searched node name.
317
+ # @return [Hash] The search result removing the filtered results.
318
+ # @raise [SearchFatalError] if more than one result is returned when
319
+ # searching by node name.
320
+ # @api private
321
+ def filter_partial_search_response(resp, name)
322
+ return resp if name.nil?
323
+ filtered_resp = resp.select do |row|
324
+ row['data']['name'] == name
325
+ end
326
+ filtered_resp.tap do |r|
327
+ fail SearchFatalError,
328
+ 'Multiple responses received from Partial Search:'\
329
+ " #{r.inspect}" if r.count > 1
330
+ end
331
+ end
332
+
236
333
  # Parses a partial full search search response.
237
334
  #
238
335
  # @param resp [Hash] partial search result. For example:
239
336
  # `{ 'rows' => [ 'data' => { 'ipaddress' => '192.168.1.1' } }] }`.
337
+ # @param name [String, nil] searched node name.
338
+ # @param keys [Hash] search keys structure. For example:
339
+ # `{ipaddress: %w(ipaddress), mysql_version: %w(mysql version) }`.
240
340
  # @return [Array<Hash>] An array with the response, for example:
241
341
  # `[{ 'ipaddress' => '192.168.1.1' }]`
242
342
  # @raise [SearchFatalError] if the Chef search response is wrong.
243
343
  # @api private
244
- def parse_partial_search_response(resp)
245
- resp['rows'].map do |row|
344
+ def parse_partial_search_response(resp, name, keys)
345
+ filter_partial_search_response(resp['rows'], name).map do |row|
246
346
  if row.is_a?(Hash) && row['data'].is_a?(Hash)
247
- row['data']
347
+ row['data'].tap { |r| r.delete('name') unless keys.key?('name') }
248
348
  else
249
349
  fail SearchFatalError,
250
350
  "Wrong row format received from Partial Search: #{row.inspect}"
@@ -256,6 +356,7 @@ class Chef
256
356
  #
257
357
  # @param type [Symbol] search index to use. See [Chef Search Indexes]
258
358
  # (http://docs.getchef.com/chef_search.html#search-indexes).
359
+ # @param name [String, nil] searched node name.
259
360
  # @param query [String, Array<String>] search query. For example:
260
361
  # `%w(admin:true)`. Results will be *OR*-ed when multiple string queries
261
362
  # are provided.
@@ -266,7 +367,7 @@ class Chef
266
367
  # `[{ 'ipaddress' => '192.168.1.1' }]`
267
368
  # @raise [InvalidSearchKeys] if search keys structure is wrong.
268
369
  # @raise [SearchFatalError] if the Chef search response is wrong.
269
- def partial_search(type, query, keys, rows = 1000)
370
+ def partial_search(type, name, query, keys, rows = 1000)
270
371
  escaped_query =
271
372
  "search/#{escape(type)}?q=#{escape_query(query)}&start=0&rows=#{rows}"
272
373
  Chef::Log.info(
@@ -275,9 +376,9 @@ class Chef
275
376
  assert_search_keys(keys)
276
377
 
277
378
  rest = Chef::REST.new(Chef::Config[:chef_server_url])
278
- resp = rest.post_rest(escaped_query, keys)
379
+ resp = rest.post_rest(escaped_query, generate_partial_search_keys(keys))
279
380
  assert_partial_search_response(resp)
280
- parse_partial_search_response(resp)
381
+ parse_partial_search_response(resp, name, keys)
281
382
  end
282
383
  end
283
384
  end
@@ -20,6 +20,6 @@
20
20
  class Chef
21
21
  class EncryptedAttribute
22
22
  # `chef-encrypted-attributes` gem version.
23
- VERSION = '0.6.0'
23
+ VERSION = '0.7.0'
24
24
  end
25
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-encrypted-attributes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Onddo Labs, SL.
@@ -30,7 +30,7 @@ cert_chain:
30
30
  cYe8PqNEkky7ugvF4zU3sB6TW+96XasuwDv1uJmyr35LF15U6Cs83+osMbAKJTmG
31
31
  /vqKzw==
32
32
  -----END CERTIFICATE-----
33
- date: 2015-05-08 00:00:00.000000000 Z
33
+ date: 2015-05-20 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: chef
@@ -42,7 +42,7 @@ dependencies:
42
42
  - - "<"
43
43
  - !ruby/object:Gem::Version
44
44
  version: '13'
45
- type: :runtime
45
+ type: :development
46
46
  prerelease: false
47
47
  version_requirements: !ruby/object:Gem::Requirement
48
48
  requirements:
@@ -170,14 +170,14 @@ dependencies:
170
170
  requirements:
171
171
  - - '='
172
172
  - !ruby/object:Gem::Version
173
- version: 0.29.1
173
+ version: 0.31.0
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - '='
179
179
  - !ruby/object:Gem::Version
180
- version: 0.29.1
180
+ version: 0.31.0
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: yard
183
183
  requirement: !ruby/object:Gem::Requirement
@@ -195,8 +195,7 @@ dependencies:
195
195
  description: Chef plugin to add Node encrypted attributes support using client keys
196
196
  email: team@onddo.com
197
197
  executables: []
198
- extensions:
199
- - ext/mkrf_conf.rb
198
+ extensions: []
200
199
  extra_rdoc_files: []
201
200
  files:
202
201
  - ".yardopts"
@@ -208,7 +207,6 @@ files:
208
207
  - Rakefile
209
208
  - TESTING.md
210
209
  - TODO.md
211
- - ext/mkrf_conf.rb
212
210
  - lib/chef-encrypted-attributes.rb
213
211
  - lib/chef/encrypted_attribute.rb
214
212
  - lib/chef/encrypted_attribute/api.rb
@@ -261,7 +259,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
261
259
  version: '0'
262
260
  requirements: []
263
261
  rubyforge_project:
264
- rubygems_version: 2.4.3
262
+ rubygems_version: 2.2.2
265
263
  signing_key:
266
264
  specification_version: 4
267
265
  summary: Chef Encrypted Attributes
metadata.gz.sig CHANGED
Binary file
data/ext/mkrf_conf.rb DELETED
@@ -1,52 +0,0 @@
1
- # encoding: UTF-8
2
- #
3
- # Author:: Xabier de Zuazo (<xabier@onddo.com>)
4
- # Copyright:: Copyright (c) 2015 Onddo Labs, SL. (www.onddo.com)
5
- # License:: Apache License, Version 2.0
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
- #
19
-
20
- # Conditional gem dependency installation within a gemspec.
21
- #
22
- # Based on:
23
- # * http://www.programmersparadox.com/2012/05/21
24
- # /gemspec-loading-dependent-gems-based-on-the-users-system/
25
- # * https://www.tiredpixel.com/2014/01/05
26
- # /curses-conditional-ruby-gem-installation-within-a-gemspec/
27
-
28
- require 'rubygems/dependency_installer'
29
-
30
- di = Gem::DependencyInstaller.new
31
-
32
- begin
33
- if RUBY_VERSION < '1.9.3'
34
- puts "Installing mixlib-shellout < 1.6.1 because Ruby #{RUBY_VERSION}"
35
- di.install 'mixlib-shellout', '< 1.6.1'
36
- end
37
- if RUBY_VERSION < '2'
38
- puts "Installing highline < 1.7 because Ruby #{RUBY_VERSION}"
39
- di.install 'highline', '< 1.7'
40
- puts "Installing ohai < 8 because Ruby #{RUBY_VERSION}"
41
- di.install 'ohai', '< 8'
42
- end
43
- rescue => e
44
- warn "#{$PROGRAM_NAME}: #{e}"
45
- exit!
46
- end
47
-
48
- puts 'Writing fake Rakefile'
49
- # Write fake Rakefile for rake since Makefile isn't used
50
- File.open(File.join(File.dirname(__FILE__), 'Rakefile'), 'w') do |f|
51
- f.write("task :default\n")
52
- end