chef 11.12.8-x86-mingw32 → 11.14.0.alpha.2-x86-mingw32

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 (193) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -2
  3. data/distro/common/html/_sources/index.txt +6 -0
  4. data/distro/common/html/_sources/knife_ssl_check.txt +41 -0
  5. data/distro/common/html/_sources/knife_ssl_fetch.txt +41 -0
  6. data/distro/common/html/_static/basic.css +2 -5
  7. data/distro/common/html/_static/doctools.js +5 -14
  8. data/distro/common/html/_static/jquery.js +2 -154
  9. data/distro/common/html/_static/pygments.css +2 -2
  10. data/distro/common/html/_static/searchtools.js +212 -150
  11. data/distro/common/html/_static/underscore.js +29 -21
  12. data/distro/common/html/_static/websupport.js +1 -1
  13. data/distro/common/html/ctl_chef_client.html +15 -18
  14. data/distro/common/html/ctl_chef_server.html +7 -7
  15. data/distro/common/html/ctl_chef_shell.html +6 -6
  16. data/distro/common/html/ctl_chef_solo.html +7 -8
  17. data/distro/common/html/index.html +34 -24
  18. data/distro/common/html/knife.html +23 -24
  19. data/distro/common/html/knife_bootstrap.html +13 -9
  20. data/distro/common/html/knife_client.html +10 -11
  21. data/distro/common/html/knife_common_options.html +6 -7
  22. data/distro/common/html/knife_configure.html +3 -4
  23. data/distro/common/html/knife_cookbook.html +18 -11
  24. data/distro/common/html/knife_cookbook_site.html +14 -14
  25. data/distro/common/html/knife_data_bag.html +24 -23
  26. data/distro/common/html/knife_delete.html +4 -5
  27. data/distro/common/html/knife_deps.html +4 -5
  28. data/distro/common/html/knife_diff.html +6 -7
  29. data/distro/common/html/knife_download.html +12 -13
  30. data/distro/common/html/knife_edit.html +4 -5
  31. data/distro/common/html/knife_environment.html +8 -9
  32. data/distro/common/html/knife_exec.html +9 -10
  33. data/distro/common/html/knife_index_rebuild.html +4 -5
  34. data/distro/common/html/knife_list.html +8 -9
  35. data/distro/common/html/knife_node.html +34 -33
  36. data/distro/common/html/knife_raw.html +2 -3
  37. data/distro/common/html/knife_recipe_list.html +3 -4
  38. data/distro/common/html/knife_role.html +30 -29
  39. data/distro/common/html/knife_search.html +7 -7
  40. data/distro/common/html/knife_show.html +4 -5
  41. data/distro/common/html/knife_ssh.html +2 -3
  42. data/distro/common/html/knife_ssl_check.html +148 -0
  43. data/distro/common/html/knife_ssl_fetch.html +152 -0
  44. data/distro/common/html/knife_status.html +4 -5
  45. data/distro/common/html/knife_tag.html +2 -3
  46. data/distro/common/html/knife_upload.html +5 -6
  47. data/distro/common/html/knife_user.html +9 -10
  48. data/distro/common/html/knife_using.html +12 -12
  49. data/distro/common/html/knife_xargs.html +11 -12
  50. data/distro/common/html/search.html +1 -2
  51. data/distro/common/html/searchindex.js +1 -1
  52. data/distro/common/man/man1/chef-shell.1 +19 -11
  53. data/distro/common/man/man1/knife-bootstrap.1 +35 -19
  54. data/distro/common/man/man1/knife-client.1 +111 -28
  55. data/distro/common/man/man1/knife-configure.1 +30 -14
  56. data/distro/common/man/man1/knife-cookbook-site.1 +105 -22
  57. data/distro/common/man/man1/knife-cookbook.1 +164 -23
  58. data/distro/common/man/man1/knife-data-bag.1 +157 -33
  59. data/distro/common/man/man1/knife-delete.1 +21 -17
  60. data/distro/common/man/man1/knife-deps.1 +60 -16
  61. data/distro/common/man/man1/knife-diff.1 +37 -17
  62. data/distro/common/man/man1/knife-download.1 +68 -24
  63. data/distro/common/man/man1/knife-edit.1 +19 -15
  64. data/distro/common/man/man1/knife-environment.1 +105 -17
  65. data/distro/common/man/man1/knife-exec.1 +78 -18
  66. data/distro/common/man/man1/knife-index-rebuild.1 +16 -8
  67. data/distro/common/man/man1/knife-list.1 +39 -23
  68. data/distro/common/man/man1/knife-node.1 +170 -22
  69. data/distro/common/man/man1/knife-raw.1 +33 -13
  70. data/distro/common/man/man1/knife-recipe-list.1 +17 -5
  71. data/distro/common/man/man1/knife-role.1 +86 -18
  72. data/distro/common/man/man1/knife-search.1 +80 -16
  73. data/distro/common/man/man1/knife-show.1 +30 -14
  74. data/distro/common/man/man1/knife-ssh.1 +54 -14
  75. data/distro/common/man/man1/knife-ssl-check.1 +207 -0
  76. data/distro/common/man/man1/knife-ssl-fetch.1 +207 -0
  77. data/distro/common/man/man1/knife-status.1 +48 -12
  78. data/distro/common/man/man1/knife-tag.1 +30 -10
  79. data/distro/common/man/man1/knife-upload.1 +72 -20
  80. data/distro/common/man/man1/knife-user.1 +79 -23
  81. data/distro/common/man/man1/knife-xargs.1 +61 -53
  82. data/distro/common/man/man8/chef-client.8 +87 -29
  83. data/distro/common/man/man8/chef-solo.8 +36 -15
  84. data/lib/chef/application.rb +19 -14
  85. data/lib/chef/application/client.rb +5 -0
  86. data/lib/chef/application/solo.rb +5 -0
  87. data/lib/chef/application/windows_service_manager.rb +3 -0
  88. data/lib/chef/chef_fs/chef_fs_data_store.rb +72 -24
  89. data/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb +20 -4
  90. data/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb +20 -1
  91. data/lib/chef/chef_fs/file_system/file_system_entry.rb +10 -2
  92. data/lib/chef/client.rb +2 -3
  93. data/lib/chef/config.rb +34 -8
  94. data/lib/chef/cookbook/cookbook_version_loader.rb +45 -4
  95. data/lib/chef/cookbook_version.rb +38 -30
  96. data/lib/chef/dsl/recipe.rb +4 -1
  97. data/lib/chef/event_dispatch/base.rb +14 -0
  98. data/lib/chef/event_dispatch/events_output_stream.rb +29 -0
  99. data/lib/chef/exceptions.rb +8 -0
  100. data/lib/chef/formatters/base.rb +16 -45
  101. data/lib/chef/formatters/doc.rb +51 -26
  102. data/lib/chef/formatters/indentable_output_stream.rb +165 -0
  103. data/lib/chef/knife/node_environment_set.rb +54 -0
  104. data/lib/chef/knife/user_create.rb +1 -1
  105. data/lib/chef/monkey_patches/pathname.rb +32 -0
  106. data/lib/chef/node.rb +1 -1
  107. data/lib/chef/platform/provider_mapping.rb +345 -338
  108. data/lib/chef/policy_builder/expand_node_object.rb +1 -1
  109. data/lib/chef/policy_builder/policyfile.rb +1 -1
  110. data/lib/chef/provider.rb +1 -0
  111. data/lib/chef/provider/git.rb +1 -1
  112. data/lib/chef/provider/link.rb +2 -2
  113. data/lib/chef/provider/remote_file/content.rb +1 -1
  114. data/lib/chef/provider/remote_file/local_file.rb +8 -2
  115. data/lib/chef/provider/service/arch.rb +0 -1
  116. data/lib/chef/provider/service/debian.rb +0 -2
  117. data/lib/chef/provider/service/freebsd.rb +2 -1
  118. data/lib/chef/provider/service/gentoo.rb +1 -1
  119. data/lib/chef/provider/service/init.rb +0 -1
  120. data/lib/chef/provider/service/insserv.rb +0 -2
  121. data/lib/chef/provider/service/invokercd.rb +0 -2
  122. data/lib/chef/provider/service/macosx.rb +2 -1
  123. data/lib/chef/provider/service/redhat.rb +0 -1
  124. data/lib/chef/provider/service/simple.rb +1 -0
  125. data/lib/chef/provider/service/solaris.rb +1 -0
  126. data/lib/chef/provider/service/systemd.rb +1 -1
  127. data/lib/chef/provider/service/upstart.rb +1 -1
  128. data/lib/chef/provider/user.rb +9 -9
  129. data/lib/chef/provider/user/solaris.rb +2 -0
  130. data/lib/chef/resource.rb +1 -0
  131. data/lib/chef/resource/remote_file.rb +32 -6
  132. data/lib/chef/run_context.rb +22 -0
  133. data/lib/chef/run_lock.rb +43 -4
  134. data/lib/chef/version.rb +2 -2
  135. data/spec/functional/http/simple_spec.rb +84 -0
  136. data/spec/functional/resource/remote_file_spec.rb +107 -43
  137. data/spec/functional/rest_spec.rb +94 -0
  138. data/spec/functional/run_lock_spec.rb +1 -1
  139. data/spec/functional/win32/service_manager_spec.rb +6 -0
  140. data/spec/integration/knife/chef_fs_data_store_spec.rb +2 -0
  141. data/spec/integration/recipes/lwrp_inline_resources_spec.rb +76 -0
  142. data/spec/spec_helper.rb +2 -0
  143. data/spec/support/mock/platform.rb +7 -0
  144. data/spec/support/pedant/pedant_config.rb +121 -0
  145. data/spec/support/pedant/run_pedant.rb +63 -0
  146. data/spec/support/pedant/stickywicket.pem +27 -0
  147. data/spec/support/shared/functional/http.rb +242 -0
  148. data/spec/support/shared/unit/api_error_inspector.rb +2 -2
  149. data/spec/unit/api_client_spec.rb +2 -2
  150. data/spec/unit/application/client_spec.rb +6 -1
  151. data/spec/unit/application/knife_spec.rb +4 -0
  152. data/spec/unit/application/solo_spec.rb +2 -0
  153. data/spec/unit/application_spec.rb +7 -0
  154. data/spec/unit/client_spec.rb +16 -0
  155. data/spec/unit/config_spec.rb +3 -20
  156. data/spec/unit/cookbook_version_spec.rb +224 -122
  157. data/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb +2 -2
  158. data/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb +2 -2
  159. data/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb +2 -2
  160. data/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb +2 -2
  161. data/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb +2 -2
  162. data/spec/unit/handler_spec.rb +0 -1
  163. data/spec/unit/knife/client_bulk_delete_spec.rb +3 -0
  164. data/spec/unit/knife/cookbook_bulk_delete_spec.rb +2 -0
  165. data/spec/unit/knife/cookbook_metadata_spec.rb +2 -2
  166. data/spec/unit/knife/cookbook_site_install_spec.rb +3 -1
  167. data/spec/unit/knife/cookbook_upload_spec.rb +10 -10
  168. data/spec/unit/knife/node_environment_set_spec.rb +80 -0
  169. data/spec/unit/knife/user_create_spec.rb +6 -4
  170. data/spec/unit/knife/user_edit_spec.rb +5 -0
  171. data/spec/unit/knife_spec.rb +3 -0
  172. data/spec/unit/mixin/securable_spec.rb +18 -20
  173. data/spec/unit/node/attribute_spec.rb +15 -2
  174. data/spec/unit/node/immutable_collections_spec.rb +4 -4
  175. data/spec/unit/provider/cron_spec.rb +14 -14
  176. data/spec/unit/provider/git_spec.rb +4 -4
  177. data/spec/unit/provider/group_spec.rb +1 -1
  178. data/spec/unit/provider/ohai_spec.rb +2 -2
  179. data/spec/unit/provider/remote_file/content_spec.rb +58 -35
  180. data/spec/unit/provider/remote_file/local_file_spec.rb +23 -0
  181. data/spec/unit/provider/service/solaris_smf_service_spec.rb +13 -13
  182. data/spec/unit/resource/mount_spec.rb +0 -1
  183. data/spec/unit/resource/remote_file_spec.rb +29 -0
  184. data/spec/unit/resource_spec.rb +1 -1
  185. data/spec/unit/run_context_spec.rb +7 -0
  186. data/spec/unit/run_lock_spec.rb +98 -0
  187. data/spec/unit/version_constraint_spec.rb +1 -1
  188. metadata +166 -153
  189. data/distro/common/html/_static/chef.css +0 -507
  190. data/distro/common/html/_static/chef_logo.png +0 -0
  191. data/lib/chef/checksum/storage.rb +0 -18
  192. data/lib/chef/checksum/storage/filesystem.rb +0 -56
  193. data/spec/unit/checksum/storage/filesystem_spec.rb +0 -70
