wycats-thor 0.9.8 → 0.10.26

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ require 'thor/actions/templater'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Creates an empty directory.
7
+ #
8
+ # ==== Parameters
9
+ # destination<String>:: the relative path to the destination root
10
+ # log_status<Boolean>:: if false, does not log the status. True by default.
11
+ #
12
+ # ==== Examples
13
+ #
14
+ # empty_directory "doc"
15
+ #
16
+ def empty_directory(destination, log_status=true)
17
+ action EmptyDirectory.new(self, nil, destination, log_status)
18
+ end
19
+
20
+ class EmptyDirectory < Templater #:nodoc:
21
+
22
+ def invoke!
23
+ invoke_with_options!(base.options) do
24
+ ::FileUtils.mkdir_p(destination)
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,58 @@
1
+ require 'thor/actions/templater'
2
+ require 'open-uri'
3
+
4
+ class Thor
5
+ module Actions
6
+
7
+ # Gets the content at the given address and places it at the given relative
8
+ # destination. If a block is given instead of destination, the content of
9
+ # the url is yielded and used as location.
10
+ #
11
+ # ==== Parameters
12
+ # source<String>:: the address of the given content
13
+ # destination<String>:: the relative path to the destination root
14
+ # log_status<Boolean>:: if false, does not log the status. True by default.
15
+ #
16
+ # ==== Examples
17
+ #
18
+ # get "http://gist.github.com/103208", "doc/README"
19
+ #
20
+ # get "http://gist.github.com/103208" do |content|
21
+ # content.split("\n").first
22
+ # end
23
+ #
24
+ def get(source, destination=nil, log_status=true, &block)
25
+ action Get.new(self, source, block || destination, log_status)
26
+ end
27
+
28
+ class Get < Templater #:nodoc:
29
+
30
+ def render
31
+ @render ||= open(source).read
32
+ end
33
+
34
+ protected
35
+
36
+ def source=(source)
37
+ if source =~ /^http\:\/\//
38
+ @source = source
39
+ else
40
+ super(source)
41
+ end
42
+ end
43
+
44
+ def destination=(destination)
45
+ destination = if destination.nil?
46
+ File.basename(source)
47
+ elsif destination.is_a?(Proc)
48
+ destination.arity == 1 ? destination.call(render) : destination.call
49
+ else
50
+ destination
51
+ end
52
+
53
+ super(destination)
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,93 @@
1
+ class Thor
2
+ module Actions
3
+
4
+ # Injects the given content into a file. Different from append_file,
5
+ # prepend_file and gsub_file, this method is reversible. By this reason,
6
+ # the flag can only be strings. gsub_file is your friend if you need to
7
+ # deal with more complex cases.
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
+ # flag<String>:: Flag of where to add the changes.
13
+ # log_status<Boolean>:: If false, does not log the status. True by default.
14
+ # If a symbol is given, uses it as the output color.
15
+ #
16
+ # ==== Examples
17
+ #
18
+ # inject_into_file "config/environment.rb", "config.gem thor", :after => "Rails::Initializer.run do |config|\n"
19
+ #
20
+ # inject_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 inject_into_file(destination, *args, &block)
26
+ if block_given?
27
+ data, flag = block, args.shift
28
+ else
29
+ data, flag = args.shift, args.shift
30
+ end
31
+
32
+ log_status = args.empty? || args.pop
33
+ action InjectIntoFile.new(self, destination, data, flag, log_status)
34
+ end
35
+
36
+ class InjectIntoFile #:nodoc:
37
+ attr_reader :base, :destination, :relative_destination, :flag, :replacement
38
+
39
+ def initialize(base, destination, data, flag, log_status=true)
40
+ @base, @log_status = base, log_status
41
+ behavior, @flag = flag.keys.first, flag.values.first
42
+
43
+ self.destination = destination
44
+ data = data.call if data.is_a?(Proc)
45
+
46
+ @replacement = if behavior == :after
47
+ @flag + data
48
+ else
49
+ data + @flag
50
+ end
51
+ end
52
+
53
+ def invoke!
54
+ say_status :inject
55
+ replace!(flag, replacement)
56
+ end
57
+
58
+ def revoke!
59
+ say_status :deinject
60
+ replace!(replacement, flag)
61
+ end
62
+
63
+ protected
64
+
65
+ # Sets the destination value from a relative destination value. The
66
+ # relative destination is kept to be used in output messages.
67
+ #
68
+ def destination=(destination)
69
+ if destination
70
+ @destination = ::File.expand_path(destination.to_s, base.destination_root)
71
+ @relative_destination = base.relative_to_absolute_root(@destination)
72
+ end
73
+ end
74
+
75
+ # Shortcut to say_status shell method.
76
+ #
77
+ def say_status(status)
78
+ base.shell.say_status status, relative_destination, @log_status
79
+ end
80
+
81
+ # Adds the content to the file.
82
+ #
83
+ def replace!(regexp, string)
84
+ unless base.options[:pretend]
85
+ content = File.read(destination)
86
+ content.gsub!(regexp, string)
87
+ File.open(destination, 'wb') { |file| file.write(content) }
88
+ end
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,38 @@
1
+ require 'thor/actions/templater'
2
+ require 'erb'
3
+
4
+ class Thor
5
+ module Actions
6
+
7
+ # Gets an ERB template at the relative source, executes it and makes a copy
8
+ # at the relative destination. If the destination is not given it's assumed
9
+ # to be equal to the source removing .tt from the filename.
10
+ #
11
+ # ==== Parameters
12
+ # source<String>:: the relative path to the source root
13
+ # destination<String>:: the relative path to the destination root
14
+ # log_status<Boolean>:: if false, does not log the status. True by default.
15
+ #
16
+ # ==== Examples
17
+ #
18
+ # template "README", "doc/README"
19
+ #
20
+ # template "doc/README"
21
+ #
22
+ def template(source, destination=nil, log_status=true)
23
+ destination ||= source.gsub(/.tt$/, '')
24
+ action Template.new(self, source, destination, log_status)
25
+ end
26
+
27
+ class Template < Templater #:nodoc:
28
+
29
+ def render
30
+ @render ||= begin
31
+ context = base.instance_eval('binding')
32
+ ERB.new(::File.read(source), nil, '-').result(context)
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,195 @@
1
+ class Thor
2
+ module Actions
3
+
4
+ # This is the base class for templater actions, ie. that copies something
5
+ # from some directory (source) to another (destination).
6
+ #
7
+ # This implementation is completely based in Templater actions, created
8
+ # by Jonas Nicklas and Michael S. Klishin under MIT LICENSE.
9
+ #
10
+ class Templater #:nodoc:
11
+ attr_reader :base, :source, :destination, :given_destination, :relative_destination
12
+
13
+ # Initializes given the source and destination.
14
+ #
15
+ # ==== Parameters
16
+ # base<Thor::Base>:: A Thor::Base instance
17
+ # source<String>:: Relative path to the source of this file
18
+ # destination<String>:: Relative path to the destination of this file
19
+ # log_status<Boolean>:: If false, does not log the status. True by default.
20
+ # Templater log status does not accept color.
21
+ #
22
+ def initialize(base, source, destination, log_status=true)
23
+ @base, @log_status = base, log_status
24
+ self.source = source
25
+ self.destination = destination
26
+ end
27
+
28
+ # Returns the contents of the source file as a String. If render is
29
+ # available, a diff option is shown in the file collision menu.
30
+ #
31
+ # ==== Returns
32
+ # String:: The source file.
33
+ #
34
+ # def render
35
+ # end
36
+
37
+ # Checks if the destination file already exists.
38
+ #
39
+ # ==== Returns
40
+ # Boolean:: true if the file exists, false otherwise.
41
+ #
42
+ def exists?
43
+ ::File.exists?(destination)
44
+ end
45
+
46
+ # Checks if the content of the file at the destination is identical to the rendered result.
47
+ #
48
+ # ==== Returns
49
+ # Boolean:: true if it is identical, false otherwise.
50
+ #
51
+ def identical?
52
+ exists? && (is_not_comparable? || ::File.read(destination) == render)
53
+ end
54
+
55
+ # Invokes the action. By default it adds to the file the content rendered,
56
+ # but you can modify in the subclass.
57
+ #
58
+ def invoke!
59
+ invoke_with_options!(base.options) do
60
+ ::FileUtils.mkdir_p(::File.dirname(destination))
61
+ ::File.open(destination, 'w'){ |f| f.write render }
62
+ end
63
+ end
64
+
65
+ # Revokes the action.
66
+ #
67
+ def revoke!
68
+ say_status :remove, :red
69
+ ::FileUtils.rm_rf(destination) if !pretend? && exists?
70
+ end
71
+
72
+ protected
73
+
74
+ # Shortcut for pretend.
75
+ #
76
+ def pretend?
77
+ base.options[:pretend]
78
+ end
79
+
80
+ # A templater is comparable if responds to render. In such cases, we have
81
+ # to show the conflict menu to the user unless the files are identical.
82
+ #
83
+ def is_not_comparable?
84
+ !respond_to?(:render)
85
+ end
86
+
87
+ # Sets the absolute source value from a relative source value. Notice
88
+ # that we need to take into consideration both the source_root as the
89
+ # relative_root.
90
+ #
91
+ # Let's suppose that we are on the directory "dest", with source root set
92
+ # to "source" and with the following scenario:
93
+ #
94
+ # inside "bar" do
95
+ # copy_file "baz.rb"
96
+ # end
97
+ #
98
+ # In this case, the user wants to copy the file at "source/bar/baz.rb"
99
+ # to "dest/bar/baz.rb". If we don't take into account the relative_root
100
+ # (in this case, "bar"), it would copy the contents at "source/baz.rb".
101
+ #
102
+ def source=(source)
103
+ if source
104
+ @source = ::File.expand_path(source.to_s, File.join(base.source_root, base.relative_root))
105
+ end
106
+ end
107
+
108
+ # Sets the absolute destination value from a relative destination value.
109
+ # It also stores the given and relative destination. Let's suppose our
110
+ # script is being executed on "dest", it sets the destination root to
111
+ # "dest". The destination, given_destination and relative_destination
112
+ # are related in the following way:
113
+ #
114
+ # inside "bar" do
115
+ # empty_directory "baz"
116
+ # end
117
+ #
118
+ # destination #=> dest/bar/baz
119
+ # relative_destination #=> bar/baz
120
+ # given_destination #=> baz
121
+ #
122
+ def destination=(destination)
123
+ if destination
124
+ @given_destination = convert_encoded_instructions(destination.to_s)
125
+ @destination = ::File.expand_path(@given_destination, base.destination_root)
126
+ @relative_destination = base.relative_to_absolute_root(@destination)
127
+ end
128
+ end
129
+
130
+ # Filenames in the encoded form are converted. If you have a file:
131
+ #
132
+ # %class_name%.rb
133
+ #
134
+ # It gets the class name from the base and replace it:
135
+ #
136
+ # user.rb
137
+ #
138
+ def convert_encoded_instructions(filename)
139
+ filename.gsub(/%(.*?)%/) do |string|
140
+ instruction = $1.strip
141
+ base.respond_to?(instruction) ? base.send(instruction) : string
142
+ end
143
+ end
144
+
145
+ # Receives a hash of options and just execute the block if some
146
+ # conditions are met.
147
+ #
148
+ def invoke_with_options!(options, &block)
149
+ if exists?
150
+ if is_not_comparable?
151
+ say_status :exist, :blue
152
+ elsif identical?
153
+ say_status :identical, :blue
154
+ else
155
+ force_or_skip_or_conflict(options[:force], options[:skip], &block)
156
+ end
157
+ else
158
+ say_status :create, :green
159
+ block.call unless pretend?
160
+ end
161
+
162
+ destination
163
+ end
164
+
165
+ # If force is true, run the action, otherwise check if it's not being
166
+ # skipped. If both are false, show the file_collision menu, if the menu
167
+ # returns true, force it, otherwise skip.
168
+ #
169
+ def force_or_skip_or_conflict(force, skip, &block)
170
+ if force
171
+ say_status :force, :yellow
172
+ block.call unless pretend?
173
+ elsif skip
174
+ say_status :skip, :yellow
175
+ else
176
+ say_status :conflict, :red
177
+ force_or_skip_or_conflict(force_on_collision?, true, &block)
178
+ end
179
+ end
180
+
181
+ # Shows the file collision menu to the user and gets the result.
182
+ #
183
+ def force_on_collision?
184
+ base.shell.file_collision(destination){ render }
185
+ end
186
+
187
+ # Shortcut to say_status shell method.
188
+ #
189
+ def say_status(status, color)
190
+ base.shell.say_status status, relative_destination, color if @log_status
191
+ end
192
+
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,328 @@
1
+ require 'fileutils'
2
+
3
+ Dir[File.join(File.dirname(__FILE__), "actions", "*.rb")].each do |action|
4
+ require action
5
+ end
6
+
7
+ class Thor
8
+ # Some actions require that a class method called source root is defined in
9
+ # the class. Remember to always cache the source root value, because Ruby
10
+ # __FILE__ always return the relative path, which may lead to mistakes if you
11
+ # are calling an action inside the "inside(path)" method.
12
+ #
13
+ module Actions
14
+ attr_accessor :behavior
15
+
16
+ # On inclusion, add some options to base.
17
+ #
18
+ def self.included(base) #:nodoc:
19
+ return unless base.respond_to?(:class_option)
20
+
21
+ base.class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
22
+ :desc => "Run but do not make any changes"
23
+
24
+ base.class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
25
+ :desc => "Overwrite files that already exist"
26
+
27
+ base.class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
28
+ :desc => "Skip files that already exist"
29
+
30
+ base.class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
31
+ :desc => "Supress status output"
32
+ end
33
+
34
+ # Extends initializer to add more configuration options.
35
+ #
36
+ # ==== Configuration
37
+ # behavior<Symbol>:: The actions default behavior. Can be :invoke or :revoke.
38
+ # It also accepts :force, :skip and :pretend to set the behavior
39
+ # and the respective option.
40
+ #
41
+ # root<String>:: The root directory needed for some actions. It's also known
42
+ # as destination root.
43
+ #
44
+ def initialize(args=[], options={}, config={})
45
+ self.behavior = case config[:behavior].to_s
46
+ when "force", "skip"
47
+ _cleanup_options_and_set(options, config[:behavior])
48
+ :invoke
49
+ when "revoke"
50
+ :revoke
51
+ else
52
+ :invoke
53
+ end
54
+
55
+ super
56
+ self.root = config[:root]
57
+ end
58
+
59
+ # Wraps an action object and call it accordingly to the thor class behavior.
60
+ #
61
+ def action(instance)
62
+ if behavior == :revoke
63
+ instance.revoke!
64
+ else
65
+ instance.invoke!
66
+ end
67
+ end
68
+
69
+ # Returns the root for this thor class (also aliased as destination root).
70
+ #
71
+ def root
72
+ @root_stack.last
73
+ end
74
+ alias :destination_root :root
75
+
76
+ # Sets the root for this thor class. Relatives path are added to the
77
+ # directory where the script was invoked and expanded.
78
+ #
79
+ def root=(root)
80
+ @root_stack ||= []
81
+ @root_stack[0] = File.expand_path(root || '')
82
+ end
83
+
84
+ # Gets the current root relative to the absolute root.
85
+ #
86
+ # inside "foo" do
87
+ # relative_root #=> "foo"
88
+ # end
89
+ #
90
+ def relative_root(remove_dot=true)
91
+ relative_to_absolute_root(root, remove_dot)
92
+ end
93
+
94
+ # Returns the given path relative to the absolute root (ie, root where
95
+ # the script started).
96
+ #
97
+ def relative_to_absolute_root(path, remove_dot=true)
98
+ path = path.gsub(@root_stack[0], '.')
99
+ remove_dot ? (path[2..-1] || '') : path
100
+ end
101
+
102
+ # Get the source root in the class. Raises an error if a source root is
103
+ # not specified in the thor class.
104
+ #
105
+ def source_root
106
+ self.class.source_root
107
+ rescue NoMethodError => e
108
+ raise NoMethodError, "You have to specify the class method source_root in your thor class."
109
+ end
110
+
111
+ # Do something in the root or on a provided subfolder. If a relative path
112
+ # is given it's referenced from the current root. The full path is yielded
113
+ # to the block you provide. The path is set back to the previous path when
114
+ # the method exits.
115
+ #
116
+ # ==== Parameters
117
+ # dir<String>:: the directory to move to.
118
+ #
119
+ def inside(dir='', &block)
120
+ @root_stack.push File.expand_path(dir, root)
121
+ FileUtils.mkdir_p(root) unless File.exist?(root)
122
+ FileUtils.cd(root) { block.arity == 1 ? yield(root) : yield }
123
+ @root_stack.pop
124
+ end
125
+
126
+ # Goes to the root and execute the given block.
127
+ #
128
+ def in_root
129
+ inside(@root_stack.first) { yield }
130
+ end
131
+
132
+ # Changes the mode of the given file or directory.
133
+ #
134
+ # ==== Parameters
135
+ # mode<Integer>:: the file mode
136
+ # path<String>:: the name of the file to change mode
137
+ # log_status<Boolean>:: if false, does not log the status. True by default.
138
+ # If a symbol is given, uses it as the output color.
139
+ #
140
+ # ==== Example
141
+ #
142
+ # chmod "script/*", 0755
143
+ #
144
+ def chmod(path, mode, log_status=true)
145
+ return unless behavior == :invoke
146
+ path = File.expand_path(path, root)
147
+ say_status :chmod, relative_to_absolute_root(path), log_status
148
+ FileUtils.chmod_R(mode, path) unless options[:pretend]
149
+ end
150
+
151
+ # Executes a command.
152
+ #
153
+ # ==== Parameters
154
+ # command<String>:: the command to be executed.
155
+ # log_status<Boolean>:: if false, does not log the status. True by default.
156
+ # If a symbol is given, uses it as the output color.
157
+ #
158
+ # ==== Example
159
+ #
160
+ # inside('vendor') do
161
+ # run('ln -s ~/edge rails')
162
+ # end
163
+ #
164
+ def run(command, log_status=true)
165
+ return unless behavior == :invoke
166
+ say_status :run, "\"#{command}\" from #{relative_to_absolute_root(root, false)}", log_status
167
+ `#{command}` unless options[:pretend]
168
+ end
169
+
170
+ # Executes a ruby script (taking into account WIN32 platform quirks).
171
+ #
172
+ # ==== Parameters
173
+ # command<String>:: the command to be executed.
174
+ # log_status<Boolean>:: if false, does not log the status. True by default.
175
+ # If a symbol is given, uses it as the output color.
176
+ #
177
+ def run_ruby_script(command, log_status=true)
178
+ return unless behavior == :invoke
179
+ say_status File.basename(Thor::Util.ruby_command), command, log_status
180
+ `#{Thor::Util.ruby_command} #{command}` unless options[:pretend]
181
+ end
182
+
183
+ # Run a thor command. A hash of options can be given and it's converted to
184
+ # switches.
185
+ #
186
+ # ==== Parameters
187
+ # task<String>:: the task to be invoked
188
+ # args<Array>:: arguments to the task
189
+ # options<Hash>:: a hash with options used on invocation
190
+ # log_status<Boolean>:: if false, does not log the status. True by default.
191
+ # If a symbol is given, uses it as the output color.
192
+ #
193
+ # ==== Examples
194
+ #
195
+ # thor :install, "http://gist.github.com/103208"
196
+ # #=> thor install http://gist.github.com/103208
197
+ #
198
+ # thor :list, :all => true, :substring => 'rails'
199
+ # #=> thor list --all --substring=rails
200
+ #
201
+ def thor(task, *args)
202
+ log_status = args.last.is_a?(Symbol) || [true, false].include?(args.last) ? args.pop : true
203
+ options = args.last.is_a?(Hash) ? args.pop : {}
204
+
205
+ args.unshift task
206
+ args.push Thor::Options.to_switches(options)
207
+ command = args.join(' ').strip
208
+
209
+ say_status :thor, command, log_status
210
+ run "thor #{command}", false
211
+ end
212
+
213
+ # Removes a file at the given location.
214
+ #
215
+ # ==== Parameters
216
+ # path<String>:: path of the file to be changed
217
+ # log_status<Boolean>:: if false, does not log the status. True by default.
218
+ # If a symbol is given, uses it as the output color.
219
+ #
220
+ # ==== Example
221
+ #
222
+ # remove_file 'README'
223
+ # remove_file 'app/controllers/application_controller.rb'
224
+ #
225
+ def remove_file(path, log_status=true)
226
+ return unless behavior == :invoke
227
+ path = File.expand_path(path, root)
228
+ color = log_status.is_a?(Symbol) ? log_status : :red
229
+
230
+ say_status :remove, relative_to_absolute_root(path), log_status
231
+ ::FileUtils.rm_rf(path) if !options[:pretend] && File.exists?(path)
232
+ end
233
+
234
+ # Run a regular expression replacement on a file.
235
+ #
236
+ # ==== Parameters
237
+ # path<String>:: path of the file to be changed
238
+ # flag<Regexp|String>:: the regexp or string to be replaced
239
+ # replacement<String>:: the replacement, can be also given as a block
240
+ # log_status<Boolean>:: if false, does not log the status. True by default.
241
+ # If a symbol is given, uses it as the output color.
242
+ #
243
+ # ==== Example
244
+ #
245
+ # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
246
+ #
247
+ # gsub_file 'README', /rake/, :green do |match|
248
+ # match << " no more. Use thor!"
249
+ # end
250
+ #
251
+ def gsub_file(path, flag, *args, &block)
252
+ return unless behavior == :invoke
253
+ log_status = args.last.is_a?(Symbol) || [ true, false ].include?(args.last) ? args.pop : true
254
+
255
+ path = File.expand_path(path, root)
256
+ say_status :gsub, relative_to_absolute_root(path), log_status
257
+
258
+ unless options[:pretend]
259
+ content = File.read(path)
260
+ content.gsub!(flag, *args, &block)
261
+ File.open(path, 'wb') { |file| file.write(content) }
262
+ end
263
+ end
264
+
265
+ # Append text to a file.
266
+ #
267
+ # ==== Parameters
268
+ # path<String>:: path of the file to be changed
269
+ # data<String>:: the data to append to the file, can be also given as a block.
270
+ # log_status<Boolean>:: if false, does not log the status. True by default.
271
+ # If a symbol is given, uses it as the output color.
272
+ #
273
+ # ==== Example
274
+ #
275
+ # append_file 'config/environments/test.rb', 'config.gem "rspec"'
276
+ #
277
+ def append_file(path, data=nil, log_status=true, &block)
278
+ return unless behavior == :invoke
279
+ path = File.expand_path(path, root)
280
+ say_status :append, relative_to_absolute_root(path), log_status
281
+ File.open(path, 'ab') { |file| file.write(data || block.call) } unless options[:pretend]
282
+ end
283
+
284
+ # Prepend text to a file.
285
+ #
286
+ # ==== Parameters
287
+ # path<String>:: path of the file to be changed
288
+ # data<String>:: the data to prepend to the file, can be also given as a block.
289
+ # log_status<Boolean>:: if false, does not log the status. True by default.
290
+ # If a symbol is given, uses it as the output color.
291
+ #
292
+ # ==== Example
293
+ #
294
+ # prepend_file 'config/environments/test.rb', 'config.gem "rspec"'
295
+ #
296
+ def prepend_file(path, data=nil, log_status=true, &block)
297
+ return unless behavior == :invoke
298
+ path = File.expand_path(path, root)
299
+ say_status :prepend, relative_to_absolute_root(path), log_status
300
+
301
+ unless options[:pretend]
302
+ content = data || block.call
303
+ content << File.read(path)
304
+ File.open(path, 'wb') { |file| file.write(content) }
305
+ end
306
+ end
307
+
308
+ protected
309
+
310
+ # Allow current root to be shared between invocations.
311
+ #
312
+ def _shared_configuration #:nodoc:
313
+ super.merge!(:root => self.root)
314
+ end
315
+
316
+ def _cleanup_options_and_set(options, key) #:nodoc:
317
+ case options
318
+ when Array
319
+ %w(--force -f --skip -s).each { |i| options.delete(i) }
320
+ options << "--#{key}"
321
+ when Hash
322
+ [:force, :skip, "force", "skip"].each { |i| options.delete(i) }
323
+ options.merge!(key => true)
324
+ end
325
+ end
326
+
327
+ end
328
+ end