diff options
-rw-r--r-- | lib/chef/event_dispatch/base.rb | 14 | ||||
-rw-r--r-- | lib/chef/event_dispatch/events_output_stream.rb | 29 | ||||
-rw-r--r-- | lib/chef/formatters/base.rb | 102 | ||||
-rw-r--r-- | lib/chef/formatters/doc.rb | 4 | ||||
-rw-r--r-- | lib/chef/run_context.rb | 22 |
5 files changed, 134 insertions, 37 deletions
diff --git a/lib/chef/event_dispatch/base.rb b/lib/chef/event_dispatch/base.rb index 82beefeec9..bfd4503097 100644 --- a/lib/chef/event_dispatch/base.rb +++ b/lib/chef/event_dispatch/base.rb @@ -277,6 +277,20 @@ class Chef def resource_updated(resource, action) end + # A stream has opened. + def stream_opened(stream, options = {}) + end + + # A stream has closed. + def stream_closed(stream, options = {}) + end + + # A chunk of data from a stream. The stream is managed by "stream," which + # can be any tag whatsoever. Data in different "streams" may not be placed + # on the same line or even sent to the same console. + def stream_output(stream, output, options = {}) + end + # Called before handlers run def handlers_start(handler_count) end diff --git a/lib/chef/event_dispatch/events_output_stream.rb b/lib/chef/event_dispatch/events_output_stream.rb new file mode 100644 index 0000000000..8de9b0fed1 --- /dev/null +++ b/lib/chef/event_dispatch/events_output_stream.rb @@ -0,0 +1,29 @@ +class Chef + module EventDispatch + class EventsOutputStream + # This is a fake stream that connects to events. + # + # == Arguments + # events: the EventDispatch object to send data to (run_context.events) + # options is a hash with these possible options: + # - name: a string that identifies the stream to the user. Preferably short. + + def initialize(events, options = {}) + @events = events + @options = options + events.stream_opened(self, options) + end + + attr_reader :options + attr_reader :events + + def print(str) + events.stream_output(self, str, options) + end + + def close + events.stream_closed(self, options) + end + end + end +end diff --git a/lib/chef/formatters/base.rb b/lib/chef/formatters/base.rb index 7bcb629fc7..612aab3085 100644 --- a/lib/chef/formatters/base.rb +++ b/lib/chef/formatters/base.rb @@ -66,6 +66,7 @@ class Chef attr_reader :err attr_accessor :indent attr_reader :line_started + attr_accessor :sticky_tag def initialize(out, err) @out, @err = out, err @@ -84,60 +85,84 @@ class Chef # but will not terminate the line (future print and puts statements # will start off where this print left off). def color(string, *colors) - if !@line_started - @out.print ' ' * indent - @line_started = true - end - if string[-1..-1] == "\n" - @line_started = false - end - - if Chef::Config[:color] - @out.print highline.color(string, *colors) - else - @out.print string - end + print(string, :colors => colors) end - alias :print :color - # Print a line. This will continue from the last start_line or print, # or start a new line and indent if necessary. def puts(string, *colors) - if !@line_started - @out.print ' ' * indent - end - - if Chef::Config[:color] - @out.puts highline.color(string, *colors) - else - @out.puts string - end - @line_started = false + print(string, :end_line => true, :colors => colors) end # Print an entire line from start to end. This will terminate any existing # lines and cause indentation. def puts_line(string, *colors) - if @line_started - @out.puts '' - @line_started = false - end - - puts(string, *colors) + print(string, :start_line => true, :end_line => true, :colors => colors) end # Print the start of a new line. This will terminate any existing lines and # cause indentation but will not move to the next line yet (future 'print' # and 'puts' statements will stay on this line). def start_line(string, *colors) - if @line_started - @out.puts '' - @line_started = false + print(string, :start_line => true, :colors => colors) + end + + # Print a line, with possible options. + def print(string, *colors) + if colors.size == 1 && colors[0].kind_of?(Hash) + options = colors[0] + else + options = { :colors => colors } + end + + # If we aren't printing to the same stream, or if start_line is true, + # move to the next line. + if options[:start_line] || @stream != options[:stream] + if @line_started + @out.puts '' + @line_started = false + end + @stream = options[:stream] + end + + # Split the output by line and indent each + printed_anything = false + string.lines.each do |line| + printed_anything = true + print_line_with_options(line, options) + end + + if options[:end_line] + # If we're supposed to end the line, and the string did not end with + # \n, then we end the line. + if @line_started + @out.puts '' + @line_started = false + elsif !printed_anything + @out.puts ' ' * indent + end end - print(string, *colors) end + private + + def print_line_with_options(line, options) + # Start the line with indent if it is not started + if !@line_started + @out.print ' ' * indent + @line_started = true + end + # Note that the next line will need to be started + if line[-1..-1] == "\n" + @line_started = false + end + + if Chef::Config[:color] && options[:colors] + @out.print highline.color(line, *options[:colors]) + else + @out.print line + end + end end @@ -175,12 +200,16 @@ class Chef @output.start_line(*args) end + def print_sticky(*args) + @output.print_sticky(*args) + end + def indent_by(amount) @output.indent += amount end # Input: a Formatters::ErrorDescription object. - # Outputs error to SDOUT. + # Outputs error to STDOUT. def display_error(description) puts("") description.display(output) @@ -303,4 +332,3 @@ class Chef end end - diff --git a/lib/chef/formatters/doc.rb b/lib/chef/formatters/doc.rb index 89ec59b813..c8b61cc433 100644 --- a/lib/chef/formatters/doc.rb +++ b/lib/chef/formatters/doc.rb @@ -240,6 +240,10 @@ class Chef puts_line("* Whyrun not supported for #{resource}, bypassing load.", :yellow) end + def stream_output(stream, output, options = {}) + print(output, { :stream => stream }.merge(options)) + end + # Called before handlers run def handlers_start(handler_count) puts '' diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb index a102ef4692..3dd53f0f8f 100644 --- a/lib/chef/run_context.rb +++ b/lib/chef/run_context.rb @@ -24,6 +24,7 @@ require 'chef/role' require 'chef/log' require 'chef/recipe' require 'chef/run_context/cookbook_compiler' +require 'chef/event_dispatch/events_output_stream' class Chef @@ -249,6 +250,27 @@ ERROR_MESSAGE @cookbook_compiler.unreachable_cookbook?(cookbook_name) end + # Open a stream object that can be printed into and will dispatch to events + # + # == Arguments + # options is a hash with these possible options: + # - name: a string that identifies the stream to the user. Preferably short. + # + # Pass a block and the stream will be yielded to it, and close on its own + # at the end of the block. + def open_stream(options = {}) + stream = EventDispatch::EventsOutputStream.new(events, options) + if block_given? + begin + yield stream + ensure + stream.close + end + else + stream + end + end + private def loaded_recipe(cookbook, recipe) |