@@ -277,6 +277,20 @@ class Chef
277
277
  def resource_updated(resource, action)
278
278
  end
279
279
 
280
+ # A stream has opened.
281
+ def stream_opened(stream, options = {})
282
+ end
283
+
284
+ # A stream has closed.
285
+ def stream_closed(stream, options = {})
286
+ end
287
+
288
+ # A chunk of data from a stream. The stream is managed by "stream," which
289
+ # can be any tag whatsoever. Data in different "streams" may not be placed
290
+ # on the same line or even sent to the same console.
291
+ def stream_output(stream, output, options = {})
292
+ end
293
+
280
294
  # Called before handlers run
281
295
  def handlers_start(handler_count)
282
296
  end
@@ -0,0 +1,29 @@
1
+ class Chef
2
+ module EventDispatch
3
+ class EventsOutputStream
4
+ # This is a fake stream that connects to events.
5
+ #
6
+ # == Arguments
7
+ # events: the EventDispatch object to send data to (run_context.events)
8
+ # options is a hash with these possible options:
9
+ # - name: a string that identifies the stream to the user. Preferably short.
10
+
11
+ def initialize(events, options = {})
12
+ @events = events
13
+ @options = options
14
+ events.stream_opened(self, options)
15
+ end
16
+
17
+ attr_reader :options
18
+ attr_reader :events
19
+
20
+ def print(str)
21
+ events.stream_output(self, str, options)
22
+ end
23
+
24
+ def close
25
+ events.stream_closed(self, options)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -321,5 +321,13 @@ class Chef
321
321
  super "This functionality is not supported on platform #{platform}."
