acquia_toolbelt 2.3.0 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. data/.gitignore +7 -0
  2. data/.ruby-version +1 -0
  3. data/.travis.yml +7 -0
  4. data/CONTRIBUTING.md +11 -0
  5. data/Gemfile +3 -0
  6. data/Gemfile.lock +55 -0
  7. data/Guardfile +5 -0
  8. data/LICENSE +19 -0
  9. data/README.md +149 -0
  10. data/Rakefile +1 -0
  11. data/acquia_toolbelt.gemspec +34 -0
  12. data/bin/acquia +9 -0
  13. data/lib/acquia_toolbelt/cli/api.rb +164 -0
  14. data/lib/acquia_toolbelt/cli/auth.rb +31 -0
  15. data/lib/acquia_toolbelt/cli/database.rb +237 -0
  16. data/lib/acquia_toolbelt/cli/deploy.rb +36 -0
  17. data/lib/acquia_toolbelt/cli/domain.rb +177 -0
  18. data/lib/acquia_toolbelt/cli/environment.rb +71 -0
  19. data/lib/acquia_toolbelt/cli/file.rb +31 -0
  20. data/lib/acquia_toolbelt/cli/server.rb +67 -0
  21. data/lib/acquia_toolbelt/cli/site.rb +28 -0
  22. data/lib/acquia_toolbelt/cli/ssh.rb +78 -0
  23. data/lib/acquia_toolbelt/cli/svn.rb +73 -0
  24. data/lib/acquia_toolbelt/cli/task.rb +74 -0
  25. data/lib/acquia_toolbelt/cli/ui.rb +44 -0
  26. data/lib/acquia_toolbelt/cli.rb +103 -0
  27. data/lib/acquia_toolbelt/error.rb +4 -0
  28. data/lib/acquia_toolbelt/thor.rb +95 -0
  29. data/lib/acquia_toolbelt/version.rb +3 -0
  30. data/lib/acquia_toolbelt.rb +4 -0
  31. data/lib/vendor/thor/CHANGELOG.md +139 -0
  32. data/lib/vendor/thor/Gemfile +20 -0
  33. data/lib/vendor/thor/LICENSE.md +20 -0
  34. data/lib/vendor/thor/README.md +35 -0
  35. data/lib/vendor/thor/lib/thor/actions/create_file.rb +105 -0
  36. data/lib/vendor/thor/lib/thor/actions/create_link.rb +60 -0
  37. data/lib/vendor/thor/lib/thor/actions/directory.rb +119 -0
  38. data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +137 -0
  39. data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +317 -0
  40. data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +109 -0
  41. data/lib/vendor/thor/lib/thor/actions.rb +318 -0
  42. data/lib/vendor/thor/lib/thor/base.rb +654 -0
  43. data/lib/vendor/thor/lib/thor/command.rb +136 -0
  44. data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +80 -0
  45. data/lib/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
  46. data/lib/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
  47. data/lib/vendor/thor/lib/thor/error.rb +32 -0
  48. data/lib/vendor/thor/lib/thor/group.rb +282 -0
  49. data/lib/vendor/thor/lib/thor/invocation.rb +172 -0
  50. data/lib/vendor/thor/lib/thor/parser/argument.rb +74 -0
  51. data/lib/vendor/thor/lib/thor/parser/arguments.rb +171 -0
  52. data/lib/vendor/thor/lib/thor/parser/option.rb +121 -0
  53. data/lib/vendor/thor/lib/thor/parser/options.rb +218 -0
  54. data/lib/vendor/thor/lib/thor/parser.rb +4 -0
  55. data/lib/vendor/thor/lib/thor/rake_compat.rb +72 -0
  56. data/lib/vendor/thor/lib/thor/runner.rb +322 -0
  57. data/lib/vendor/thor/lib/thor/shell/basic.rb +422 -0
  58. data/lib/vendor/thor/lib/thor/shell/color.rb +148 -0
  59. data/lib/vendor/thor/lib/thor/shell/html.rb +127 -0
  60. data/lib/vendor/thor/lib/thor/shell.rb +88 -0
  61. data/lib/vendor/thor/lib/thor/util.rb +270 -0
  62. data/lib/vendor/thor/lib/thor/version.rb +3 -0
  63. data/lib/vendor/thor/lib/thor.rb +474 -0
  64. data/lib/vendor/thor/spec/actions/create_file_spec.rb +170 -0
  65. data/lib/vendor/thor/spec/actions/create_link_spec.rb +95 -0
  66. data/lib/vendor/thor/spec/actions/directory_spec.rb +169 -0
  67. data/lib/vendor/thor/spec/actions/empty_directory_spec.rb +129 -0
  68. data/lib/vendor/thor/spec/actions/file_manipulation_spec.rb +382 -0
  69. data/lib/vendor/thor/spec/actions/inject_into_file_spec.rb +135 -0
  70. data/lib/vendor/thor/spec/actions_spec.rb +331 -0
  71. data/lib/vendor/thor/spec/base_spec.rb +291 -0
  72. data/lib/vendor/thor/spec/command_spec.rb +80 -0
  73. data/lib/vendor/thor/spec/core_ext/hash_with_indifferent_access_spec.rb +48 -0
  74. data/lib/vendor/thor/spec/core_ext/ordered_hash_spec.rb +115 -0
  75. data/lib/vendor/thor/spec/exit_condition_spec.rb +19 -0
  76. data/lib/vendor/thor/spec/fixtures/application.rb +2 -0
  77. data/lib/vendor/thor/spec/fixtures/app{1}/README +3 -0
  78. data/lib/vendor/thor/spec/fixtures/bundle/execute.rb +6 -0
  79. data/lib/vendor/thor/spec/fixtures/bundle/main.thor +1 -0
  80. data/lib/vendor/thor/spec/fixtures/command.thor +10 -0
  81. data/lib/vendor/thor/spec/fixtures/doc/%file_name%.rb.tt +1 -0
  82. data/lib/vendor/thor/spec/fixtures/doc/COMMENTER +11 -0
  83. data/lib/vendor/thor/spec/fixtures/doc/README +3 -0
  84. data/lib/vendor/thor/spec/fixtures/doc/block_helper.rb +3 -0
  85. data/lib/vendor/thor/spec/fixtures/doc/components/.empty_directory +0 -0
  86. data/lib/vendor/thor/spec/fixtures/doc/config.rb +1 -0
  87. data/lib/vendor/thor/spec/fixtures/doc/config.yaml.tt +1 -0
  88. data/lib/vendor/thor/spec/fixtures/doc/excluding/%file_name%.rb.tt +1 -0
  89. data/lib/vendor/thor/spec/fixtures/enum.thor +10 -0
  90. data/lib/vendor/thor/spec/fixtures/group.thor +128 -0
  91. data/lib/vendor/thor/spec/fixtures/invoke.thor +118 -0
  92. data/lib/vendor/thor/spec/fixtures/path with spaces +0 -0
  93. data/lib/vendor/thor/spec/fixtures/preserve/script.sh +3 -0
  94. data/lib/vendor/thor/spec/fixtures/script.thor +220 -0
  95. data/lib/vendor/thor/spec/fixtures/subcommand.thor +17 -0
  96. data/lib/vendor/thor/spec/group_spec.rb +222 -0
  97. data/lib/vendor/thor/spec/helper.rb +67 -0
  98. data/lib/vendor/thor/spec/invocation_spec.rb +108 -0
  99. data/lib/vendor/thor/spec/parser/argument_spec.rb +53 -0
  100. data/lib/vendor/thor/spec/parser/arguments_spec.rb +66 -0
  101. data/lib/vendor/thor/spec/parser/option_spec.rb +202 -0
  102. data/lib/vendor/thor/spec/parser/options_spec.rb +400 -0
  103. data/lib/vendor/thor/spec/rake_compat_spec.rb +72 -0
  104. data/lib/vendor/thor/spec/register_spec.rb +197 -0
  105. data/lib/vendor/thor/spec/runner_spec.rb +241 -0
  106. data/lib/vendor/thor/spec/shell/basic_spec.rb +330 -0
  107. data/lib/vendor/thor/spec/shell/color_spec.rb +95 -0
  108. data/lib/vendor/thor/spec/shell/html_spec.rb +31 -0
  109. data/lib/vendor/thor/spec/shell_spec.rb +47 -0
  110. data/lib/vendor/thor/spec/subcommand_spec.rb +30 -0
  111. data/lib/vendor/thor/spec/thor_spec.rb +499 -0
  112. data/lib/vendor/thor/spec/util_spec.rb +196 -0
  113. data/lib/vendor/thor/thor.gemspec +24 -0
  114. data/script/release +50 -0
  115. data/script/setup_build +6 -0
  116. data/script/test +23 -0
  117. data/spec/auth_spec.rb +15 -0
  118. data/spec/cassettes/databases/all_databases.json +1 -0
  119. data/spec/cassettes/databases/copy_database_from_dev_to_stage.json +1 -0
  120. data/spec/cassettes/databases/create_a_database_backup.json +1 -0
  121. data/spec/cassettes/databases/create_a_new_database.json +1 -0
  122. data/spec/cassettes/databases/delete_a_database.json +1 -0
  123. data/spec/cassettes/databases/get_all_existing_databases.json +1 -0
  124. data/spec/cassettes/databases/list_all_database_backups.json +1 -0
  125. data/spec/cassettes/databases/view_database_instance_details.json +1 -0
  126. data/spec/cassettes/deploy/release_vcs_branch.json +1 -0
  127. data/spec/cassettes/domains/create_new_domain.json +1 -0
  128. data/spec/cassettes/domains/delete_a_domain.json +1 -0
  129. data/spec/cassettes/domains/get_all_existing_domains.json +1 -0
  130. data/spec/cassettes/domains/list_all_dev_domains.json +1 -0
  131. data/spec/cassettes/domains/move_from_dev_to_stage.json +1 -0
  132. data/spec/cassettes/domains/purge_varnish_cache.json +1 -0
  133. data/spec/cassettes/environments/all_environments.json +1 -0
  134. data/spec/cassettes/environments/disable_live_development.json +1 -0
  135. data/spec/cassettes/environments/enable_live_development.json +1 -0
  136. data/spec/cassettes/files/copy_from_dev_to_stage.json +1 -0
  137. data/spec/cassettes/servers/all_dev_servers.json +1 -0
  138. data/spec/cassettes/servers/all_prod_servers.json +1 -0
  139. data/spec/cassettes/sites/all_sites.json +1 -0
  140. data/spec/cassettes/ssh/all_sshkeys.json +1 -0
  141. data/spec/cassettes/svn/all_svnusers.json +1 -0
  142. data/spec/cassettes/tasks/all_tasks.json +1 -0
  143. data/spec/databases_spec.rb +78 -0
  144. data/spec/deploy_spec.rb +12 -0
  145. data/spec/domains_spec.rb +59 -0
  146. data/spec/environments_spec.rb +35 -0
  147. data/spec/files_spec.rb +11 -0
  148. data/spec/helper.rb +104 -0
  149. data/spec/servers_spec.rb +59 -0
  150. data/spec/sites_spec.rb +19 -0
  151. data/spec/ssh_spec.rb +19 -0
  152. data/spec/svn_spec.rb +11 -0
  153. data/spec/tasks_spec.rb +11 -0
  154. metadata +158 -4
