nyan-cat-chef-formatter 0.1.0
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.
- data/LICENSE.md +21 -0
- data/README.md +74 -0
- data/lib/nyan-cat-chef-formatter.rb +248 -0
- data/nyan-cat-chef-formatter.gemspec +18 -0
- metadata +49 -0
data/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2012 Andrea Campi
|
2
|
+
Copyright (c) 2011 Matt Sears
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
Nyan Cat <3 Chef
|
2
|
+
================
|
3
|
+
|
4
|
+
A formatter for [Chef](http://opscode.com) dedicated to the wonderful Nyan Cat!
|
5
|
+
|
6
|
+
Starting Chef Client, version 10.14.4
|
7
|
+
Compiling cookbooks
|
8
|
+
.............................................................done.
|
9
|
+
Converging 138 resources
|
10
|
+
278/278: _-_-_+-_-_-_-_+_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-__,------,
|
11
|
+
270/278: _-_-_+-_-_-_-_+_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-__| /\_/\
|
12
|
+
8/278: _-_-_+-_-_-_-_+_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_~|_( - .-)
|
13
|
+
0/278: _-_-_+-_-_-_-_+-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ "" ""
|
14
|
+
|
15
|
+
System converged.
|
16
|
+
|
17
|
+
This formatter will display the total number of processed resources, as the
|
18
|
+
number of unchanged, updated and failed resources.
|
19
|
+
|
20
|
+
The rainbow changes colors as it runs.
|
21
|
+
|
22
|
+
This is inspired by [Nyan Cat RSpec Formatter](https://github.com/mattsears/nyan-cat-formatter).
|
23
|
+
Actually no, scratch that: this is basically a ripoff. So sue me.
|
24
|
+
|
25
|
+
Usage
|
26
|
+
=====
|
27
|
+
|
28
|
+
Install the gem:
|
29
|
+
|
30
|
+
gem install nyan-cat-chef-formatter
|
31
|
+
|
32
|
+
If you are using Omnibus Chef you need to specify the full path to the `gem`
|
33
|
+
binary:
|
34
|
+
|
35
|
+
/opt/chef/embedded/bin/gem install nyan-cat-chef-formatter
|
36
|
+
|
37
|
+
Or write a cookbook to install it using the `chef_gem` resource, if that's
|
38
|
+
how you roll.
|
39
|
+
|
40
|
+
Then add the following to your `/etc/chef/client.rb` file:
|
41
|
+
|
42
|
+
gem 'nyan-cat-chef-formatter'
|
43
|
+
require 'nyan-cat-chef-formatter'
|
44
|
+
|
45
|
+
This enables the formatter, but doesn't use it by default. To see Nyan in all its
|
46
|
+
glory, run:
|
47
|
+
|
48
|
+
chef-client -Fnyan -lfatal
|
49
|
+
|
50
|
+
Enjoy!
|
51
|
+
|
52
|
+
For serious Nyan addicts only!
|
53
|
+
------------------------------
|
54
|
+
|
55
|
+
To enable the Nyan formatter by default, add the following line to
|
56
|
+
`/etc/chef/client.rb`:
|
57
|
+
|
58
|
+
formatter :nyan
|
59
|
+
|
60
|
+
Contributing
|
61
|
+
----------
|
62
|
+
|
63
|
+
Once you've made your great commits:
|
64
|
+
|
65
|
+
1. Fork Nyan Cat
|
66
|
+
2. Create a topic branch - git checkout -b my_branch
|
67
|
+
3. Push to your branch - git push origin my_branch
|
68
|
+
4. Create a Pull Request from your branch
|
69
|
+
5. That's it!
|
70
|
+
|
71
|
+
Author
|
72
|
+
----------
|
73
|
+
[Andrea Campi](https://www.github.com/andreacampi) :: @andreacampi
|
74
|
+
[Matt Sears](https://wwww.mattsears.com) :: @mattsears
|
@@ -0,0 +1,248 @@
|
|
1
|
+
require 'chef/formatters/minimal'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
module Formatters
|
5
|
+
class NyanCat < Formatters::Minimal
|
6
|
+
|
7
|
+
cli_name(:nyan)
|
8
|
+
|
9
|
+
ESC = "\e["
|
10
|
+
NND = "#{ESC}0m"
|
11
|
+
PASS = '='
|
12
|
+
PASS_ARY = ['-', '_']
|
13
|
+
FAIL = '*'
|
14
|
+
ERROR = '!'
|
15
|
+
UPDATED = '+'
|
16
|
+
|
17
|
+
# attr_reader :current, :example_results, :color_index, :pending_count,
|
18
|
+
# :failure_count, :example_count
|
19
|
+
#
|
20
|
+
def initialize(out, err)
|
21
|
+
super
|
22
|
+
|
23
|
+
@started = @finished = false
|
24
|
+
end
|
25
|
+
|
26
|
+
def run_start(version)
|
27
|
+
super
|
28
|
+
|
29
|
+
@total_count = 0
|
30
|
+
@current = @color_index = @failure_count = @updated_count = 0
|
31
|
+
@ticks = []
|
32
|
+
end
|
33
|
+
|
34
|
+
# Called before convergence starts
|
35
|
+
def converge_start(run_context)
|
36
|
+
@total_count = run_context.resource_collection.all_resources.size # + 150
|
37
|
+
@started = true
|
38
|
+
puts "Converging #{run_context.resource_collection.all_resources.size} resources"
|
39
|
+
end
|
40
|
+
|
41
|
+
def converge_complete
|
42
|
+
@finished = true
|
43
|
+
dump_progress
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
def resource_failed_retriable(resource, action, retry_count, exception)
|
48
|
+
return unless @started
|
49
|
+
@failure_count += 1
|
50
|
+
tick FAIL
|
51
|
+
end
|
52
|
+
|
53
|
+
def resource_failed(resource, action, exception)
|
54
|
+
return unless @started
|
55
|
+
@failure_count += 1
|
56
|
+
tick FAIL
|
57
|
+
end
|
58
|
+
|
59
|
+
def resource_skipped(resource, action, conditional)
|
60
|
+
return unless @started
|
61
|
+
tick PASS
|
62
|
+
end
|
63
|
+
|
64
|
+
def resource_up_to_date(resource, action)
|
65
|
+
return unless @started
|
66
|
+
tick PASS
|
67
|
+
end
|
68
|
+
|
69
|
+
# Called after a resource has been completely converged.
|
70
|
+
def resource_updated(resource, action)
|
71
|
+
updated_resources << resource
|
72
|
+
return unless @started
|
73
|
+
@updated_count += 1
|
74
|
+
tick UPDATED
|
75
|
+
end
|
76
|
+
|
77
|
+
def tick(mark = PASS)
|
78
|
+
@ticks << mark
|
79
|
+
@current += 1
|
80
|
+
@total_count = @current if @current > @total_count
|
81
|
+
dump_progress
|
82
|
+
end
|
83
|
+
|
84
|
+
# Determine which Ascii Nyan Cat to display. If tests are complete,
|
85
|
+
# Nyan Cat goes to sleep. If there are failing or pending examples,
|
86
|
+
# Nyan Cat is concerned.
|
87
|
+
#
|
88
|
+
# @return [String] Nyan Cat
|
89
|
+
def nyan_cat
|
90
|
+
if self.failed? && self.finished?
|
91
|
+
ascii_cat('x')[@color_index%2].join("\n") #'~|_(x.x)'
|
92
|
+
elsif self.failed?
|
93
|
+
ascii_cat('o')[@color_index%2].join("\n") #'~|_(o.o)'
|
94
|
+
elsif self.finished?
|
95
|
+
ascii_cat('-')[@color_index%2].join("\n") # '~|_(-.-)'
|
96
|
+
else
|
97
|
+
ascii_cat('^')[@color_index%2].join("\n") # '~|_(^.^)'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Displays the current progress in all Nyan Cat glory
|
102
|
+
#
|
103
|
+
# @return nothing
|
104
|
+
def dump_progress
|
105
|
+
padding = @total_count.to_s.length * 2 + 2
|
106
|
+
line = nyan_trail.split("\n").each_with_index.inject([]) do |result, (trail, index)|
|
107
|
+
value = "#{scoreboard[index]}/#{@total_count}:"
|
108
|
+
result << format("%s %s", value, trail)
|
109
|
+
end.join("\n")
|
110
|
+
output.print line + eol
|
111
|
+
end
|
112
|
+
|
113
|
+
# Determines how we end the trail line. If complete, return a newline etc.
|
114
|
+
#
|
115
|
+
# @return [String]
|
116
|
+
def eol
|
117
|
+
return "\n" if @finished
|
118
|
+
length = (nyan_cat.split("\n").length - 1)
|
119
|
+
length > 0 ? format("\e[1A" * length + "\r") : "\r"
|
120
|
+
end
|
121
|
+
|
122
|
+
# Calculates the current flight length
|
123
|
+
#
|
124
|
+
# @return [Fixnum]
|
125
|
+
def current_width
|
126
|
+
padding = @total_count.to_s.length * 2 + 6
|
127
|
+
cat_length = nyan_cat.split("\n").group_by(&:size).max.first
|
128
|
+
padding + (@current >= @total_count ? @total_count : @current) + cat_length
|
129
|
+
end
|
130
|
+
|
131
|
+
# A Unix trick using stty to get the console columns
|
132
|
+
#
|
133
|
+
# @return [Fixnum]
|
134
|
+
def terminal_width
|
135
|
+
if defined? JRUBY_VERSION
|
136
|
+
default_width = 80
|
137
|
+
else
|
138
|
+
default_width = `stty size`.split.map { |x| x.to_i }.reverse.first - 1
|
139
|
+
end
|
140
|
+
@terminal_width ||= default_width
|
141
|
+
end
|
142
|
+
|
143
|
+
# Creates a data store of pass, failed, and pending example results
|
144
|
+
# We have to pad the results here because sprintf can't properly pad color
|
145
|
+
#
|
146
|
+
# @return [Array]
|
147
|
+
def scoreboard
|
148
|
+
padding = @total_count.to_s.length
|
149
|
+
[ @current.to_s.rjust(padding),
|
150
|
+
green((@current - @updated_count - @failure_count).to_s.rjust(padding)),
|
151
|
+
blue(@updated_count.to_s.rjust(padding)),
|
152
|
+
red(@failure_count.to_s.rjust(padding)) ]
|
153
|
+
end
|
154
|
+
|
155
|
+
# Creates a rainbow trail
|
156
|
+
#
|
157
|
+
# @return [String] the sprintf format of the Nyan cat
|
158
|
+
def nyan_trail
|
159
|
+
marks = @ticks.map{ |mark| highlight(mark) }
|
160
|
+
marks.shift(current_width - terminal_width) if current_width >= terminal_width
|
161
|
+
nyan_cat_lines = nyan_cat.split("\n").each_with_index.map do |line, index|
|
162
|
+
format("%s#{line}", marks.join)
|
163
|
+
end.join("\n")
|
164
|
+
end
|
165
|
+
|
166
|
+
# Ascii version of Nyan cat. Two cats in the array allow Nyan to animate running.
|
167
|
+
#
|
168
|
+
# @param o [String] Nyan's eye
|
169
|
+
# @return [Array] Nyan cats
|
170
|
+
def ascii_cat(o = '^')
|
171
|
+
[[ "_,------, ",
|
172
|
+
"_| /\\_/\\ ",
|
173
|
+
"~|_( #{o} .#{o}) ",
|
174
|
+
" \"\" \"\" "
|
175
|
+
],
|
176
|
+
[ "_,------, ",
|
177
|
+
"_| /\\_/\\",
|
178
|
+
"^|__( #{o} .#{o}) ",
|
179
|
+
" \"\" \"\" "
|
180
|
+
]]
|
181
|
+
end
|
182
|
+
|
183
|
+
# Colorizes the string with raindow colors of the rainbow
|
184
|
+
#
|
185
|
+
# @params string [String]
|
186
|
+
# @return [String]
|
187
|
+
def rainbowify(string)
|
188
|
+
c = colors[@color_index % colors.size]
|
189
|
+
@color_index += 1
|
190
|
+
"#{ESC}38;5;#{c}m#{string}#{NND}"
|
191
|
+
end
|
192
|
+
|
193
|
+
# Calculates the colors of the rainbow
|
194
|
+
#
|
195
|
+
# @return [Array]
|
196
|
+
def colors
|
197
|
+
@colors ||= (0...(6 * 7)).map do |n|
|
198
|
+
pi_3 = Math::PI / 3
|
199
|
+
n *= 1.0 / 6
|
200
|
+
r = (3 * Math.sin(n ) + 3).to_i
|
201
|
+
g = (3 * Math.sin(n + 2 * pi_3) + 3).to_i
|
202
|
+
b = (3 * Math.sin(n + 4 * pi_3) + 3).to_i
|
203
|
+
36 * r + 6 * g + b + 16
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Determines how to color the example. If pass, it is rainbowified, otherwise
|
208
|
+
# we assign red if failed or yellow if an error occurred.
|
209
|
+
#
|
210
|
+
# @return [String]
|
211
|
+
def highlight(mark = PASS)
|
212
|
+
case mark
|
213
|
+
when PASS; rainbowify PASS_ARY[@color_index%2]
|
214
|
+
when FAIL; "\e[31m#{mark}\e[0m"
|
215
|
+
when ERROR; "\e[33m#{mark}\e[0m"
|
216
|
+
when UPDATED; "\e[34m#{mark}\e[0m"
|
217
|
+
else mark
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Converts a float of seconds into a minutes/seconds string
|
222
|
+
#
|
223
|
+
# @return [String]
|
224
|
+
def format_duration(duration)
|
225
|
+
seconds = ((duration % 60) * 100.0).round / 100.0 # 1.8.7 safe .round(2)
|
226
|
+
seconds = seconds.to_i if seconds.to_i == seconds # drop that zero if it's not needed
|
227
|
+
|
228
|
+
message = "#{seconds} second#{seconds == 1 ? "" : "s"}"
|
229
|
+
message = "#{(duration / 60).to_i} minute#{(duration / 60).to_i == 1 ? "" : "s"} and " + message if duration >= 60
|
230
|
+
|
231
|
+
message
|
232
|
+
end
|
233
|
+
|
234
|
+
def finished?
|
235
|
+
@finished
|
236
|
+
end
|
237
|
+
|
238
|
+
def failed?
|
239
|
+
@failure_count.to_i > 0
|
240
|
+
end
|
241
|
+
|
242
|
+
def green(text); "\e[32m#{text}\e[0m"; end
|
243
|
+
def red(text); "\e[31m#{text}\e[0m"; end
|
244
|
+
def yellow(text); "\e[33m#{text}\e[0m"; end
|
245
|
+
def blue(text); "\e[34m#{text}\e[0m"; end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "nyan-cat-chef-formatter"
|
5
|
+
s.version = "0.1.0"
|
6
|
+
s.authors = ["Andrea Campi"]
|
7
|
+
s.email = ["andrea.campi@zephirworks.com"]
|
8
|
+
s.homepage = "https://github.com/andreacampi/nyan-cat-chef-formatter"
|
9
|
+
s.summary = %q{Nyan Cat inspired Chef formatter}
|
10
|
+
s.description = %q{Nyan Cat inspired Chef formatter}
|
11
|
+
|
12
|
+
s.rubyforge_project = "nyan-cat-chef-formatter"
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nyan-cat-chef-formatter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Andrea Campi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-06 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Nyan Cat inspired Chef formatter
|
15
|
+
email:
|
16
|
+
- andrea.campi@zephirworks.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- LICENSE.md
|
22
|
+
- README.md
|
23
|
+
- lib/nyan-cat-chef-formatter.rb
|
24
|
+
- nyan-cat-chef-formatter.gemspec
|
25
|
+
homepage: https://github.com/andreacampi/nyan-cat-chef-formatter
|
26
|
+
licenses: []
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
none: false
|
33
|
+
requirements:
|
34
|
+
- - ! '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
requirements: []
|
44
|
+
rubyforge_project: nyan-cat-chef-formatter
|
45
|
+
rubygems_version: 1.8.24
|
46
|
+
signing_key:
|
47
|
+
specification_version: 3
|
48
|
+
summary: Nyan Cat inspired Chef formatter
|
49
|
+
test_files: []
|