322
322
  end
323
323
  end
324
+
325
+ # Raised when Chef::Config[:run_lock_timeout] is set and some other client run fails
326
+ # to release the run lock becure Chef::Config[:run_lock_timeout] seconds pass.
327
+ class RunLockTimeout < RuntimeError
328
+ def initialize(duration, blocking_pid)
329
+ super "Unable to acquire lock. Waited #{duration} seconds for #{blocking_pid} to release."
330
+ end
331
+ end
324
332
  end
325
333
  end
@@ -21,6 +21,7 @@ require 'chef/event_dispatch/base'
21
21
  require 'chef/formatters/error_inspectors'
22
22
  require 'chef/formatters/error_descriptor'
23
23
  require 'chef/formatters/error_mapper'
24
+ require 'chef/formatters/indentable_output_stream'
24
25
 
25
26
  class Chef
26
27
 
@@ -56,47 +57,6 @@ class Chef
56
57
  formatter_class.new(out, err)
57
58
  end
58
59
 
59
- # == Outputter
60
- # Handles basic printing tasks like colorizing.
61
- # --
62
- # TODO: Duplicates functionality from knife, upfactor.
63
- class Outputter
64
-
65
- attr_reader :out
66
- attr_reader :err
67
-
68
- def initialize(out, err)
69
- @out, @err = out, err
70
- end
71
-
72
- def highline
73
- @highline ||= begin
74
- require 'highline'
75
- HighLine.new
76
- end
77
- end
78
-
79
- def color(string, *colors)
80
- if Chef::Config[:color]
81
- @out.print highline.color(string, *colors)
82
- else
83
- @out.print string
84
- end
85
- end
86
-
87
- alias :print :color
88
-
89
- def puts(string, *colors)
90
- if Chef::Config[:color]
91
- @out.puts highline.color(string, *colors)
92
- else
93
- @out.puts string
94
- end
95
- end
96
-
97
- end
98
-
99
-
100
60
  # == Formatters::Base