@@ -0,0 +1,317 @@
1
+ require 'erb'
2
+ require 'open-uri'
3
+
4
+ class Thor
5
+ module Actions
6
+
7
+ # Copies the file from the relative source to the relative destination. If
8
+ # the destination is not given it's assumed to be equal to the source.
9
+ #
10
+ # ==== Parameters
11
+ # source<String>:: the relative path to the source root.
12
+ # destination<String>:: the relative path to the destination root.
13
+ # config<Hash>:: give :verbose => false to not log the status, and
14
+ # :mode => :preserve, to preserve the file mode from the source.
15
+
16
+ #
17
+ # ==== Examples
18
+ #
19
+ # copy_file "README", "doc/README"
20
+ #
21
+ # copy_file "doc/README"
22
+ #
23
+ def copy_file(source, *args, &block)
24
+ config = args.last.is_a?(Hash) ? args.pop : {}
25
+ destination = args.first || source
26
+ source = File.expand_path(find_in_source_paths(source.to_s))
27
+
28
+ create_file destination, nil, config do
29
+ content = File.binread(source)
30
+ content = block.call(content) if block
31
+ content
32
+ end
33
+ if config[:mode] == :preserve
34
+ mode = File.stat(source).mode
35
+ chmod(destination, mode, config)
36
+ end
37
+ end
38
+
39
+ # Links the file from the relative source to the relative destination. If
40
+ # the destination is not given it's assumed to be equal to the source.
41
+ #
42
+ # ==== Parameters
43
+ # source<String>:: the relative path to the source root.
44
+ # destination<String>:: the relative path to the destination root.
45
+ # config<Hash>:: give :verbose => false to not log the status.
46
+ #
47
+ # ==== Examples
48
+ #
49
+ # link_file "README", "doc/README"
50
+ #
51
+ # link_file "doc/README"
52
+ #
53
+ def link_file(source, *args, &block)
54
+ config = args.last.is_a?(Hash) ? args.pop : {}
55
+ destination = args.first || source
56
+ source = File.expand_path(find_in_source_paths(source.to_s))
57
+
58
+ create_link destination, source, config
59
+ end
60
+
61
+ # Gets the content at the given address and places it at the given relative
62
+ # destination. If a block is given instead of destination, the content of
63
+ # the url is yielded and used as location.
64
+ #
65
+ # ==== Parameters
66
+ # source<String>:: the address of the given content.
67
+ # destination<String>:: the relative path to the destination root.
68
+ # config<Hash>:: give :verbose => false to not log the status.
69
+ #
70
+ # ==== Examples
71
+ #
72
+ # get "http://gist.github.com/103208", "doc/README"
73
+ #
74
+ # get "http://gist.github.com/103208" do |content|
75
+ # content.split("\n").first
76
+ # end
77
+ #
78
+ def get(source, *args, &block)
79
+ config = args.last.is_a?(Hash) ? args.pop : {}
80
+ destination = args.first
81
+
82
+ source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ /^https?\:\/\//
83
+ render = open(source) {|input| input.binmode.read }
84
+
85
+ destination ||= if block_given?
86
+ block.arity == 1 ? block.call(render) : block.call
87
+ else
88
+ File.basename(source)
89
+ end
90
+
91
+ create_file destination, render, config
92
+ end
93
+
94
+ # Gets an ERB template at the relative source, executes it and makes a copy
95
+ # at the relative destination. If the destination is not given it's assumed
96
+ # to be equal to the source removing .tt from the filename.
97
+ #
98
+ # ==== Parameters
99
+ # source<String>:: the relative path to the source root.
100
+ # destination<String>:: the relative path to the destination root.
101
+ # config<Hash>:: give :verbose => false to not log the status.
102
+ #
103
+ # ==== Examples
104
+ #
105
+ # template "README", "doc/README"
106
+ #
107
+ # template "doc/README"
108
+ #
109
+ def template(source, *args, &block)
110
+ config = args.last.is_a?(Hash) ? args.pop : {}
111
+ destination = args.first || source.sub(/\.tt$/, '')
112
+
113
+ source = File.expand_path(find_in_source_paths(source.to_s))
114
+ context = instance_eval('binding')
115
+
116
+ create_file destination, nil, config do
117
+ content = ERB.new(::File.binread(source), nil, '-', '@output_buffer').result(context)
118
+ content = block.call(content) if block
119
+ content
120
+ end
121
+ end
122
+
123
+ # Changes the mode of the given file or directory.
124
+ #
125
+ # ==== Parameters
126
+ # mode<Integer>:: the file mode
127
+ # path<String>:: the name of the file to change mode
128
+ # config<Hash>:: give :verbose => false to not log the status.
129
+ #
130
+ # ==== Example
131
+ #
132
+ # chmod "script/server", 0755
133
+ #
134
+ def chmod(path, mode, config={})
135
+ return unless behavior == :invoke
136
+ path = File.expand_path(path, destination_root)
137
+ say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true)
138
+ FileUtils.chmod_R(mode, path) unless options[:pretend]
139
+ end
140
+
141
+ # Prepend text to a file. Since it depends on insert_into_file, it's reversible.
142
+ #
143
+ # ==== Parameters
144
+ # path<String>:: path of the file to be changed
145
+ # data<String>:: the data to prepend to the file, can be also given as a block.
146
+ # config<Hash>:: give :verbose => false to not log the status.
147
+ #
148
+ # ==== Example
149
+ #
150
+ # prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"'
151
+ #
152
+ # prepend_to_file 'config/environments/test.rb' do
153
+ # 'config.gem "rspec"'
154
+ # end
155
+ #
156
+ def prepend_to_file(path, *args, &block)
157
+ config = args.last.is_a?(Hash) ? args.pop : {}
158
+ config.merge!(:after => /\A/)
159
+ insert_into_file(path, *(args << config), &block)
160
+ end
161
+ alias_method :prepend_file, :prepend_to_file
162
+
163
+ # Append text to a file. Since it depends on insert_into_file, it's reversible.
164
+ #
165
+ # ==== Parameters
166
+ # path<String>:: path of the file to be changed
167
+ # data<String>:: the data to append to the file, can be also given as a block.
168
+ # config<Hash>:: give :verbose => false to not log the status.
169
+ #
170
+ # ==== Example
171
+ #
172
+ # append_to_file 'config/environments/test.rb', 'config.gem "rspec"'
173
+ #
174
+ # append_to_file 'config/environments/test.rb' do
175
+ # 'config.gem "rspec"'
176
+ # end
177
+ #
178
+ def append_to_file(path, *args, &block)
179
+ config = args.last.is_a?(Hash) ? args.pop : {}
180
+ config.merge!(:before => /\z/)
181
+ insert_into_file(path, *(args << config), &block)
182
+ end
183
+ alias_method :append_file, :append_to_file
184
+
185
+ # Injects text right after the class definition. Since it depends on
186
+ # insert_into_file, it's reversible.
187
+ #
188
+ # ==== Parameters
189
+ # path<String>:: path of the file to be changed
190
+ # klass<String|Class>:: the class to be manipulated
191
+ # data<String>:: the data to append to the class, can be also given as a block.
192
+ # config<Hash>:: give :verbose => false to not log the status.
193
+ #
194
+ # ==== Examples
195
+ #
196
+ # inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n"
197
+ #
198
+ # inject_into_class "app/controllers/application_controller.rb", ApplicationController do
199
+ # " filter_parameter :password\n"
200
+ # end
201
+ #
202
+ def inject_into_class(path, klass, *args, &block)
203
+ config = args.last.is_a?(Hash) ? args.pop : {}
204
+ config.merge!(:after => /class #{klass}\n|class #{klass} .*\n/)
205
+ insert_into_file(path, *(args << config), &block)
206
+ end
207
+
208
+ # Run a regular expression replacement on a file.
209
+ #
210
+ # ==== Parameters
211
+ # path<String>:: path of the file to be changed
212
+ # flag<Regexp|String>:: the regexp or string to be replaced
213
+ # replacement<String>:: the replacement, can be also given as a block
214
+ # config<Hash>:: give :verbose => false to not log the status.
215
+ #
216
+ # ==== Example
217
+ #
218
+ # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
219
+ #
220
+ # gsub_file 'README', /rake/, :green do |match|
221
+ # match << " no more. Use thor!"
222
+ # end
223
+ #
224
+ def gsub_file(path, flag, *args, &block)
225
+ return unless behavior == :invoke
226
+ config = args.last.is_a?(Hash) ? args.pop : {}
227
+
228
+ path = File.expand_path(path, destination_root)
229
+ say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
230
+
231
+ unless options[:pretend]
232
+ content = File.binread(path)
233
+ content.gsub!(flag, *args, &block)
234
+ File.open(path, 'wb') { |file| file.write(content) }
235
+ end
236
+ end
237
+
238
+ # Uncomment all lines matching a given regex. It will leave the space
239
+ # which existed before the comment hash in tact but will remove any spacing
240
+ # between the comment hash and the beginning of the line.
241
+ #
242
+ # ==== Parameters
243
+ # path<String>:: path of the file to be changed
244
+ # flag<Regexp|String>:: the regexp or string used to decide which lines to uncomment
245
+ # config<Hash>:: give :verbose => false to not log the status.
246
+ #
247
+ # ==== Example
248
+ #
249
+ # uncomment_lines 'config/initializers/session_store.rb', /active_record/
250
+ #
251
+ def uncomment_lines(path, flag, *args)
252
+ flag = flag.respond_to?(:source) ? flag.source : flag
253
+
254
+ gsub_file(path, /^(\s*)#[[:blank:]]*(.*#{flag})/, '\1\2', *args)
255
+ end
256
+
257
+ # Comment all lines matching a given regex. It will leave the space
258
+ # which existed before the beginning of the line in tact and will insert
259
+ # a single space after the comment hash.
260
+ #
261
+ # ==== Parameters
262
+ # path<String>:: path of the file to be changed
263
+ # flag<Regexp|String>:: the regexp or string used to decide which lines to comment
264
+ # config<Hash>:: give :verbose => false to not log the status.
265
+ #
266
+ # ==== Example
267
+ #
268
+ # comment_lines 'config/initializers/session_store.rb', /cookie_store/
269
+ #
270
+ def comment_lines(path, flag, *args)
271
+ flag = flag.respond_to?(:source) ? flag.source : flag
272
+
273
+ gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args)
274
+ end
275
+
276
+ # Removes a file at the given location.
277
+ #
278
+ # ==== Parameters
279
+ # path<String>:: path of the file to be changed
280
+ # config<Hash>:: give :verbose => false to not log the status.
281
+ #
282
+ # ==== Example
283
+ #
284
+ # remove_file 'README'
285
+ # remove_file 'app/controllers/application_controller.rb'
286
+ #
287
+ def remove_file(path, config={})
288
+ return unless behavior == :invoke
289
+ path = File.expand_path(path, destination_root)
290
+
291
+ say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true)
292
+ ::FileUtils.rm_rf(path) if !options[:pretend] && File.exists?(path)
293
+ end
294
+ alias :remove_dir :remove_file
295
+
296
+ attr_accessor :output_buffer
297
+ private :output_buffer, :output_buffer=
298
+
299
+ private
300
+
301
+ def concat(string)
302
+ @output_buffer.concat(string)
303
+ end
304
+
305
+ def capture(*args, &block)
306
+ with_output_buffer { block.call(*args) }
307
+ end
308
+
309
+ def with_output_buffer(buf = '') #:nodoc:
310
+ self.output_buffer, old_buffer = buf, output_buffer
311
+ yield
312
+ output_buffer
313
+ ensure
314
+ self.output_buffer = old_buffer
315
+ end
316
+ end
317
+ end
@@ -0,0 +1,109 @@
1
+ require 'thor/actions/empty_directory'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Injects the given content into a file. Different from gsub_file, this
7
+ # method is reversible.
8
+ #
9
+ # ==== Parameters
10
+ # destination<String>:: Relative path to the destination root
11
+ # data<String>:: Data to add to the file. Can be given as a block.
12
+ # config<Hash>:: give :verbose => false to not log the status and the flag
13
+ # for injection (:after or :before) or :force => true for
14
+ # insert two or more times the same content.
15
+ #
16
+ # ==== Examples
17
+ #
18
+ # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
19
+ #
20
+ # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
21
+ # gems = ask "Which gems would you like to add?"
22
+ # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
23
+ # end
24
+ #
25
+ def insert_into_file(destination, *args, &block)
26
+ if block_given?
27
+ data, config = block, args.shift
28
+ else
29
+ data, config = args.shift, args.shift
30
+ end
31
+ action InjectIntoFile.new(self, destination, data, config)
32
+ end
33
+ alias_method :inject_into_file, :insert_into_file
34
+
35
+ class InjectIntoFile < EmptyDirectory #:nodoc:
36
+ attr_reader :replacement, :flag, :behavior
37
+
38
+ def initialize(base, destination, data, config)
39
+ super(base, destination, { :verbose => true }.merge(config))
40
+
41
+ @behavior, @flag = if @config.key?(:after)
42
+ [:after, @config.delete(:after)]
43
+ else
44
+ [:before, @config.delete(:before)]
45
+ end
46
+
47
+ @replacement = data.is_a?(Proc) ? data.call : data
48
+ @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp)
49
+ end
50
+
51
+ def invoke!
52
+ say_status :invoke
53
+
54
+ content = if @behavior == :after
55
+ '\0' + replacement
56
+ else
57
+ replacement + '\0'
58
+ end
59
+
60
+ replace!(/#{flag}/, content, config[:force])
61
+ end
62
+
63
+ def revoke!
64
+ say_status :revoke
65
+
66
+ regexp = if @behavior == :after
67
+ content = '\1\2'
68
+ /(#{flag})(.*)(#{Regexp.escape(replacement)})/m
69
+ else
70
+ content = '\2\3'
71
+ /(#{Regexp.escape(replacement)})(.*)(#{flag})/m
72
+ end
73
+
74
+ replace!(regexp, content, true)
75
+ end
76
+
77
+ protected
78
+
79
+ def say_status(behavior)
80
+ status = if behavior == :invoke
81
+ if flag == /\A/
82
+ :prepend
83
+ elsif flag == /\z/
84
+ :append
85
+ else
86
+ :insert
87
+ end
88
+ else
89
+ :subtract
90
+ end
91
+
92
+ super(status, config[:verbose])
93
+ end
94
+
95
+ # Adds the content to the file.
96
+ #
97
+ def replace!(regexp, string, force)
98
+ unless base.options[:pretend]
99
+ content = File.binread(destination)
100
+ if force || !content.include?(replacement)
101
+ content.gsub!(regexp, string)
102
+ File.open(destination, 'wb') { |file| file.write(content) }
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+ end
109
+ end