summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/chef/event_dispatch/base.rb14
-rw-r--r--lib/chef/event_dispatch/events_output_stream.rb29
-rw-r--r--lib/chef/formatters/base.rb102
-rw-r--r--lib/chef/formatters/doc.rb4
-rw-r--r--lib/chef/run_context.rb22
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)