chef 0.7.10

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of chef might be problematic. Click here for more details.

Files changed (120) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +135 -0
  3. data/bin/chef-client +26 -0
  4. data/bin/chef-solo +26 -0
  5. data/lib/chef.rb +49 -0
  6. data/lib/chef/application.rb +98 -0
  7. data/lib/chef/application/agent.rb +18 -0
  8. data/lib/chef/application/client.rb +209 -0
  9. data/lib/chef/application/indexer.rb +141 -0
  10. data/lib/chef/application/server.rb +18 -0
  11. data/lib/chef/application/solo.rb +214 -0
  12. data/lib/chef/client.rb +396 -0
  13. data/lib/chef/compile.rb +138 -0
  14. data/lib/chef/config.rb +141 -0
  15. data/lib/chef/cookbook.rb +144 -0
  16. data/lib/chef/cookbook/metadata.rb +407 -0
  17. data/lib/chef/cookbook/metadata/version.rb +87 -0
  18. data/lib/chef/cookbook_loader.rb +168 -0
  19. data/lib/chef/couchdb.rb +172 -0
  20. data/lib/chef/daemon.rb +170 -0
  21. data/lib/chef/exceptions.rb +36 -0
  22. data/lib/chef/file_cache.rb +205 -0
  23. data/lib/chef/log.rb +39 -0
  24. data/lib/chef/mixin/check_helper.rb +31 -0
  25. data/lib/chef/mixin/checksum.rb +37 -0
  26. data/lib/chef/mixin/command.rb +351 -0
  27. data/lib/chef/mixin/create_path.rb +56 -0
  28. data/lib/chef/mixin/deep_merge.rb +36 -0
  29. data/lib/chef/mixin/find_preferred_file.rb +99 -0
  30. data/lib/chef/mixin/from_file.rb +36 -0
  31. data/lib/chef/mixin/generate_url.rb +48 -0
  32. data/lib/chef/mixin/language.rb +79 -0
  33. data/lib/chef/mixin/params_validate.rb +197 -0
  34. data/lib/chef/mixin/template.rb +84 -0
  35. data/lib/chef/node.rb +406 -0
  36. data/lib/chef/node/attribute.rb +412 -0
  37. data/lib/chef/openid_registration.rb +181 -0
  38. data/lib/chef/platform.rb +253 -0
  39. data/lib/chef/provider.rb +40 -0
  40. data/lib/chef/provider/cron.rb +137 -0
  41. data/lib/chef/provider/directory.rb +72 -0
  42. data/lib/chef/provider/execute.rb +58 -0
  43. data/lib/chef/provider/file.rb +191 -0
  44. data/lib/chef/provider/group.rb +120 -0
  45. data/lib/chef/provider/group/groupadd.rb +92 -0
  46. data/lib/chef/provider/group/pw.rb +88 -0
  47. data/lib/chef/provider/http_request.rb +102 -0
  48. data/lib/chef/provider/ifconfig.rb +131 -0
  49. data/lib/chef/provider/link.rb +157 -0
  50. data/lib/chef/provider/mount.rb +121 -0
  51. data/lib/chef/provider/mount/mount.rb +208 -0
  52. data/lib/chef/provider/package.rb +160 -0
  53. data/lib/chef/provider/package/apt.rb +110 -0
  54. data/lib/chef/provider/package/dpkg.rb +113 -0
  55. data/lib/chef/provider/package/freebsd.rb +153 -0
  56. data/lib/chef/provider/package/macports.rb +105 -0
  57. data/lib/chef/provider/package/portage.rb +124 -0
  58. data/lib/chef/provider/package/rpm.rb +99 -0
  59. data/lib/chef/provider/package/rubygems.rb +130 -0
  60. data/lib/chef/provider/package/yum-dump.py +104 -0
  61. data/lib/chef/provider/package/yum.rb +175 -0
  62. data/lib/chef/provider/remote_directory.rb +126 -0
  63. data/lib/chef/provider/remote_file.rb +134 -0
  64. data/lib/chef/provider/route.rb +118 -0
  65. data/lib/chef/provider/ruby_block.rb +15 -0
  66. data/lib/chef/provider/script.rb +42 -0
  67. data/lib/chef/provider/service.rb +129 -0
  68. data/lib/chef/provider/service/debian.rb +64 -0
  69. data/lib/chef/provider/service/freebsd.rb +157 -0
  70. data/lib/chef/provider/service/gentoo.rb +54 -0
  71. data/lib/chef/provider/service/init.rb +126 -0
  72. data/lib/chef/provider/service/redhat.rb +62 -0
  73. data/lib/chef/provider/template.rb +141 -0
  74. data/lib/chef/provider/user.rb +170 -0
  75. data/lib/chef/provider/user/pw.rb +113 -0
  76. data/lib/chef/provider/user/useradd.rb +107 -0
  77. data/lib/chef/queue.rb +145 -0
  78. data/lib/chef/recipe.rb +210 -0
  79. data/lib/chef/resource.rb +256 -0
  80. data/lib/chef/resource/apt_package.rb +34 -0
  81. data/lib/chef/resource/bash.rb +33 -0
  82. data/lib/chef/resource/cron.rb +143 -0
  83. data/lib/chef/resource/csh.rb +33 -0
  84. data/lib/chef/resource/directory.rb +76 -0
  85. data/lib/chef/resource/dpkg_package.rb +34 -0
  86. data/lib/chef/resource/execute.rb +127 -0
  87. data/lib/chef/resource/file.rb +84 -0
  88. data/lib/chef/resource/gem_package.rb +41 -0
  89. data/lib/chef/resource/group.rb +68 -0
  90. data/lib/chef/resource/http_request.rb +52 -0
  91. data/lib/chef/resource/ifconfig.rb +134 -0
  92. data/lib/chef/resource/link.rb +78 -0
  93. data/lib/chef/resource/macports_package.rb +29 -0
  94. data/lib/chef/resource/mount.rb +135 -0
  95. data/lib/chef/resource/package.rb +80 -0
  96. data/lib/chef/resource/perl.rb +33 -0
  97. data/lib/chef/resource/portage_package.rb +33 -0
  98. data/lib/chef/resource/python.rb +33 -0
  99. data/lib/chef/resource/remote_directory.rb +91 -0
  100. data/lib/chef/resource/remote_file.rb +60 -0
  101. data/lib/chef/resource/route.rb +135 -0
  102. data/lib/chef/resource/ruby.rb +33 -0
  103. data/lib/chef/resource/ruby_block.rb +20 -0
  104. data/lib/chef/resource/script.rb +51 -0
  105. data/lib/chef/resource/service.rb +134 -0
  106. data/lib/chef/resource/template.rb +60 -0
  107. data/lib/chef/resource/user.rb +98 -0
  108. data/lib/chef/resource_collection.rb +176 -0
  109. data/lib/chef/resource_definition.rb +67 -0
  110. data/lib/chef/rest.rb +238 -0
  111. data/lib/chef/role.rb +231 -0
  112. data/lib/chef/run_list.rb +156 -0
  113. data/lib/chef/runner.rb +123 -0
  114. data/lib/chef/search.rb +88 -0
  115. data/lib/chef/search/result.rb +64 -0
  116. data/lib/chef/search_index.rb +77 -0
  117. data/lib/chef/tasks/chef_repo.rake +345 -0
  118. data/lib/chef/util/file_edit.rb +125 -0
  119. data/lib/chef/util/fileedit.rb +121 -0
  120. metadata +262 -0