101
61
  # Base class that all formatters should inherit from.
102
62
  class Base < EventDispatch::Base
@@ -112,7 +72,7 @@ class Chef
112
72
  attr_reader :output
113
73
 
114
74
  def initialize(out, err)
115
- @output = Outputter.new(out, err)
75
+ @output = IndentableOutputStream.new(out, err)
116
76
  end
117
77
 
118
78
  def puts(*args)
@@ -123,8 +83,20 @@ class Chef
123
83
  @output.print(*args)
124
84
  end
125
85
 
86
+ def puts_line(*args)
87
+ @output.puts_line(*args)
88
+ end
89
+
90
+ def start_line(*args)
91
+ @output.start_line(*args)
92
+ end
93
+
94
+ def indent_by(amount)
95
+ @output.indent += amount
96
+ end
97
+
126
98
  # Input: a Formatters::ErrorDescription object.
127
- # Outputs error to SDOUT.
99
+ # Outputs error to STDOUT.
128
100
  def display_error(description)
129
101
  puts("")
130
102
  description.display(output)
@@ -237,7 +209,7 @@ class Chef
237
209
 
238
210
 
239
211
  # == NullFormatter
240
- # Formatter that doesn't actually produce any ouput. You can use this to
212
+ # Formatter that doesn't actually produce any output. You can use this to
241
213
  # disable the use of output formatters.
