bee 0.10.2 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,314 @@
1
+ # Copyright 2006-2011 Michel Casabianca <michel.casabianca@gmail.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'rubygems'
16
+ require 'bee_console_style'
17
+
18
+ module Bee
19
+
20
+ module Console
21
+
22
+ # Class to format build output on console.
23
+ class Formatter
24
+
25
+ include Bee::Util::BuildErrorMixin
26
+
27
+ # Minimum duration to print on console even if not verbose (in seconds)
28
+ AUTO_DURATION = 60
29
+
30
+ # Construct formatting order
31
+ CONSTRUCT_FORMATS = {
32
+ 'if' => ['if', 'then', 'else'],
33
+ 'while' => ['while', 'do'],
34
+ 'for' => ['for', 'in', 'do'],
35
+ 'try' => ['try', 'catch'],
36
+ }
37
+
38
+ # Verbosity indicator
39
+ attr_reader :verbose
40
+
41
+ # Constructor.
42
+ # - style: style as a Hash or a String.
43
+ # - color: tells if we use default color scheme. Defaults to false.
44
+ # - verbose: tells if build is verbose. Defaults to false.
45
+ # - outputer: object on which we call print and puts for outputs.
46
+ # Defaults to Kernel.
47
+ def initialize(style, color=false, verbose=false, outputer=Kernel)
48
+ @style = Bee::Console::Style.new(style, color)
49
+ @verbose = verbose
50
+ @outputer = outputer
51
+ end
52
+
53
+ ##########################################################################
54
+ # LOW LEVEL OUTPUT METHODS #
55
+ ##########################################################################
56
+
57
+ # Print a given message on console:
58
+ # - message: the message to print.
59
+ def print(message)
60
+ @outputer.print(message)
61
+ end
62
+
63
+ # Puts a given message on console:
64
+ # - message: the message to put.
65
+ def puts(message)
66
+ @outputer.puts(message)
67
+ end
68
+
69
+ ##########################################################################
70
+ # METHODS CALLED BY LISTENER #
71
+ ##########################################################################
72
+
73
+ # Print build start message:
74
+ # - build: the started build.
75
+ # - dry_run: tells if we are running in dry mode.
76
+ def print_build_started(build, dry_run)
77
+ if @verbose
78
+ build_type = dry_run ? "dry run of" : "build"
79
+ puts "Starting #{build_type} '#{build.file}'..."
80
+ end
81
+ end
82
+
83
+ # Print message when build finished:
84
+ # - duration: the build duration in seconds.
85
+ # - success: tells if build was a success.
86
+ # - exception : exception raised, if any.
87
+ # - last_target: last met target, if any.
88
+ # - last_task: last met task, if any.
89
+ def print_build_finished(duration)
90
+ puts "Built in #{duration} s" if @verbose or duration >= AUTO_DURATION
91
+ end
92
+
93
+ # Print target:
94
+ # - target: the target we are running.
95
+ def print_target(target)
96
+ puts format_target(target)
97
+ end
98
+
99
+ # Print task:
100
+ # - task: the task we are running.
101
+ def print_task(task)
102
+ puts format_task(task) if @verbose
103
+ end
104
+
105
+ ##########################################################################
106
+ # FORMATTING METHODS #
107
+ ##########################################################################
108
+
109
+ # Format a target.
110
+ # - target: target to format.
111
+ def format_target(target)
112
+ name = target.name
113
+ return format_title(name)
114
+ end
115
+
116
+ # Format a task.
117
+ # - task: task to format.
118
+ def format_task(task)
119
+ if task.kind_of?(String)
120
+ source = task
121
+ elsif task.kind_of?(Hash)
122
+ if task.key?('rb')
123
+ source = "rb: #{task['rb']}"
124
+ else
125
+ if task.keys.length == 1
126
+ source = format_entry(task)
127
+ else
128
+ source = format_construct(task)
129
+ end
130
+ end
131
+ end
132
+ formatted = '- ' + source.strip.gsub(/\n/, "\n. ")
133
+ styled = @style.style(formatted, :task)
134
+ return styled
135
+ end
136
+
137
+ # Format a success string.
138
+ # - string: string to format.
139
+ def format_success(string)
140
+ string = @style.style(string, :success)
141
+ return string
142
+ end
143
+
144
+ # Format an error string.
145
+ # - string: string to format.
146
+ def format_error(string)
147
+ string = @style.style(string, :error)
148
+ return string
149
+ end
150
+
151
+ # Format error message:
152
+ # - exception: raised exception.
153
+ def format_error_message(exception)
154
+ message = format_error('ERROR')
155
+ message << ": "
156
+ message << exception.to_s
157
+ if exception.kind_of?(Bee::Util::BuildError)
158
+ message << "\nIn target '#{exception.target.name}'" if exception.target
159
+ message << ", in task:\n#{format_task(exception.task)}" if exception.task
160
+ end
161
+ return message
162
+ end
163
+
164
+ # Format a description.
165
+ # - title: description title (project, property or target name).
166
+ # - text: description text.
167
+ # - indent: indentation width.
168
+ # - bullet: tells if we must put a bullet.
169
+ def format_description(title, text=nil, indent=0, bullet=true)
170
+ string = ' '*indent
171
+ string << '- ' if bullet
172
+ string << title
173
+ if text and !text.empty?
174
+ string << ": "
175
+ if text.split("\n").length > 1
176
+ string << "\n"
177
+ text.split("\n").each do |line|
178
+ string << ' '*(indent+2) + line.strip + "\n"
179
+ end
180
+ else
181
+ string << text.strip + "\n"
182
+ end
183
+ else
184
+ string << "\n"
185
+ end
186
+ return string
187
+ end
188
+
189
+ # Format a title.
190
+ # - title: title to format.
191
+ def format_title(title)
192
+ length = @style.line_length || Bee::Util::term_width
193
+ right = ' ' + @style.line_character*2
194
+ size = length - (title.length + 4)
195
+ size = 2 if size <= 0
196
+ left = @style.line_character*size + ' '
197
+ line = left + title + right
198
+ # apply style
199
+ formatted = @style.style(line, :target)
200
+ return formatted
201
+ end
202
+
203
+ ##########################################################################
204
+ # HELP FORMATTING METHODS #
205
+ ##########################################################################
206
+
207
+ # Return help about build.
208
+ # - build: running build.
209
+ def help_build(build)
210
+ build.context.evaluate
211
+ help = ''
212
+ # print build name and description
213
+ if build.name
214
+ help << "build: #{build.name}\n"
215
+ end
216
+ if build.extends
217
+ help << "extends: #{build.extends.map{|b| b.name}.join(', ')}\n"
218
+ end
219
+ if build.description
220
+ help << format_description('description', build.description, 0, false)
221
+ end
222
+ # print build properties
223
+ if build.context.properties.length > 0
224
+ help << "properties:\n"
225
+ for property in build.context.properties.sort
226
+ help << "- #{property}: " +
227
+ "#{build.context.get_property(property).inspect}\n"
228
+ end
229
+ end
230
+ # print build targets
231
+ description = build.targets.description
232
+ if description.length > 0
233
+ help << "targets:\n"
234
+ for name in description.keys.sort
235
+ help << format_description(name, description[name], 0)
236
+ end
237
+ end
238
+ # print default target
239
+ help << "default: #{build.targets.default}\n"
240
+ return help.strip
241
+ end
242
+
243
+ # Return help about task(s).
244
+ # - task: task to print help about (all tasks if nil).
245
+ def help_task(task)
246
+ task = '?' if task == nil or task.length == 0
247
+ package_manager = Bee::Task::PackageManager.new(nil)
248
+ methods = package_manager.help_task(task)
249
+ help = ''
250
+ for method in methods.keys.sort
251
+ text = methods[method].strip
252
+ help << format_title(method)
253
+ help << "\n"
254
+ help << text
255
+ help << "\n"
256
+ if text =~ /Alias for \w+/
257
+ alias_method = text.scan(/Alias for (\w+)/).flatten[0]
258
+ help << "\n"
259
+ help << package_manager.help_task(alias_method)[alias_method].strip
260
+ help << "\n"
261
+ end
262
+ end
263
+ return help
264
+ end
265
+
266
+ # Return help about template(s).
267
+ # - template: template to print help about (all templates if nil).
268
+ def help_template(template)
269
+ templates = Bee::Util::search_templates(template)
270
+ help = ''
271
+ for name in templates.keys
272
+ build = YAML::load(File.read(templates[name]))
273
+ properties = nil
274
+ for entry in build
275
+ properties = entry['properties'] if entry['properties']
276
+ end
277
+ description = 'No description found'
278
+ if properties
279
+ if properties['description']
280
+ description = properties['description']
281
+ end
282
+ end
283
+ help << format_title(name)
284
+ help << "\n"
285
+ help << description
286
+ help << "\n"
287
+ end
288
+ return help
289
+ end
290
+
291
+ private
292
+
293
+ def format_entry(entry)
294
+ return YAML::dump(entry).sub(/---/, '').strip
295
+ end
296
+
297
+ def format_construct(construct)
298
+ for key in CONSTRUCT_FORMATS.keys
299
+ if construct.has_key?(key)
300
+ lines = []
301
+ for entry in CONSTRUCT_FORMATS[key]
302
+ lines << format_entry({entry => construct[entry]})
303
+ end
304
+ return lines.join("\n")
305
+ end
306
+ end
307
+ return "UNKNOWN CONSTRUCT"
308
+ end
309
+
310
+ end
311
+
312
+ end
313
+
314
+ end
@@ -0,0 +1,222 @@
1
+ # Copyright 2006-2011 Michel Casabianca <michel.casabianca@gmail.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'rubygems'
16
+ require 'bee_util'
17
+
18
+ module Bee
19
+
20
+ module Console
21
+
22
+ # Class to manage a style for console output.
23
+ class Style
24
+
25
+ include Bee::Util::BuildErrorMixin
26
+
27
+ # style attributes
28
+ attr_reader :line_character
29
+ attr_reader :line_length
30
+ attr_reader :target_style
31
+ attr_reader :target_foreground
32
+ attr_reader :target_background
33
+ attr_reader :task_style
34
+ attr_reader :task_foreground
35
+ attr_reader :task_background
36
+ attr_reader :success_style
37
+ attr_reader :success_foreground
38
+ attr_reader :success_background
39
+ attr_reader :error_style
40
+ attr_reader :error_foreground
41
+ attr_reader :error_background
42
+
43
+ # List of style types
44
+ TYPES = [:target, :task, :success, :error]
45
+
46
+ # List of colors.
47
+ COLORS = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white]
48
+
49
+ # Foreground color codes.
50
+ FOREGROUND_COLOR_CODES = {
51
+ :black => 30,
52
+ :red => 31,
53
+ :green => 32,
54
+ :yellow => 33,
55
+ :blue => 34,
56
+ :magenta => 35,
57
+ :cyan => 36,
58
+ :white => 37
59
+ }
60
+
61
+ # Background color codes.
62
+ BACKGROUND_COLOR_CODES = {
63
+ :black => 40,
64
+ :red => 41,
65
+ :green => 42,
66
+ :yellow => 43,
67
+ :blue => 44,
68
+ :magenta => 45,
69
+ :cyan => 46,
70
+ :white => 47
71
+ }
72
+
73
+ # List of styles.
74
+ STYLES = [:reset, :bright, :dim, :underscore, :blink, :reverse, :hidden]
75
+
76
+ # Style codes.
77
+ STYLE_CODES = {
78
+ :reset => 0,
79
+ :bright => 1,
80
+ :dim => 2,
81
+ :underscore => 4,
82
+ :blink => 5,
83
+ :reverse => 7,
84
+ :hidden => 8
85
+ }
86
+
87
+ # Default style (supposed to work on any configuration).
88
+ DEFAULT_STYLE = {
89
+ :line_character => '-'
90
+ }
91
+
92
+ # Color style (supposed to work on color terminals).
93
+ COLOR_STYLE = {
94
+ :line_character => '-',
95
+ :target_foreground => :yellow,
96
+ :task_foreground => :blue,
97
+ :success_style => :bright,
98
+ :success_foreground => :green,
99
+ :error_style => :bright,
100
+ :error_foreground => :red
101
+ }
102
+
103
+ # Short style keys for command line
104
+ SHORT_STYLE_KEYS = {
105
+ 'lc' => 'line_character',
106
+ 'll' => 'line_length',
107
+ 'ts' => 'target_style',
108
+ 'tf' => 'target_foreground',
109
+ 'tb' => 'target_background',
110
+ 'ks' => 'task_style',
111
+ 'kf' => 'task_foreground',
112
+ 'kb' => 'task_background',
113
+ 'ss' => 'success_style',
114
+ 'sf' => 'success_foreground',
115
+ 'sb' => 'success_background',
116
+ 'es' => 'error_style',
117
+ 'ef' => 'error_foreground',
118
+ 'eb' => 'error_background'
119
+ }
120
+
121
+ # Build the style from command line arguments:
122
+ # - style: the style as a hash or a string (as passed on command line).
123
+ # Defaults to nil.
124
+ # - color: tells if we use color style. Defaults to nil.
125
+ def initialize(style=nil, color=nil)
126
+ @line_character = nil
127
+ @line_length = nil
128
+ @target_style = nil
129
+ @target_foreground = nil
130
+ @target_background = nil
131
+ @task_style = nil
132
+ @task_foreground = nil
133
+ @task_background = nil
134
+ @success_style = nil
135
+ @success_foreground = nil
136
+ @success_background = nil
137
+ @error_style = nil
138
+ @error_foreground = nil
139
+ @error_background = nil
140
+ apply(color ? COLOR_STYLE : DEFAULT_STYLE)
141
+ apply(style)
142
+ end
143
+
144
+ # Apply style to a string:
145
+ # - string: the string to apply style to.
146
+ # - type: the type of style to apply (one of :target, :task, :success or
147
+ # :error).
148
+ def style(string, type)
149
+ raise "Type '#{type}' unknown: must be one of " + TYPES.map{|e| ":#{e}"}.join(', ') if
150
+ not TYPES.include?(type)
151
+ style = eval("@#{type}_style")
152
+ foreground = eval("@#{type}_foreground")
153
+ background = eval("@#{type}_background")
154
+ # if no style nor colors, return raw string
155
+ return string if not foreground and not background and not style
156
+ # insert style and colors in string
157
+ colorized = "\e["
158
+ colorized << "#{STYLE_CODES[style]};" if style
159
+ colorized << "#{FOREGROUND_COLOR_CODES[foreground]};" if foreground
160
+ colorized << "#{BACKGROUND_COLOR_CODES[background]};" if background
161
+ colorized = colorized[0..-2]
162
+ colorized << "m#{string}\e[#{STYLE_CODES[:reset]}m"
163
+ return colorized
164
+ end
165
+
166
+ private
167
+
168
+ # Apply a given style:
169
+ # - style: the style as a hash or a string.
170
+ def apply(style)
171
+ if style.kind_of?(Hash)
172
+ for key, value in style
173
+ check_attribute_value(key, value)
174
+ eval("@#{key} = #{value.inspect}")
175
+ end
176
+ elsif style.kind_of?(String)
177
+ for pair in style.split(',')
178
+ key, value = pair.split(':')
179
+ key = SHORT_STYLE_KEYS[key] || key
180
+ key = key.to_sym
181
+ if key == :line_length
182
+ value = value.to_i
183
+ elsif key == :line_character
184
+ value = ' ' if not value or value.length == 0
185
+ else
186
+ value = value.to_sym if value
187
+ end
188
+ check_attribute_value(key, value)
189
+ eval("@#{key} = #{value.inspect}")
190
+ end
191
+ else
192
+ raise "Style must ne a Hash or a String" if style
193
+ end
194
+ end
195
+
196
+ def check_attribute_value(attribute, value)
197
+ raise "Attribute '#{attribute}' must be a symbol" unless
198
+ attribute.kind_of?(Symbol)
199
+ raise "Unknown attribute '#{attribute}'" unless
200
+ instance_variable_defined?("@#{attribute}".to_sym)
201
+ if attribute == :line_length
202
+ raise "'line_length' attribute must be an integer" unless
203
+ value.kind_of?(Integer)
204
+ elsif attribute == :line_character
205
+ raise "'line_character' must be a single character" unless
206
+ value.kind_of?(String) and value.length == 1
207
+ else
208
+ raise "Value '#{value}' should be a symbol" unless
209
+ value.kind_of?(Symbol)
210
+ if attribute.to_s[-6..-1] == '_style'
211
+ raise "Unkown style '#{value}'" if not STYLES.member?(value)
212
+ else
213
+ raise "Unkown color '#{value}'" if not COLORS.member?(value)
214
+ end
215
+ end
216
+ end
217
+
218
+ end
219
+
220
+ end
221
+
222
+ end