foreman 0.85.0 → 0.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/data/export/systemd/master.target.erb +1 -1
  4. data/data/export/systemd/process.service.erb +6 -3
  5. data/lib/foreman/cli.rb +3 -3
  6. data/lib/foreman/export/systemd.rb +7 -13
  7. data/lib/foreman/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  8. data/lib/foreman/vendor/thor/lib/thor/actions/create_link.rb +59 -0
  9. data/lib/foreman/vendor/thor/lib/thor/actions/directory.rb +118 -0
  10. data/lib/foreman/vendor/thor/lib/thor/actions/empty_directory.rb +135 -0
  11. data/lib/foreman/vendor/thor/lib/thor/actions/file_manipulation.rb +327 -0
  12. data/lib/foreman/vendor/thor/lib/thor/actions/inject_into_file.rb +103 -0
  13. data/lib/foreman/vendor/thor/lib/thor/actions.rb +318 -0
  14. data/lib/foreman/vendor/thor/lib/thor/base.rb +656 -0
  15. data/lib/foreman/vendor/thor/lib/thor/command.rb +133 -0
  16. data/lib/foreman/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +85 -0
  17. data/lib/foreman/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
  18. data/lib/foreman/vendor/thor/lib/thor/core_ext/ordered_hash.rb +129 -0
  19. data/lib/foreman/vendor/thor/lib/thor/error.rb +32 -0
  20. data/lib/foreman/vendor/thor/lib/thor/group.rb +281 -0
  21. data/lib/foreman/vendor/thor/lib/thor/invocation.rb +177 -0
  22. data/lib/foreman/vendor/thor/lib/thor/line_editor/basic.rb +35 -0
  23. data/lib/foreman/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
  24. data/lib/foreman/vendor/thor/lib/thor/line_editor.rb +17 -0
  25. data/lib/foreman/vendor/thor/lib/thor/parser/argument.rb +70 -0
  26. data/lib/foreman/vendor/thor/lib/thor/parser/arguments.rb +175 -0
  27. data/lib/foreman/vendor/thor/lib/thor/parser/option.rb +146 -0
  28. data/lib/foreman/vendor/thor/lib/thor/parser/options.rb +220 -0
  29. data/lib/foreman/vendor/thor/lib/thor/parser.rb +4 -0
  30. data/lib/foreman/vendor/thor/lib/thor/rake_compat.rb +71 -0
  31. data/lib/foreman/vendor/thor/lib/thor/runner.rb +322 -0
  32. data/lib/foreman/vendor/thor/lib/thor/shell/basic.rb +436 -0
  33. data/lib/foreman/vendor/thor/lib/thor/shell/color.rb +149 -0
  34. data/lib/foreman/vendor/thor/lib/thor/shell/html.rb +126 -0
  35. data/lib/foreman/vendor/thor/lib/thor/shell.rb +81 -0
  36. data/lib/foreman/vendor/thor/lib/thor/util.rb +268 -0
  37. data/lib/foreman/vendor/thor/lib/thor/version.rb +3 -0
  38. data/lib/foreman/vendor/thor/lib/thor.rb +492 -0
  39. data/lib/foreman/version.rb +1 -1
  40. data/man/foreman.1 +1 -1
  41. data/spec/foreman/export/systemd_spec.rb +88 -46
  42. data/spec/resources/export/systemd/{app-alpha@.service → app-alpha.1.service} +6 -3
  43. data/spec/resources/export/systemd/{app-bravo@.service → app-alpha.2.service} +6 -3
  44. data/spec/resources/export/systemd/app-bravo.1.service +18 -0
  45. data/spec/resources/export/systemd/app.target +1 -1
  46. data/spec/spec_helper.rb +1 -1
  47. metadata +39 -22
  48. data/data/export/systemd/process_master.target.erb +0 -2