242
214
  class NullFormatter < Base
243
215
 
@@ -247,4 +219,3 @@ class Chef
247
219
 
248
220
  end
249
221
  end
250
-
@@ -10,7 +10,6 @@ class Chef
10
10
 
11
11
  attr_reader :start_time, :end_time
12
12
  cli_name(:doc)
13
-
14
13
 
15
14
  def initialize(out, err)
16
15
  super
@@ -26,7 +25,7 @@ class Chef
26
25
  end
27
26
 
28
27
  def run_start(version)
29
- puts "Starting Chef Client, version #{version}"
28
+ puts_line "Starting Chef Client, version #{version}"
30
29
  end
31
30
 
32
31
  def total_resources
@@ -36,18 +35,18 @@ class Chef
36
35
  def run_completed(node)
37
36
  @end_time = Time.now
38
37
  if Chef::Config[:why_run]
39
- puts "Chef Client finished, #{@updated_resources}/#{total_resources} resources would have been updated"
38
+ puts_line "Chef Client finished, #{@updated_resources}/#{total_resources} resources would have been updated"
40
39
  else
41
- puts "Chef Client finished, #{@updated_resources}/#{total_resources} resources updated in #{elapsed_time} seconds"
40
+ puts_line "Chef Client finished, #{@updated_resources}/#{total_resources} resources updated in #{elapsed_time} seconds"
42
41
  end
43
42
  end
44
43
 
45
44
  def run_failed(exception)
46
45
  @end_time = Time.now
47
46
  if Chef::Config[:why_run]
48
- puts "Chef Client failed. #{@updated_resources} resources would have been updated"
47
+ puts_line "Chef Client failed. #{@updated_resources} resources would have been updated"
49
48
  else
50
- puts "Chef Client failed. #{@updated_resources} resources updated in #{elapsed_time} seconds"
49
+ puts_line "Chef Client failed. #{@updated_resources} resources updated in #{elapsed_time} seconds"
51
50
  end
52
51
  end
53
52
 
@@ -61,7 +60,7 @@ class Chef
61
60
 
62
61
  # About to attempt to register as +node_name+
63
62
  def registration_start(node_name, config)
64
- puts "Creating a new client identity for #{node_name} using the validator key."
63
+ puts_line "Creating a new client identity for #{node_name} using the validator key."
65
64
  end
66
65
 
67
66
  def registration_completed
@@ -82,7 +81,7 @@ class Chef
82
81
 
