diff options
Diffstat (limited to 'lib/bundler/ui/shell.rb')
| -rw-r--r-- | lib/bundler/ui/shell.rb | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/lib/bundler/ui/shell.rb b/lib/bundler/ui/shell.rb new file mode 100644 index 0000000000..b836208da8 --- /dev/null +++ b/lib/bundler/ui/shell.rb @@ -0,0 +1,191 @@ +# frozen_string_literal: true + +require_relative "../vendored_thor" + +module Bundler + module UI + class Shell + LEVELS = %w[silent error warn confirm info debug].freeze + OUTPUT_STREAMS = [:stdout, :stderr].freeze + + attr_writer :shell + attr_reader :output_stream + + def initialize(options = {}) + Thor::Base.shell = options["no-color"] ? Thor::Shell::Basic : nil + @shell = Thor::Base.shell.new + @level = ENV["DEBUG"] ? "debug" : "info" + @warning_history = [] + @output_stream = :stdout + @thread_safe_logger_key = "logger_level_#{object_id}" + end + + def add_color(string, *color) + @shell.set_color(string, *color) + end + + def info(msg = nil, newline = nil) + return unless info? + + tell_me(msg || yield, nil, newline) + end + + def confirm(msg = nil, newline = nil) + return unless confirm? + + tell_me(msg || yield, :green, newline) + end + + def warn(msg = nil, newline = nil, color = :yellow) + return unless warn? + return if @warning_history.include? msg + @warning_history << msg + + tell_err(msg || yield, color, newline) + end + + def error(msg = nil, newline = nil, color = :red) + return unless error? + + tell_err(msg || yield, color, newline) + end + + def debug(msg = nil, newline = nil) + return unless debug? + + tell_me(msg || yield, nil, newline) + end + + def info? + level("info") + end + + def confirm? + level("confirm") + end + + def warn? + level("warn") + end + + def error? + level("error") + end + + def debug? + level("debug") + end + + def quiet? + level("quiet") + end + + def ask(msg) + @shell.ask(msg, :green) + end + + def yes?(msg) + @shell.yes?(msg, :green) + end + + def no?(msg) + @shell.no?(msg) + end + + def level=(level) + raise ArgumentError unless LEVELS.include?(level.to_s) + @level = level.to_s + end + + def level(name = nil) + current_level = Thread.current.thread_variable_get(@thread_safe_logger_key) || @level + return current_level unless name + + unless index = LEVELS.index(name) + raise "#{name.inspect} is not a valid level" + end + index <= LEVELS.index(current_level) + end + + def output_stream=(symbol) + raise ArgumentError unless OUTPUT_STREAMS.include?(symbol) + @output_stream = symbol + end + + def trace(e, newline = nil, force = false) + return unless debug? || force + msg = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n ")}" + tell_err(msg, nil, newline) + end + + def silence(&blk) + with_level("silent", &blk) + end + + def progress(&blk) + with_output_stream(:stderr, &blk) + end + + def unprinted_warnings + [] + end + + private + + # valimism + def tell_me(msg, color = nil, newline = nil) + return tell_err(msg, color, newline) if output_stream == :stderr + + msg = word_wrap(msg) if newline.is_a?(Hash) && newline[:wrap] + if newline.nil? + @shell.say(msg, color) + else + @shell.say(msg, color, newline) + end + end + + def tell_err(message, color = nil, newline = nil) + return if @shell.send(:stderr).closed? + + newline = !message.to_s.match?(/( |\t)\Z/) if newline.nil? + message = word_wrap(message) if newline.is_a?(Hash) && newline[:wrap] + + color = nil if color && !$stderr.tty? + + buffer = @shell.send(:prepare_message, message, *color) + buffer << "\n" if newline && !message.to_s.end_with?("\n") + + @shell.send(:stderr).print(buffer) + @shell.send(:stderr).flush + end + + def strip_leading_spaces(text) + spaces = text[/\A\s+/, 0] + spaces ? text.gsub(/#{spaces}/, "") : text + end + + def word_wrap(text, line_width = Thor::Terminal.terminal_width) + strip_leading_spaces(text).split("\n").collect do |line| + line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line + end * "\n" + end + + def with_level(desired_level) + old_level = level + Thread.current.thread_variable_set(@thread_safe_logger_key, desired_level) + + yield + ensure + Thread.current.thread_variable_set(@thread_safe_logger_key, old_level) + end + + def with_output_stream(symbol) + original = output_stream + self.output_stream = symbol + yield + ensure + @output_stream = original + end + end + end +end |