@@ -0,0 +1,345 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'rubygems'
20
+ require 'json'
21
+ require 'chef'
22
+ require 'chef/role'
23
+ require 'chef/cookbook/metadata'
24
+ require 'tempfile'
25
+ require 'rake'
26
+
27
+ desc "Update your repository from source control"
28
+ task :update do
29
+ puts "** Updating your repository"
30
+
31
+ case $vcs
32
+ when :svn
33
+ sh %{svn up}
34
+ when :git
35
+ pull = false
36
+ pull = true if File.join(TOPDIR, ".git", "remotes", "origin")
37
+ IO.foreach(File.join(TOPDIR, ".git", "config")) do |line|
38
+ pull = true if line =~ /\[remote "origin"\]/
39
+ end
40
+ if pull
41
+ sh %{git pull}
42
+ else
43
+ puts "* Skipping git pull, no origin specified"
44
+ end
45
+ else
46
+ puts "* No SCM configured, skipping update"
47
+ end
48
+ end
49
+
50
+ desc "Test your cookbooks for syntax errors"
51
+ task :test_recipes do
52
+ puts "** Testing your cookbooks for syntax errors"
53
+
54
+ if File.exists?(TEST_CACHE)
55
+ cache = JSON.load(open(TEST_CACHE).read)
56
+ trap("INT") { puts "INT received, flushing test cache"; write_cache(cache) }
57
+ else
58
+ cache = {}
59
+ end
60
+
61
+ recipes = ["*cookbooks"].map { |folder|
62
+ Dir[File.join(TOPDIR, folder, "**", "*.rb")]
63
+ }.flatten
64
+
65
+ recipes.each do |recipe|
66
+ print "Testing recipe #{recipe}: "
67
+
68
+ recipe_mtime = File.stat(recipe).mtime.to_s
69
+ if cache.has_key?(recipe)
70
+ if cache[recipe]["mtime"] == recipe_mtime
71
+ puts "No modification since last test."
72
+ next
73
+ end
74
+ else
75
+ cache[recipe] = {}
76
+ end
77
+
78
+
79
+ sh %{ruby -c #{recipe}} do |ok, res|
80
+ if ok
81
+ cache[recipe]["mtime"] = recipe_mtime
82
+ else
83
+ write_cache(cache)
84
+ raise "Syntax error in #{recipe}"
85
+ end
86
+ end
87
+ end
88
+
89
+ write_cache(cache)
90
+ end
91
+
92
+ desc "Test your templates for syntax errors"
93
+ task :test_templates do
94
+ puts "** Testing your cookbooks for syntax errors"
95
+
96
+ if File.exists?(TEST_CACHE)
97
+ cache = JSON.load(open(TEST_CACHE).read)
98
+ trap("INT") { puts "INT received, flushing test cache"; write_cache(cache) }
99
+ else
100
+ cache = {}
101
+ end
102
+
103
+ templates = ["*cookbooks"].map { |folder|
104
+ Dir[File.join(TOPDIR, folder, "**", "*.erb")]
105
+ }.flatten
106
+
107
+ templates.each do |template|
108
+ print "Testing template #{template}: "
109
+
110
+ template_mtime = File.stat(template).mtime.to_s
111
+ if cache.has_key?(template)
112
+ if cache[template]["mtime"] == template_mtime
113
+ puts "No change since last test."
114
+ next
115
+ end
116
+ else
117
+ cache[template] = {}
118
+ end
119
+
120
+ sh %{erubis -x #{template} | ruby -c} do |ok, res|
121
+ if ok
122
+ cache[template]["mtime"] = template_mtime
123
+ else
124
+ write_cache(cache)
125
+ raise "Syntax error in #{template}"
126
+ end
127
+ end
128
+
129
+ end
130
+
131
+ write_cache(cache)
132
+ end
133
+
134
+ desc "Test your cookbooks for syntax errors"
135
+ task :test => [ :test_recipes , :test_templates ]
136
+
137
+ def write_cache(cache)
138
+ File.open(TEST_CACHE, "w") { |f| JSON.dump(cache, f) }
139
+ end
140
+
141
+ desc "Install the latest copy of the repository on this Chef Server"
142
+ task :install => [ :update, :test, :metadata, :roles ] do
143
+ puts "** Installing your cookbooks"
144
+ directories = [
145
+ COOKBOOK_PATH,
146
+ SITE_COOKBOOK_PATH,
147
+ CHEF_CONFIG_PATH
148
+ ]
149
+ puts "* Creating Directories"
150
+ directories.each do |dir|
151
+ sh "sudo mkdir -p #{dir}"
152
+ sh "sudo chown root #{dir}"
153
+ end
154
+ puts "* Installing new Cookbooks"
155
+ sh "sudo rsync -rlP --delete --exclude '.svn' --exclude '.git*' cookbooks/ #{COOKBOOK_PATH}"
156
+ puts "* Installing new Site Cookbooks"
157
+ sh "sudo rsync -rlP --delete --exclude '.svn' --exclude '.git*' site-cookbooks/ #{SITE_COOKBOOK_PATH}"
158
+ puts "* Installing new Node Roles"
159
+ sh "sudo rsync -rlP --delete --exclude '.svn' --exclude '.git*' roles/ #{ROLE_PATH}"
160
+
161
+ if File.exists?(File.join(File.dirname(__FILE__), "config", "server.rb"))
162
+ puts "* Installing new Chef Server Config"
163
+ sh "sudo cp config/server.rb #{CHEF_SERVER_CONFIG}"
164
+ end
165
+ if File.exists?(File.join(File.dirname(__FILE__), "config", "client.rb"))
166
+ puts "* Installing new Chef Client Config"
167
+ sh "sudo cp config/client.rb #{CHEF_CLIENT_CONFIG}"
168
+ end
169
+ end
170
+
171
+ desc "By default, run rake test"
172
+ task :default => [ :test ]
173
+
174
+ desc "Create a new cookbook (with COOKBOOK=name, optional CB_PREFIX=site-)"
175
+ task :new_cookbook do
176
+ create_cookbook(File.join(TOPDIR, "#{ENV["CB_PREFIX"]}cookbooks"))
177
+ create_readme(File.join(TOPDIR, "#{ENV["CB_PREFIX"]}cookbooks"))
178
+ create_metadata(File.join(TOPDIR, "#{ENV["CB_PREFIX"]}cookbooks"))
179
+ end
180
+
181
+ def create_cookbook(dir)
182
+ raise "Must provide a COOKBOOK=" unless ENV["COOKBOOK"]
183
+ puts "** Creating cookbook #{ENV["COOKBOOK"]}"
184
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "attributes")}"
185
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "recipes")}"
186
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "definitions")}"
187
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "libraries")}"
188
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "files", "default")}"
189
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "templates", "default")}"
190
+ unless File.exists?(File.join(dir, ENV["COOKBOOK"], "recipes", "default.rb"))
191
+ open(File.join(dir, ENV["COOKBOOK"], "recipes", "default.rb"), "w") do |file|
192
+ file.puts <<-EOH
193
+ #
194
+ # Cookbook Name:: #{ENV["COOKBOOK"]}
195
+ # Recipe:: default
196
+ #
197
+ # Copyright #{Time.now.year}, #{COMPANY_NAME}
198
+ #
199
+ EOH
200
+ case NEW_COOKBOOK_LICENSE
201
+ when :apachev2
202
+ file.puts <<-EOH
203
+ # Licensed under the Apache License, Version 2.0 (the "License");
204
+ # you may not use this file except in compliance with the License.
205
+ # You may obtain a copy of the License at
206
+ #
207
+ # http://www.apache.org/licenses/LICENSE-2.0
208
+ #
209
+ # Unless required by applicable law or agreed to in writing, software
210
+ # distributed under the License is distributed on an "AS IS" BASIS,
211
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
212
+ # See the License for the specific language governing permissions and
213
+ # limitations under the License.
214
+ #
215
+ EOH
216
+ when :none
217
+ file.puts <<-EOH
218
+ # All rights reserved - Do Not Redistribute
219
+ #
220
+ EOH
221
+ end
222
+ end
223
+ end
224
+ end
225
+
226
+ def create_readme(dir)
227
+ raise "Must provide a COOKBOOK=" unless ENV["COOKBOOK"]
228
+ puts "** Creating README for cookbook: #{ENV["COOKBOOK"]}"
229
+ unless File.exists?(File.join(dir, ENV["COOKBOOK"], "README.rdoc"))
230
+ open(File.join(dir, ENV["COOKBOOK"], "README.rdoc"), "w") do |file|
231
+ file.puts <<-EOH
232
+ = DESCRIPTION:
233
+
234
+ = REQUIREMENTS:
235
+
236
+ = ATTRIBUTES:
237
+
238
+ = USAGE:
239
+
240
+ EOH
241
+ end
242
+ end
243
+ end
244
+
245
+ def create_metadata(dir)
246
+ raise "Must provide a COOKBOOK=" unless ENV["COOKBOOK"]
247
+ puts "** Creating metadata for cookbook: #{ENV["COOKBOOK"]}"
248
+
249
+ case NEW_COOKBOOK_LICENSE
250
+ when :apachev2
251
+ license = "Apache 2.0"
252
+ when :none
253
+ license = "All rights reserved"
254
+ end
255
+
256
+ unless File.exists?(File.join(dir, ENV["COOKBOOK"], "metadata.rb"))
257
+ open(File.join(dir, ENV["COOKBOOK"], "metadata.rb"), "w") do |file|
258
+ if File.exists?(File.join(dir, ENV["COOKBOOK"], 'README.rdoc'))
259
+ long_description = "long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))"
260
+ end
261
+ file.puts <<-EOH
262
+ maintainer "#{COMPANY_NAME}"
263
+ maintainer_email "#{SSL_EMAIL_ADDRESS}"
264
+ license "#{license}"
265
+ description "Installs/Configures #{ENV["COOKBOOK"]}"
266
+ #{long_description}
267
+ version "0.1"
268
+ EOH
269
+ end
270
+ end
271
+ end
272
+
273
+ desc "Create a new self-signed SSL certificate for FQDN=foo.example.com"
274
+ task :ssl_cert do
275
+ $expect_verbose = true
276
+ fqdn = ENV["FQDN"]
277
+ fqdn =~ /^(.+?)\.(.+)$/
278
+ hostname = $1
279
+ domain = $2
280
+ raise "Must provide FQDN!" unless fqdn && hostname && domain
281
+ puts "** Creating self signed SSL Certificate for #{fqdn}"
282
+ sh("(cd #{CADIR} && openssl genrsa 2048 > #{fqdn}.key)")
283
+ sh("(cd #{CADIR} && chmod 644 #{fqdn}.key)")
284
+ puts "* Generating Self Signed Certificate Request"
285
+ tf = Tempfile.new("#{fqdn}.ssl-conf")
286
+ ssl_config = <<EOH
287
+ [ req ]
288
+ distinguished_name = req_distinguished_name
289
+ prompt = no
290
+
291
+ [ req_distinguished_name ]
292
+ C = #{SSL_COUNTRY_NAME}
293
+ ST = #{SSL_STATE_NAME}
294
+ L = #{SSL_LOCALITY_NAME}
295
+ O = #{COMPANY_NAME}
296
+ OU = #{SSL_ORGANIZATIONAL_UNIT_NAME}
297
+ CN = #{fqdn}
298
+ emailAddress = #{SSL_EMAIL_ADDRESS}
299
+ EOH
300
+ tf.puts(ssl_config)
301
+ tf.close
302
+ sh("(cd #{CADIR} && openssl req -config '#{tf.path}' -new -x509 -nodes -sha1 -days 3650 -key #{fqdn}.key > #{fqdn}.crt)")
303
+ sh("(cd #{CADIR} && openssl x509 -noout -fingerprint -text < #{fqdn}.crt > #{fqdn}.info)")
304
+ sh("(cd #{CADIR} && cat #{fqdn}.crt #{fqdn}.key > #{fqdn}.pem)")
305
+ sh("(cd #{CADIR} && chmod 644 #{fqdn}.pem)")
306
+ end
307
+
308
+ desc "Build cookbook metadata.json from metadata.rb"
309
+ task :metadata do
310
+ Chef::Config[:cookbook_path] = [ File.join(TOPDIR, 'cookbooks'), File.join(TOPDIR, 'site-cookbooks') ]
311
+ cl = Chef::CookbookLoader.new
312
+ cl.each do |cookbook|
313
+ if ENV['COOKBOOK']
314
+ next unless cookbook.name.to_s == ENV['COOKBOOK']
315
+ end
316
+ cook_meta = Chef::Cookbook::Metadata.new(cookbook)
317
+ Chef::Config.cookbook_path.each do |cdir|
318
+ metadata_rb_file = File.join(cdir, cookbook.name.to_s, 'metadata.rb')
319
+ metadata_json_file = File.join(cdir, cookbook.name.to_s, 'metadata.json')
320
+ if File.exists?(metadata_rb_file)
321
+ puts "Generating metadata for #{cookbook.name}"
322
+ cook_meta.from_file(metadata_rb_file)
323
+ File.open(metadata_json_file, "w") do |f|
324
+ f.write(JSON.pretty_generate(cook_meta))
325
+ end
326
+ end
327
+ end
328
+ end
329
+ end
330
+
331
+ desc "Build roles from roles/role_name.json from role_name.rb"
332
+ task :roles do
333
+ Chef::Config[:role_path] = File.join(TOPDIR, 'roles')
334
+ Dir[File.join(TOPDIR, 'roles', '**', '*.rb')].each do |role_file|
335
+ short_name = File.basename(role_file, '.rb')
336
+ puts "Generating role JSON for #{short_name}"
337
+ role = Chef::Role.new
338
+ role.name(short_name)
339
+ role.from_file(role_file)
340
+ File.open(File.join(TOPDIR, 'roles', "#{short_name}.json"), "w") do |f|
341
+ f.write(JSON.pretty_generate(role))
342
+ end
343
+ end
344
+ end
345
+
@@ -0,0 +1,125 @@
1
+ #
2
+ # Author:: Nuo Yan (<nuo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2009 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'ftools'
19
+ require 'fileutils'
20
+ require 'tempfile'
21
+
22
+ class Chef
23
+ class Util
24
+ class FileEdit
25
+
26
+ private
27
+
28
+ attr_accessor :original_pathname, :contents, :file_edited
29
+
30
+ public
31
+
32
+ def initialize(filepath)
33
+ @original_pathname = filepath
34
+ @file_edited = false
35
+
36
+ raise ArgumentError, "File doesn't exist" unless File.exist? @original_pathname
37
+ raise ArgumentError, "File is blank" unless (@contents = File.new(@original_pathname).readlines).length > 0
38
+ end
39
+
40
+ #search the file line by line and match each line with the given regex
41
+ #if matched, replace the whole line with newline.
42
+ def search_file_replace_line(regex, newline)
43
+ search_match(regex, newline, 'r', 1)
44
+ end
45
+
46
+ #search the file line by line and match each line with the given regex
47
+ #if matched, replace the match (all occurances) with the replace parameter
48
+ def search_file_replace(regex, replace)
49
+ search_match(regex, replace, 'r', 2)
50
+ end
51
+
52
+ #search the file line by line and match each line with the given regex
53
+ #if matched, delete the line
54
+ def search_file_delete_line(regex)
55
+ search_match(regex, " ", 'd', 1)
56
+ end
57
+
58
+ #search the file line by line and match each line with the given regex
59
+ #if matched, delete the match (all occurances) from the line
60
+ def search_file_delete(regex)
61
+ search_match(regex, " ", 'd', 2)
62
+ end
63
+
64
+ #search the file line by line and match each line with the given regex
65
+ #if matched, insert newline after each matching line
66
+ def insert_line_after_match(regex, newline)
67
+ search_match(regex, newline, 'i', 0)
68
+ end
69
+
70
+ #Make a copy of old_file and write new file out (only if file changed)
71
+ def write_file
72
+
73
+ # file_edited is false when there was no match in the whole file and thus no contents have changed.
74
+ if file_edited
75
+ backup_pathname = original_pathname + ".old"
76
+ File.copy(original_pathname, backup_pathname)
77
+ Tempfile.open("w") do |newfile|
78
+ contents.each do |line|
79
+ newfile.puts(line)
80
+ end
81
+ newfile.flush
82
+ FileUtils.mv(newfile.path, original_pathname)
83
+ end
84
+ end
85
+ self.file_edited = false
86
+
87
+ end
88
+
89
+ private
90
+
91
+ #helper method to do the match, replace, delete, and insert operations
92
+ #command is the switch of delete, replace, and insert ('d', 'r', 'i')
93
+ #method is to control operation on whole line or only the match (1 for line, 2 for match)
94
+ def search_match(regex, replace, command, method)
95
+
96
+ #convert regex to a Regexp object (if not already is one) and store it in exp.
97
+ exp = Regexp.new(regex)
98
+
99
+ #loop through contents and do the appropriate operation depending on 'command' and 'method'
100
+ new_contents = []
101
+
102
+ contents.each do |line|
103
+ if line.match(exp)
104
+ self.file_edited = true
105
+ case
106
+ when command == 'r'
107
+ new_contents << ((method == 1) ? replace : line.gsub!(exp, replace))
108
+ when command == 'd'
109
+ if method == 2
110
+ new_contents << line.gsub!(exp, "")
111
+ end
112
+ when command == 'i'
113
+ new_contents << line
114
+ new_contents << replace
115
+ end
116
+ else
117
+ new_contents << line
118
+ end
119
+ end
120
+
121
+ self.contents = new_contents
122
+ end
123
+ end
124
+ end
125
+ end