83
82
  # Called before the cookbook collection is fetched from the server.
84
83
  def cookbook_resolution_start(expanded_run_list)
85
- puts "resolving cookbooks for run list: #{expanded_run_list.inspect}"
84
+ puts_line "resolving cookbooks for run list: #{expanded_run_list.inspect}"
86
85
  end
87
86
 
88
87
  # Called when there is an error getting the cookbook collection from the
@@ -111,12 +110,13 @@ class Chef
111
110
 
112
111
  # Called before cookbook sync starts
113
112
  def cookbook_sync_start(cookbook_count)
114
- puts "Synchronizing Cookbooks:"
113
+ puts_line "Synchronizing Cookbooks:"
114
+ indent
115
115
  end
116
116
 
117
117
  # Called when cookbook +cookbook_name+ has been sync'd
118
118
  def synchronized_cookbook(cookbook_name)
119
- puts " - #{cookbook_name}"
119
+ puts_line "- #{cookbook_name}"
120
120
  end
121
121
 
122
122
  # Called when an individual file in a cookbook has been updated
@@ -125,11 +125,12 @@ class Chef
125
125
 
126
126
  # Called after all cookbooks have been sync'd.
127
127
  def cookbook_sync_complete
128
+ unindent
128
129
  end
129
130
 
130
131
  # Called when cookbook loading starts.
131
132
  def library_load_start(file_count)
132
- puts "Compiling Cookbooks..."
133
+ puts_line "Compiling Cookbooks..."
133
134
  end
134
135
 
135
136
  # Called after a file in a cookbook is loaded.
@@ -142,11 +143,12 @@ class Chef
142
143
 
143
144
  # Called before convergence starts
144
145
  def converge_start(run_context)
145
- puts "Converging #{run_context.resource_collection.all_resources.size} resources"
146
+ puts_line "Converging #{run_context.resource_collection.all_resources.size} resources"
146
147
  end
147
148
 
148
149
  # Called when the converge phase is finished.
149
150
  def converge_complete
151
+ unindent if @current_recipe
150
152
  end
151
153
 
152
154
  # Called before action is executed on a resource.
@@ -157,12 +159,15 @@ class Chef
157
159
  resource_recipe = "<Dynamically Defined Resource>"
158
160
  end
159
161
 
160
- if resource_recipe != @current_recipe
161
- puts "Recipe: #{resource_recipe}"
162
+ if resource_recipe != @current_recipe && !resource.enclosing_provider
163
+ unindent if @current_recipe
164
+ puts_line "Recipe: #{resource_recipe}"
162
165
  @current_recipe = resource_recipe
166
+ indent
163
167
  end
164
168
  # TODO: info about notifies
165
- print " * #{resource} action #{action}"
169
+ start_line "* #{resource} action #{action}", :stream => resource
170
+ indent
166
171
  end
167
172
 
168
173
  # Called when a resource fails, but will retry.
@@ -172,12 +177,14 @@ class Chef
172
177
  # Called when a resource fails and will not be retried.
173
178
  def resource_failed(resource, action, exception)
174
179
  super
180
+ unindent
175
181
  end
176
182
 
177
183
  # Called when a resource action has been skipped b/c of a conditional
178
184
  def resource_skipped(resource, action, conditional)
179
185
  # TODO: more info about conditional
180
- puts " (skipped due to #{conditional.short_description})"
186
+ puts " (skipped due to #{conditional.short_description})", :stream => resource
187
+ unindent
181
188
  end
182
189
 
183
190
  # Called after #load_current_resource has run.
@@ -187,11 +194,13 @@ class Chef
187
194
  # Called when a resource has no converge actions, e.g., it was already correct.
188
195
  def resource_up_to_date(resource, action)
189
196
  @up_to_date_resources+= 1
190
- puts " (up to date)"
197
+ puts " (up to date)", :stream => resource
198
+ unindent
191
199
  end
192
200
 
193
201
  def resource_bypassed(resource, action, provider)
194
- puts " (Skipped: whyrun not supported by provider #{provider.class.name})"
202
+ puts " (Skipped: whyrun not supported by provider #{provider.class.name})", :stream => resource
203
+ unindent
195
204
  end
