diff --git a/CHANGELOG.md b/CHANGELOG.md index 630c5dea..79ab42ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ appear at the top. * Backend implementations now only need to implement `execute_command`, `upload!` and `download!` * Removed `Printer` from backend hierarchy for `Local` and `Netssh` backends (they now just extend `Abstract`) * Removed unused `Net::SSH:LogLevelShim` + * Removed dependency on the `colorize` gem. SSHKit now implements its own ANSI color logic, with no external dependencies. Note that SSHKit now only supports the `:bold` or plain modes. Other modes will be gracefully ignored. [#263](https://github.com/capistrano/sshkit/issues/263) ## 1.7.1 diff --git a/lib/sshkit/color.rb b/lib/sshkit/color.rb index f66c4969..91109874 100644 --- a/lib/sshkit/color.rb +++ b/lib/sshkit/color.rb @@ -1,16 +1,56 @@ -require 'colorize' - module SSHKit + # Very basic support for ANSI color, so that we don't have to rely on + # any external dependencies. This class handles colorizing strings, and + # automatically disabling color if the underlying output is not a tty. + # class Color + COLOR_CODES = { + :black => 30, + :red => 31, + :green => 32, + :yellow => 33, + :blue => 34, + :magenta => 35, + :cyan => 36, + :white => 37, + :light_black => 90, + :light_red => 91, + :light_green => 92, + :light_yellow => 93, + :light_blue => 94, + :light_magenta => 95, + :light_cyan => 96, + :light_white => 97 + }.freeze + def initialize(output, env=ENV) @output, @env = output, env end + # Converts the given obj to string and surrounds in the appropriate ANSI + # color escape sequence, based on the specified color and mode. The color + # must be a symbol (see COLOR_CODES for a complete list). + # + # If the underlying output does not support ANSI color (see `colorize?), + # the string will be not be colorized. Likewise if the specified color + # symbol is unrecognized, the string will not be colorized. + # + # Note that the only mode currently support is :bold. All other values + # will be silently ignored (i.e. treated the same as mode=nil). + # def colorize(obj, color, mode=nil) string = obj.to_s - colorize? ? string.colorize(color: color, mode: mode) : string + return string unless colorize? + return string unless COLOR_CODES.key?(color) + + result = mode == :bold ? "\e[1;" : "\e[0;" + result << COLOR_CODES.fetch(color).to_s + result << ";49m#{string}\e[0m" end + # Returns `true` if the underlying output is a tty, or if the SSHKIT_COLOR + # environment variable is set. + # def colorize? @env['SSHKIT_COLOR'] || (@output.respond_to?(:tty?) && @output.tty?) end diff --git a/sshkit.gemspec b/sshkit.gemspec index 419ae837..5d5a0a09 100644 --- a/sshkit.gemspec +++ b/sshkit.gemspec @@ -19,7 +19,6 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency('net-ssh', '>= 2.8.0') gem.add_runtime_dependency('net-scp', '>= 1.1.2') - gem.add_runtime_dependency('colorize', '>= 0.7.0') gem.add_development_dependency('minitest', ['>= 2.11.3', '< 2.12.0']) gem.add_development_dependency('rake') diff --git a/test/unit/test_color.rb b/test/unit/test_color.rb index 6f2d0cb6..7449551b 100644 --- a/test/unit/test_color.rb +++ b/test/unit/test_color.rb @@ -26,5 +26,55 @@ def test_does_not_colorize_when_tty_method_not_defined_and_SSHKIT_COLOR_not_pres color = SSHKit::Color.new(stub(), {}) assert_equal 'hi', color.colorize('hi', :red) end + + def test_colorize_colors + color = SSHKit::Color.new(stub(tty?: true), {}) + assert_equal "\e[0;30;49mhi\e[0m", color.colorize('hi', :black) + assert_equal "\e[0;31;49mhi\e[0m", color.colorize('hi', :red) + assert_equal "\e[0;32;49mhi\e[0m", color.colorize('hi', :green) + assert_equal "\e[0;33;49mhi\e[0m", color.colorize('hi', :yellow) + assert_equal "\e[0;34;49mhi\e[0m", color.colorize('hi', :blue) + assert_equal "\e[0;35;49mhi\e[0m", color.colorize('hi', :magenta) + assert_equal "\e[0;36;49mhi\e[0m", color.colorize('hi', :cyan) + assert_equal "\e[0;37;49mhi\e[0m", color.colorize('hi', :white) + assert_equal "\e[0;90;49mhi\e[0m", color.colorize('hi', :light_black) + assert_equal "\e[0;91;49mhi\e[0m", color.colorize('hi', :light_red) + assert_equal "\e[0;92;49mhi\e[0m", color.colorize('hi', :light_green) + assert_equal "\e[0;93;49mhi\e[0m", color.colorize('hi', :light_yellow) + assert_equal "\e[0;94;49mhi\e[0m", color.colorize('hi', :light_blue) + assert_equal "\e[0;95;49mhi\e[0m", color.colorize('hi', :light_magenta) + assert_equal "\e[0;96;49mhi\e[0m", color.colorize('hi', :light_cyan) + assert_equal "\e[0;97;49mhi\e[0m", color.colorize('hi', :light_white) + end + + def test_colorize_bold_colors + color = SSHKit::Color.new(stub(tty?: true), {}) + assert_equal "\e[1;30;49mhi\e[0m", color.colorize('hi', :black, :bold) + assert_equal "\e[1;31;49mhi\e[0m", color.colorize('hi', :red, :bold) + assert_equal "\e[1;32;49mhi\e[0m", color.colorize('hi', :green, :bold) + assert_equal "\e[1;33;49mhi\e[0m", color.colorize('hi', :yellow, :bold) + assert_equal "\e[1;34;49mhi\e[0m", color.colorize('hi', :blue, :bold) + assert_equal "\e[1;35;49mhi\e[0m", color.colorize('hi', :magenta, :bold) + assert_equal "\e[1;36;49mhi\e[0m", color.colorize('hi', :cyan, :bold) + assert_equal "\e[1;37;49mhi\e[0m", color.colorize('hi', :white, :bold) + assert_equal "\e[1;90;49mhi\e[0m", color.colorize('hi', :light_black, :bold) + assert_equal "\e[1;91;49mhi\e[0m", color.colorize('hi', :light_red, :bold) + assert_equal "\e[1;92;49mhi\e[0m", color.colorize('hi', :light_green, :bold) + assert_equal "\e[1;93;49mhi\e[0m", color.colorize('hi', :light_yellow, :bold) + assert_equal "\e[1;94;49mhi\e[0m", color.colorize('hi', :light_blue, :bold) + assert_equal "\e[1;95;49mhi\e[0m", color.colorize('hi', :light_magenta, :bold) + assert_equal "\e[1;96;49mhi\e[0m", color.colorize('hi', :light_cyan, :bold) + assert_equal "\e[1;97;49mhi\e[0m", color.colorize('hi', :light_white, :bold) + end + + def test_ignores_unrecognized_color + color = SSHKit::Color.new(stub(tty?: true), {}) + assert_equal 'hi', color.colorize('hi', :tangerine) + end + + def test_ignores_unrecognized_mode + color = SSHKit::Color.new(stub(tty?: true), {}) + assert_equal "\e[0;31;49mhi\e[0m", color.colorize('hi', :red, :underline) + end end end