@@ -0,0 +1,327 @@
1
+ require "erb"
2
+ require "open-uri"
3
+
4
+ class Foreman::Thor
5
+ module Actions
6
+ # Copies the file from the relative source to the relative destination. If
7
+ # the destination is not given it's assumed to be equal to the source.
8
+ #
9
+ # ==== Parameters
10
+ # source<String>:: the relative path to the source root.
11
+ # destination<String>:: the relative path to the destination root.
12
+ # config<Hash>:: give :verbose => false to not log the status, and
13
+ # :mode => :preserve, to preserve the file mode from the source.
14
+
15
+ #
16
+ # ==== Examples
17
+ #
18
+ # copy_file "README", "doc/README"
19
+ #
20
+ # copy_file "doc/README"
21
+ #
22
+ def copy_file(source, *args, &block)
23
+ config = args.last.is_a?(Hash) ? args.pop : {}
24
+ destination = args.first || source
25
+ source = File.expand_path(find_in_source_paths(source.to_s))
26
+
27
+ create_file destination, nil, config do
28
+ content = File.binread(source)
29
+ content = yield(content) if block
30
+ content
31
+ end
32
+ if config[:mode] == :preserve
33
+ mode = File.stat(source).mode
34
+ chmod(destination, mode, config)
35
+ end
36
+ end
37
+
38
+ # Links the file from the relative source to the relative destination. If
39
+ # the destination is not given it's assumed to be equal to the source.
40
+ #
41
+ # ==== Parameters
42
+ # source<String>:: the relative path to the source root.
43
+ # destination<String>:: the relative path to the destination root.
44
+ # config<Hash>:: give :verbose => false to not log the status.
45
+ #
46
+ # ==== Examples
47
+ #
48
+ # link_file "README", "doc/README"
49
+ #
50
+ # link_file "doc/README"
51
+ #
52
+ def link_file(source, *args)
53
+ config = args.last.is_a?(Hash) ? args.pop : {}
54
+ destination = args.first || source
55
+ source = File.expand_path(find_in_source_paths(source.to_s))
56
+
57
+ create_link destination, source, config
58
+ end
59
+
60
+ # Gets the content at the given address and places it at the given relative
61
+ # destination. If a block is given instead of destination, the content of
62
+ # the url is yielded and used as location.
63
+ #
64
+ # ==== Parameters
65
+ # source<String>:: the address of the given content.
66
+ # destination<String>:: the relative path to the destination root.
67
+ # config<Hash>:: give :verbose => false to not log the status.
68
+ #
69
+ # ==== Examples
70
+ #
71
+ # get "http://gist.github.com/103208", "doc/README"
72
+ #
73
+ # get "http://gist.github.com/103208" do |content|
74
+ # content.split("\n").first
75
+ # end
76
+ #
77
+ def get(source, *args, &block)
78
+ config = args.last.is_a?(Hash) ? args.pop : {}
79
+ destination = args.first
80
+
81
+ source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ %r{^https?\://}
82
+ render = open(source) { |input| input.binmode.read }
83
+
84
+ destination ||= if block_given?
85
+ block.arity == 1 ? yield(render) : yield
86
+ else
87
+ File.basename(source)
88
+ end
89
+
90
+ create_file destination, render, config
91
+ end
92
+
93
+ # Gets an ERB template at the relative source, executes it and makes a copy
94
+ # at the relative destination. If the destination is not given it's assumed
95
+ # to be equal to the source removing .tt from the filename.
96
+ #
97
+ # ==== Parameters
98
+ # source<String>:: the relative path to the source root.
99
+ # destination<String>:: the relative path to the destination root.
100
+ # config<Hash>:: give :verbose => false to not log the status.
101
+ #
102
+ # ==== Examples
103
+ #
104
+ # template "README", "doc/README"
105
+ #
106
+ # template "doc/README"
107
+ #
108
+ def template(source, *args, &block)
109
+ config = args.last.is_a?(Hash) ? args.pop : {}
110
+ destination = args.first || source.sub(/#{TEMPLATE_EXTNAME}$/, "")
111
+
112
+ source = File.expand_path(find_in_source_paths(source.to_s))
113
+ context = config.delete(:context) || instance_eval("binding")
114
+
115
+ create_file destination, nil, config do
116
+ content = CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer").result(context)
117
+ content = yield(content) if block
118
+ content
119
+ end
120
+ end
121
+
122
+ # Changes the mode of the given file or directory.
123
+ #
124
+ # ==== Parameters
125
+ # mode<Integer>:: the file mode
126
+ # path<String>:: the name of the file to change mode
127
+ # config<Hash>:: give :verbose => false to not log the status.
128
+ #
129
+ # ==== Example
130
+ #
131
+ # chmod "script/server", 0755
132
+ #
133
+ def chmod(path, mode, config = {})
134
+ return unless behavior == :invoke
135
+ path = File.expand_path(path, destination_root)
136
+ say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true)
137
+ FileUtils.chmod_R(mode, path) unless options[:pretend]
138
+ end
139
+
140
+ # Prepend text to a file. Since it depends on insert_into_file, it's reversible.
141
+ #
142
+ # ==== Parameters
143
+ # path<String>:: path of the file to be changed
144
+ # data<String>:: the data to prepend to the file, can be also given as a block.
145
+ # config<Hash>:: give :verbose => false to not log the status.
146
+ #
147
+ # ==== Example
148
+ #
149
+ # prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"'
150
+ #
151
+ # prepend_to_file 'config/environments/test.rb' do
152
+ # 'config.gem "rspec"'
153
+ # end
154
+ #
155
+ def prepend_to_file(path, *args, &block)
156
+ config = args.last.is_a?(Hash) ? args.pop : {}
157
+ config[:after] = /\A/
158
+ insert_into_file(path, *(args << config), &block)
159
+ end
160
+ alias_method :prepend_file, :prepend_to_file
161
+
162
+ # Append text to a file. Since it depends on insert_into_file, it's reversible.
163
+ #
164
+ # ==== Parameters
165
+ # path<String>:: path of the file to be changed
166
+ # data<String>:: the data to append to the file, can be also given as a block.
167
+ # config<Hash>:: give :verbose => false to not log the status.
168
+ #
169
+ # ==== Example
170
+ #
171
+ # append_to_file 'config/environments/test.rb', 'config.gem "rspec"'
172
+ #
173
+ # append_to_file 'config/environments/test.rb' do
174
+ # 'config.gem "rspec"'
175
+ # end
176
+ #
177
+ def append_to_file(path, *args, &block)
178
+ config = args.last.is_a?(Hash) ? args.pop : {}
179
+ config[:before] = /\z/
180
+ insert_into_file(path, *(args << config), &block)
181
+ end
182
+ alias_method :append_file, :append_to_file
183
+
184
+ # Injects text right after the class definition. Since it depends on
185
+ # insert_into_file, it's reversible.
186
+ #
187
+ # ==== Parameters
188
+ # path<String>:: path of the file to be changed
189
+ # klass<String|Class>:: the class to be manipulated
190
+ # data<String>:: the data to append to the class, can be also given as a block.
191
+ # config<Hash>:: give :verbose => false to not log the status.
192
+ #
193
+ # ==== Examples
194
+ #
195
+ # inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n"
196
+ #
197
+ # inject_into_class "app/controllers/application_controller.rb", ApplicationController do
198
+ # " filter_parameter :password\n"
199
+ # end
200
+ #
201
+ def inject_into_class(path, klass, *args, &block)
202
+ config = args.last.is_a?(Hash) ? args.pop : {}
203
+ config[:after] = /class #{klass}\n|class #{klass} .*\n/
204
+ insert_into_file(path, *(args << config), &block)
205
+ end
206
+
207
+ # Run a regular expression replacement on a file.
208
+ #
209
+ # ==== Parameters
210
+ # path<String>:: path of the file to be changed
211
+ # flag<Regexp|String>:: the regexp or string to be replaced
212
+ # replacement<String>:: the replacement, can be also given as a block
213
+ # config<Hash>:: give :verbose => false to not log the status.
214
+ #
215
+ # ==== Example
216
+ #
217
+ # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
218
+ #
219
+ # gsub_file 'README', /rake/, :green do |match|
220
+ # match << " no more. Use thor!"
221
+ # end
222
+ #
223
+ def gsub_file(path, flag, *args, &block)
224
+ return unless behavior == :invoke
225
+ config = args.last.is_a?(Hash) ? args.pop : {}
226
+
227
+ path = File.expand_path(path, destination_root)
228
+ say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
229
+
230
+ unless options[:pretend]
231
+ content = File.binread(path)
232
+ content.gsub!(flag, *args, &block)
233
+ File.open(path, "wb") { |file| file.write(content) }
234
+ end
235
+ end
236
+
237
+ # Uncomment all lines matching a given regex. It will leave the space
238
+ # which existed before the comment hash in tact but will remove any spacing
239
+ # between the comment hash and the beginning of the line.
240
+ #
241
+ # ==== Parameters
242
+ # path<String>:: path of the file to be changed
243
+ # flag<Regexp|String>:: the regexp or string used to decide which lines to uncomment
244
+ # config<Hash>:: give :verbose => false to not log the status.
245
+ #
246
+ # ==== Example
247
+ #
248
+ # uncomment_lines 'config/initializers/session_store.rb', /active_record/
249
+ #
250
+ def uncomment_lines(path, flag, *args)
251
+ flag = flag.respond_to?(:source) ? flag.source : flag
252
+
253
+ gsub_file(path, /^(\s*)#[[:blank:]]*(.*#{flag})/, '\1\2', *args)
254
+ end
255
+
256
+ # Comment all lines matching a given regex. It will leave the space
257
+ # which existed before the beginning of the line in tact and will insert
258
+ # a single space after the comment hash.
259
+ #
260
+ # ==== Parameters
261
+ # path<String>:: path of the file to be changed
262
+ # flag<Regexp|String>:: the regexp or string used to decide which lines to comment
263
+ # config<Hash>:: give :verbose => false to not log the status.
264
+ #
265
+ # ==== Example
266
+ #
267
+ # comment_lines 'config/initializers/session_store.rb', /cookie_store/
268
+ #
269
+ def comment_lines(path, flag, *args)
270
+ flag = flag.respond_to?(:source) ? flag.source : flag
271
+
272
+ gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args)
273
+ end
274
+
275
+ # Removes a file at the given location.
276
+ #
277
+ # ==== Parameters
278
+ # path<String>:: path of the file to be changed
279
+ # config<Hash>:: give :verbose => false to not log the status.
280
+ #
281
+ # ==== Example
282
+ #
283
+ # remove_file 'README'
284
+ # remove_file 'app/controllers/application_controller.rb'
285
+ #
286
+ def remove_file(path, config = {})
287
+ return unless behavior == :invoke
288
+ path = File.expand_path(path, destination_root)
289
+
290
+ say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true)
291
+ ::FileUtils.rm_rf(path) if !options[:pretend] && File.exist?(path)
292
+ end
293
+ alias_method :remove_dir, :remove_file
294
+
295
+ attr_accessor :output_buffer
296
+ private :output_buffer, :output_buffer=
297
+
298
+ private
299
+
300
+ def concat(string)
301
+ @output_buffer.concat(string)
302
+ end
303
+
304
+ def capture(*args)
305
+ with_output_buffer { yield(*args) }
306
+ end
307
+
308
+ def with_output_buffer(buf = "") #:nodoc:
309
+ self.output_buffer, old_buffer = buf, output_buffer
310
+ yield
311
+ output_buffer
312
+ ensure
313
+ self.output_buffer = old_buffer
314
+ end
315
+
316
+ # Foreman::Thor::Actions#capture depends on what kind of buffer is used in ERB.
317
+ # Thus CapturableERB fixes ERB to use String buffer.
318
+ class CapturableERB < ERB
319
+ def set_eoutvar(compiler, eoutvar = "_erbout")
320
+ compiler.put_cmd = "#{eoutvar}.concat"
321
+ compiler.insert_cmd = "#{eoutvar}.concat"
322
+ compiler.pre_cmd = ["#{eoutvar} = ''"]
323
+ compiler.post_cmd = [eoutvar]
324
+ end
325
+ end
326
+ end
327
+ end
@@ -0,0 +1,103 @@
1
+ require "foreman/vendor/thor/lib/thor/actions/empty_directory"
2
+
3
+ class Foreman::Thor
4
+ module Actions
5
+ # Injects the given content into a file. Different from gsub_file, this
6
+ # method is reversible.
7
+ #
8
+ # ==== Parameters
9
+ # destination<String>:: Relative path to the destination root
10
+ # data<String>:: Data to add to the file. Can be given as a block.
11
+ # config<Hash>:: give :verbose => false to not log the status and the flag
12
+ # for injection (:after or :before) or :force => true for
13
+ # insert two or more times the same content.
14
+ #
15
+ # ==== Examples
16
+ #
17
+ # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
18
+ #
19
+ # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
20
+ # gems = ask "Which gems would you like to add?"
21
+ # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
22
+ # end
23
+ #
24
+ def insert_into_file(destination, *args, &block)
25
+ data = block_given? ? block : args.shift
26
+ config = args.shift
27
+ action InjectIntoFile.new(self, destination, data, config)
28
+ end
29
+ alias_method :inject_into_file, :insert_into_file
30
+
31
+ class InjectIntoFile < EmptyDirectory #:nodoc:
32
+ attr_reader :replacement, :flag, :behavior
33
+
34
+ def initialize(base, destination, data, config)
35
+ super(base, destination, {:verbose => true}.merge(config))
36
+
37
+ @behavior, @flag = if @config.key?(:after)
38
+ [:after, @config.delete(:after)]
39
+ else
40
+ [:before, @config.delete(:before)]
41
+ end
42
+
43
+ @replacement = data.is_a?(Proc) ? data.call : data
44
+ @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp)
45
+ end
46
+
47
+ def invoke!
48
+ say_status :invoke
49
+
50
+ content = if @behavior == :after
51
+ '\0' + replacement
52
+ else
53
+ replacement + '\0'
54
+ end
55
+
56
+ replace!(/#{flag}/, content, config[:force])
57
+ end
58
+
59
+ def revoke!
60
+ say_status :revoke
61
+
62
+ regexp = if @behavior == :after
63
+ content = '\1\2'
64
+ /(#{flag})(.*)(#{Regexp.escape(replacement)})/m
65
+ else
66
+ content = '\2\3'
67
+ /(#{Regexp.escape(replacement)})(.*)(#{flag})/m
68
+ end
69
+
70
+ replace!(regexp, content, true)
71
+ end
72
+
73
+ protected
74
+
75
+ def say_status(behavior)
76
+ status = if behavior == :invoke
77
+ if flag == /\A/
78
+ :prepend
79
+ elsif flag == /\z/
80
+ :append
81
+ else
82
+ :insert
83
+ end
84
+ else
85
+ :subtract
86
+ end
87
+
88
+ super(status, config[:verbose])
89
+ end
90
+
91
+ # Adds the content to the file.
92
+ #
93
+ def replace!(regexp, string, force)
94
+ return if base.options[:pretend]
95
+ content = File.binread(destination)
96
+ if force || !content.include?(replacement)
97
+ content.gsub!(regexp, string)
98
+ File.open(destination, "wb") { |file| file.write(content) }
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end