196
205
 
197
206
  def output_record(line)
@@ -207,12 +216,12 @@ class Chef
207
216
  next if line.nil?
208
217
  output_record line
209
218
  if line.kind_of? String
210
- @output.color "\n - #{prefix}#{line}", :green
219
+ start_line "- #{prefix}#{line}", :green
211
220
  elsif line.kind_of? Array
212
221
  # Expanded output - delta
213
222
  # @todo should we have a resource_update_delta callback?
214
223
  line.each do |detail|
215
- @output.color "\n #{detail}", :white
224
+ start_line detail, :white
216
225
  end
217
226
  end
218
227
  end
@@ -221,28 +230,36 @@ class Chef
221
230
  # Called after a resource has been completely converged.
222
231
  def resource_updated(resource, action)
223
232
  @updated_resources += 1
233
+ unindent
224
234
  puts "\n"
225
235
  end
226
236
 
227
237
  # Called when resource current state load is skipped due to the provider
228
238
  # not supporting whyrun mode.
229
239
  def resource_current_state_load_bypassed(resource, action, current_resource)
230
- @output.color("\n * Whyrun not supported for #{resource}, bypassing load.", :yellow)
240
+ puts_line("* Whyrun not supported for #{resource}, bypassing load.", :yellow)
241
+ end
242
+
243
+ def stream_output(stream, output, options = {})
244
+ print(output, { :stream => stream }.merge(options))
231
245
  end
232
246
 
233
247
  # Called before handlers run
234
248
  def handlers_start(handler_count)
235
- puts "\nRunning handlers:"
249
+ puts ''
250
+ puts "Running handlers:"
251
+ indent
236
252
  end
237
253
 
238
254
  # Called after an individual handler has run
239
255
  def handler_executed(handler)
240
- puts " - #{handler.class.name}"
256
+ puts_line "- #{handler.class.name}"
241
257
  end
242
258
 
243
259
  # Called after all handlers have executed
244
260
  def handlers_completed
245
- puts "Running handlers complete\n"
261
+ unindent
262
+ puts_line "Running handlers complete\n"
246
263
  end
247
264
 
248
265
  # Called when a provider makes an assumption after a failed assertion
@@ -250,7 +267,7 @@ class Chef
250
267
  def whyrun_assumption(action, resource, message)
251
268
  return unless message
252
269
  [ message ].flatten.each do |line|
253
- @output.color("\n * #{line}", :yellow)
270
+ start_line("* #{line}", :yellow)
254
271
  end
255
272
  end
256
273
 
@@ -259,9 +276,17 @@ class Chef
259
276
  return unless message
260
277
  color = Chef::Config[:why_run] ? :yellow : :red
261
278
  [ message ].flatten.each do |line|
262
- @output.color("\n * #{line}", color)
279
+ start_line("* #{line}", color)
263
280
  end
264
281
  end
282
+
283
+ def indent
284
+ indent_by(2)
285
+ end
286
+
287
+ def unindent
288
+ indent_by(-2)
289
+ end
265
290
  end
266
291
  end
267
292
  end
