bee 0.10.2 → 0.11.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.
@@ -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