@@ -0,0 +1,165 @@
1
+ class Chef
2
+ module Formatters
3
+ # Handles basic indentation and colorization tasks
4
+ class IndentableOutputStream
5
+
6
+ attr_reader :out
7
+ attr_reader :err
8
+ attr_accessor :indent
9
+ attr_reader :line_started
10
+ attr_accessor :current_stream
11
+ attr_reader :semaphore
12
+
13
+ def initialize(out, err)
14
+ @out, @err = out, err
15
+ @indent = 0
16
+ @line_started = false
17
+ @semaphore = Mutex.new
18
+ end
19
+
20
+ def highline
21
+ @highline ||= begin
22
+ require 'highline'
23
+ HighLine.new
24
+ end
25
+ end
26
+
27
+ # Print text. This will start a new line and indent if necessary
28
+ # but will not terminate the line (future print and puts statements
29
+ # will start off where this print left off).
30
+ def color(string, *args)
31
+ print(string, from_args(args))
32
+ end
33
+
34
+ # Print the start of a new line. This will terminate any existing lines and
35
+ # cause indentation but will not move to the next line yet (future 'print'
36
+ # and 'puts' statements will stay on this line).
37
+ def start_line(string, *args)
38
+ print(string, from_args(args, :start_line => true))
39
+ end
40
+
41
+ # Print a line. This will continue from the last start_line or print,
42
+ # or start a new line and indent if necessary.
43
+ def puts(string, *args)
44
+ print(string, from_args(args, :end_line => true))
45
+ end
46
+
47
+ # Print an entire line from start to end. This will terminate any existing
48
+ # lines and cause indentation.
49
+ def puts_line(string, *args)
50
+ print(string, from_args(args, :start_line => true, :end_line => true))
51
+ end
52
+
53
+ # Print a string.
54
+ #
55
+ # == Arguments
56
+ # string: string to print.
57
+ # options: a hash with these possible options:
58
+ # - :stream => OBJ: unique identifier for a stream. If two prints have
59
+ # different streams, they will print on separate lines.
60
+ # Otherwise, they will stay together.
61
+ # - :start_line => BOOLEAN: if true, print will begin on a blank (indented) line.
62
+ # - :end_line => BOOLEAN: if true, current line will be ended.
63
+ # - :name => STRING: a name to prefix in front of a stream. It will be printed
64
+ # once (with the first line of the stream) and subsequent lines
65
+ # will be indented to match.
66
+ #
67
+ # == Alternative
68
+ #
69
+ # You may also call print('string', :red) (a list of colors a la Highline.color)
70
+ def print(string, *args)
71
+ options = from_args(args)
72
+
73
+ # Make sure each line stays a unit even with threads sending output
74
+ semaphore.synchronize do
75
+ if should_start_line?(options)
76
+ move_to_next_line
77
+ end
78
+
79
+ print_string(string, options)
80
+
81
+ if should_end_line?(options)
82
+ move_to_next_line
83
+ end
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def should_start_line?(options)
90
+ options[:start_line] || @current_stream != options[:stream]
91
+ end
92
+
93
+ def should_end_line?(options)
94
+ options[:end_line] && @line_started
95
+ end
96
+
97
+ def from_args(colors, merge_options = {})
98
+ if colors.size == 1 && colors[0].kind_of?(Hash)
99
+ merge_options.merge(colors[0])
100
+ else
101
+ merge_options.merge({ :colors => colors })
102
+ end
103
+ end
104
+
105
+ def print_string(string, options)
106
+ if string.empty?
107
+ if options[:end_line]
108
+ print_line('', options)
109
+ end
110
+ else
111
+ string.lines.each do |line|
112
+ print_line(line, options)
113
+ end
114
+ end
115
+ end
116
+
117
+ def print_line(line, options)
118
+ indent_line(options)
119
+
120
+ # Note that the next line will need to be started
121
+ if line[-1..-1] == "\n"
122
+ @line_started = false
123
+ end
124
+
125
+ if Chef::Config[:color] && options[:colors]
126
+ @out.print highline.color(line, *options[:colors])
127
+ else
128
+ @out.print line
129
+ end
130
+ end
131
+
132
+ def move_to_next_line
133
+ if @line_started
134
+ @out.puts ''
135
+ @line_started = false
136
+ end
137
+ end
138
+
139
+ def indent_line(options)
140
+ if !@line_started
141
+
142
+ # Print indents. If there is a stream name, either print it (if we're
143
+ # switching streams) or print enough blanks to match
144
+ # the indents.
145
+ if options[:name]
146
+ if @current_stream != options[:stream]
147
+ @out.print "#{(' ' * indent)}[#{options[:name]}] "
148
+ else
149
+ @out.print ' ' * (indent + 3 + options[:name].size)
150
+ end
151
+ else
152
+ # Otherwise, just print indents.
153
+ @out.print ' ' * indent
154
+ end
155
+
156
+ if @current_stream != options[:stream]
157
+ @current_stream = options[:stream]
158
+ end
159
+
160
+ @line_started = true
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end