warning-shot 0.8.9

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.
Files changed (45) hide show
  1. data/History.txt +8 -0
  2. data/License.txt +24 -0
  3. data/Manifest.txt +44 -0
  4. data/README.txt +65 -0
  5. data/Rakefile +4 -0
  6. data/bin/warning-shot +74 -0
  7. data/config/hoe.rb +71 -0
  8. data/config/requirements.rb +17 -0
  9. data/config/warning_shot/binaries.yml +10 -0
  10. data/config/warning_shot/classes.yml +12 -0
  11. data/config/warning_shot/filesystem.yml +8 -0
  12. data/config/warning_shot/gems.yml +15 -0
  13. data/config/warning_shot/preload.yml +10 -0
  14. data/config/warning_shot/scripts/ruby/example.rb +19 -0
  15. data/config/warning_shot/scripts/ruby/post.rb +18 -0
  16. data/config/warning_shot/scripts/ruby/post_example.rb +18 -0
  17. data/config/warning_shot/scripts/ruby/pre.rb +18 -0
  18. data/config/warning_shot/scripts/ruby/pre_example.rb +19 -0
  19. data/config/warning_shot/scripts/shell/pre.sh +0 -0
  20. data/config/warning_shot/urls.yml +9 -0
  21. data/images/ruby_fail.png +0 -0
  22. data/images/ruby_ok.png +0 -0
  23. data/lib/warning_shot/config_parser.rb +46 -0
  24. data/lib/warning_shot/dep_checker.rb +584 -0
  25. data/lib/warning_shot/gem_handler.rb +217 -0
  26. data/lib/warning_shot/template_generator.rb +74 -0
  27. data/lib/warning_shot/test_script.rb +23 -0
  28. data/lib/warning_shot/version.rb +15 -0
  29. data/lib/warning_shot.rb +34 -0
  30. data/log/debug.log +0 -0
  31. data/script/destroy +14 -0
  32. data/script/generate +14 -0
  33. data/script/txt2html +74 -0
  34. data/setup.rb +1585 -0
  35. data/tasks/deployment.rake +34 -0
  36. data/tasks/environment.rake +7 -0
  37. data/tasks/website.rake +17 -0
  38. data/test/test_helper.rb +2 -0
  39. data/test/test_warning_shot.rb +11 -0
  40. data/website/index.html +93 -0
  41. data/website/index.txt +39 -0
  42. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  43. data/website/stylesheets/screen.css +138 -0
  44. data/website/template.rhtml +48 -0
  45. metadata +102 -0
@@ -0,0 +1,584 @@
1
+
2
+ module RippleNetworks
3
+ module WarningShot
4
+
5
+ =begin rdoc
6
+ *Name*:: WarningShot
7
+ *Type*:: Class
8
+ *Namespace*:: RippleNetworks::WarningShot
9
+ *Description*:: Application dependency checker
10
+ *Inherits*:: None
11
+ *Mixins*:: None
12
+ *Extends*:: None
13
+ *RequiredGems*:: activerecord
14
+ *RequiredRubyLibraries*:: rubygems, fileutils, net/http, net/https, uri, yaml
15
+ *RequiredBinaries*:: which, growlnotify (if --growl option used)
16
+ *Authors*:: Cory O'Daniel
17
+ *Email*:: codaniel @nospam@ rippletv.com
18
+ *Last_Edited*:: Wed Dec 12 15:01:00 PST 2007
19
+ =end
20
+ class DepChecker
21
+ include RippleNetworks::WarningShot
22
+ attr_reader :options, :warnings, :errors, :configs
23
+
24
+ LIB_DIRECTORY = $:[0]
25
+
26
+ #Config files to load
27
+ DEP_FILES = %w(urls preload classes binaries filesystem gems).freeze
28
+
29
+ #Script folders to load
30
+ SCRIPTS = %w(ruby shell).freeze
31
+
32
+ #Any mandatory options
33
+ MANDATORY_OPTIONS = %w().freeze
34
+
35
+ # Ability to map additional corporate environments to applicable rails environment
36
+ ENVIRONMENT_MAP = {
37
+ "test" => "test",
38
+ "development" => "development",
39
+ "qa" => "development",
40
+ "stage" => "production",
41
+ "production" => "production"
42
+ }.freeze
43
+
44
+ DEFAULTS = {
45
+ :dir => '.',
46
+ :environment => 'development',
47
+ :strict => false,
48
+ :flush => false,
49
+ :gems => false,
50
+ :verbose => false,
51
+ :growl => false,
52
+ :templates => false
53
+ }
54
+
55
+ #Set up CLEAR and Windows Add'l requirement
56
+ if PLATFORM =~ /win32/
57
+ CLEAR = `cls`
58
+ begin
59
+ require 'Win32/Console/ANSI'
60
+ rescue LoadError => e
61
+ puts "Run: 'gem install win32console' for colored output"
62
+ end
63
+ else
64
+ CLEAR = `clear`
65
+ end
66
+
67
+
68
+ def initialize(options=DEFAULTS)
69
+ @original_requires = $".clone
70
+
71
+ ObjectSpace.define_finalizer(self, lambda{ @log_file.close unless @log_file.closed? })
72
+
73
+ #Add directory information to defaults
74
+ DEFAULTS[:log] = File.join(options[:dir],"log","warning_shot_#{options[:environment]}.log")
75
+ DEFAULTS[:configs] = File.join(options[:dir],"config","warning_shot")
76
+
77
+ @options = DEFAULTS.merge(options)
78
+
79
+ #Map to correct running environment
80
+ @options[:environment] = ENVIRONMENT_MAP[@options[:environment]]
81
+
82
+ #No errors or warnings
83
+ @errors = 0
84
+ @warnings = 0
85
+
86
+ #initalize config file hash
87
+ @configs = {}
88
+
89
+ #Flush log
90
+ flush_log! if @options[:flush]
91
+
92
+ #Open log
93
+ @log_file = File.open(@options[:log],"a+")
94
+
95
+ #Check dependencies
96
+ @which_installed = has_binary_prereqs?
97
+ puts CLEAR if @options[:verbose]
98
+ end
99
+
100
+ =begin rdoc
101
+ *Name*:: DepChecker.has_binary?
102
+ *Access*:: public
103
+ *Description*:: Determine if an command line application is installed
104
+ *Last_Edited*:: Wed Dec 12 22:05:55 PST 2007
105
+ ===Parameters
106
+ * Name: app
107
+ * Description: name of cl tool
108
+ * Datatype: string
109
+ * Default: None
110
+ * Required: True
111
+ ===Returns
112
+ *Description*:: whether it is installed or not
113
+ *Datatype*:: Boolean
114
+ =end
115
+ def DepChecker.has_binary?(app)
116
+ %x{which #{app}}.match(/\bno/).nil?
117
+ end
118
+
119
+ def unload
120
+ ($" - @original_requires).each do |req|
121
+ $".delete(req)
122
+ end
123
+ end
124
+
125
+ =begin rdoc
126
+ *Name*:: generate_templates
127
+ *Access*:: public
128
+ *Description*:: Generates all template files
129
+ *Last_Edited*:: Fri Dec 14 17:53:32 PST 2007
130
+ *Todo*:: Encapsulate as seperate private functions
131
+ ===Parameters
132
+ * Name: path
133
+ * Description: path of creation
134
+ * Datatype: string
135
+ * Default: .
136
+ * Required: false
137
+ =end
138
+ def DepChecker.generate_templates(path=".")
139
+ TemplateGenerator.new(path)
140
+ end
141
+
142
+
143
+ =begin rdoc
144
+ *Name*:: run
145
+ *Access*:: private
146
+ *Description*:: Run dependency checker
147
+ *Last_Edited*:: Wed Dec 12 16:04:15 PST 2007
148
+ =end
149
+ def run
150
+ start_time = Time.now
151
+ section
152
+ record("WarningShot (v. #{VERSION::INTERNAL}) - started @ #{start_time}")
153
+ check_framework
154
+ record("Environment: #{@options[:environment]}")
155
+ record("Framework: #{@framework}")
156
+
157
+ section("Loading YAML files:")
158
+ ConfigParser.run(self)
159
+
160
+ section("Preloading classes")
161
+ class_loader("preload")
162
+
163
+ section("Checking class dependencies")
164
+ count = class_loader("classes")
165
+ record "#{count} classes not found",:error if count > 0
166
+
167
+ section("Checking binary dependencies")
168
+ count = check_binaries
169
+ record "#{count} binaries not found", :error if count > 0
170
+
171
+ section("Checking filesystem dependencies")
172
+ count = check_filesystem
173
+ record "#{count} files/directories not found", :error if count > 0
174
+
175
+ section("Checking URL dependencies")
176
+ count = check_urls
177
+ record "#{count} sites unavailable", :error if count > 0
178
+
179
+ section("Checking gem dependencies")
180
+ #Initialize gem handler
181
+ @gh = GemHandler.new(self.configs["gems"],self.options[:gems])
182
+
183
+ gem_errors = @gh.missing_gems.size
184
+
185
+ if @gh.missing_gems.size > 0
186
+ record "#{gem_errors} gems not found: "
187
+ @gh.missing_gems.each do |gem,version|
188
+ record "\t#{gem} : #{version}"
189
+ end
190
+ end
191
+
192
+ if self.options[:gems] && @gh.errors.size > 0
193
+ gem_errors = @gh.errors.size
194
+ record "#{gem_errors} gems failed to install:"
195
+ @gh.errors.each do |gem,message|
196
+ record "\t#{gem}: #{message}"
197
+ end
198
+ end
199
+
200
+ record("#{gem_errors} gems had errors", :error) if gem_errors > 0
201
+ @errors += gem_errors
202
+
203
+ section("Loading Ruby test scripts")
204
+ count = load_ruby_scripts
205
+ record("#{count} scripts failed to load",:error) if count > 0
206
+
207
+ section("Running Ruby test scripts")
208
+ count = test_ruby_scripts
209
+ record("#{count} scripts failed",:error) if count > 0
210
+
211
+ #section("Shell script dependencies")
212
+ #count = check_shell_scripts
213
+ #record("#{count} scripts failed",:error) if count > 0
214
+
215
+ section
216
+ section("RESULTS")
217
+ record("Total Warnings #{@warnings}",(@warnings > 0) ? :warning : :info)
218
+ record("Total Errors: #{@errors}",(@errors > 0) ? :error : :info)
219
+ record("Checked in #{Time.now.to_f-start_time.to_f}s",:info)
220
+ section
221
+
222
+ #Status via growlnotify
223
+ if @options[:growl]
224
+ #TODO Update to Red/Green ruby, instead of Rails Logo
225
+ if @errors == 0
226
+ growl("All Dependencies tests passed!","ruby_ok.png")
227
+ else
228
+ growl("#{@errors} failed dependencies!","ruby_fail.png")
229
+ end
230
+ end
231
+
232
+ unload
233
+ @log_file.close unless @log_file.closed?
234
+ end
235
+
236
+
237
+ =begin rdoc
238
+ *Name*:: record
239
+ *Access*:: public
240
+ *Description*:: Record message to log
241
+ *Last_Edited*:: Wed Dec 12 15:37:21 PST 2007
242
+ ===Parameters
243
+ * Name: level
244
+ * Description: Message level :error, :warning, :info, :none
245
+ * Datatype: Symbol
246
+ * Default: :info
247
+ * Required: false
248
+ =end
249
+ def record(msg,level=:none)
250
+ if [:error,:warning,:info,:fatal].include? level
251
+ msg = %{#{level.to_s.upcase}: #{msg}}
252
+ end
253
+
254
+ case level
255
+ when :error
256
+ @errors += 1
257
+ when :warning
258
+ @warnings += 1
259
+ end
260
+
261
+ @log_file.puts msg
262
+
263
+ if @options[:verbose]
264
+ case level
265
+ when :info
266
+ msg = "\e[37m#{msg}\e[0m"
267
+ when :error
268
+ msg = "\e[31m#{msg}\e[0m"
269
+ when :warning
270
+ msg = "\e[33m#{msg}\e[0m"
271
+ when :fatal
272
+ msg = "\e[1m\e[5m#{msg}\e[0m"
273
+ end
274
+
275
+ puts msg
276
+
277
+ Kernel.exit if level == :fatal
278
+ end
279
+ end
280
+
281
+
282
+ private
283
+
284
+ =begin rdoc
285
+ *Name*:: check_framework
286
+ *Access*:: private
287
+ *Description*:: Determines framework
288
+ *Last_Edited*:: Mon Dec 17 11:24:59 PST 2007
289
+ *Note*:: This function is still pretty experimental.
290
+ =end
291
+ def check_framework
292
+ if defined?(RAILS_ROOT)
293
+ @framework = "RAILS"
294
+ elsif defined?(Merb)
295
+ @framework = "MERB"
296
+ else
297
+ @framework = "CONSOLE"
298
+ end
299
+ end
300
+
301
+
302
+ =begin rdoc
303
+ *Name*:: growl
304
+ *Access*:: private
305
+ *Description*:: Sends msg via growlnotify
306
+ *Last_Edited*:: Wed Dec 12 19:47:34 PST 2007
307
+ ===Parameters
308
+ * Name: msg
309
+ * Description: Message displayed
310
+ * Datatype: String
311
+ * Default: None
312
+ * Required: True
313
+ * Name: img
314
+ * Description: path to image to display
315
+ * Datatype: String
316
+ * Default: nil
317
+ * Required: false
318
+ =end
319
+ def growl(msg,img=nil)
320
+ gmsg = %{growlnotify -t "WarningShot" -n "WarningShot" -m "#{msg}"}
321
+ gmsg += %{ --image #{File.join(LIB_DIRECTORY,"..","images",img)}} unless img.nil?
322
+ %x{#{gmsg}}
323
+ end
324
+
325
+
326
+ =begin rdoc
327
+ *Name*:: section
328
+ *Access*:: private
329
+ *Description*:: Display a section seperator
330
+ *Last_Edited*:: Mon Dec 17 10:45:52 PST 2007
331
+ ===Parameters
332
+ * Name: title
333
+ * Description: Puts a title in the seperator
334
+ * Datatype: string
335
+ * Default: None
336
+ * Required: False
337
+ =end
338
+ def section(title="")
339
+ record %{#{title.center(60,"-") }}
340
+ end
341
+
342
+
343
+ =begin rdoc
344
+ *Name*:: has_binary_prereqs?
345
+ *Access*:: private
346
+ *Description*:: Determine if system has the `which` command
347
+ *Last_Edited*:: Wed Dec 12 15:19:53 PST 2007
348
+ *Todo*:: Find a better way!!!
349
+ ===Returns
350
+ *Description: Whether binaries prereqs are installed
351
+ *Datatype: Boolean
352
+ =end
353
+ def has_binary_prereqs?
354
+ if DepChecker.has_binary? "which"
355
+
356
+ if @options[:growl]
357
+ unless DepChecker.has_binary? "growlnotify"
358
+ record "Could not locate: `growlnotify`", :warning
359
+ end
360
+ end
361
+ return true
362
+ else
363
+ record "Could not locate: `which`; required for binaries dependencies\n\tbinaries.yml will be skipped!!!", :error
364
+ return false
365
+ end
366
+ end
367
+
368
+
369
+ =begin rdoc
370
+ *Name*:: flush_log!
371
+ *Access*:: private
372
+ *Description*:: Flushes log file if it exists
373
+ *Last_Edited*:: Wed Dec 12 15:04:11 PST 2007
374
+ =end
375
+ def flush_log!
376
+ File.truncate(@options[:log],0) if File.exists? @options[:log]
377
+ #File.unlink @options[:log] if File.exists? @options[:log]
378
+ #FileUtils.touch @options[:log]
379
+ end
380
+
381
+
382
+ =begin rdoc
383
+ *Name*:: class_loader
384
+ *Access*:: private
385
+ *Description*:: Loads classes for dependency checking or as a resource for DepChecker
386
+ *Last_Edited*:: Wed Dec 12 20:18:13 PST 2007
387
+ ===Parameters
388
+ * Name: mode
389
+ * Description: Mode of operation (preload | classes)
390
+ * Datatype: String
391
+ * Default: :preload
392
+ * Required: false
393
+ =end
394
+ def class_loader(mode="preload")
395
+ errors = 0
396
+
397
+ @configs[mode].each do |klass|
398
+ begin
399
+ #TODO Mute output from requires, ie "puts"
400
+ #@@@ Rescue block doesn't seem to be catching error.
401
+ require klass
402
+ record("FOUND: #{klass}")
403
+ rescue LoadError => e
404
+ case mode
405
+ when "preload"
406
+ record("NOT FOUND: #{klass}",:fatal)
407
+ when "classes"
408
+ errors += 1
409
+ record("NOT FOUND: #{klass}",:error)
410
+ else
411
+ record("Invalid class_loader mode",:fatal)
412
+ end
413
+ end
414
+ end
415
+
416
+ return errors
417
+ end
418
+
419
+
420
+ =begin rdoc
421
+ *Name*:: check_binaries
422
+ *Access*:: private
423
+ *Description*:: check for installed binaries
424
+ *Last_Edited*:: Wed Dec 12 22:03:13 PST 2007
425
+ =end
426
+ def check_binaries
427
+ errors = 0
428
+
429
+ if @which_installed
430
+ @configs["binaries"].each do |binary|
431
+ if DepChecker.has_binary? binary
432
+ record("INSTALLED: #{binary}")
433
+ else
434
+ errors += 1
435
+ record("NOT FOUND: #{binary}",:error)
436
+ end
437
+ end
438
+
439
+ end
440
+
441
+ return errors
442
+ end
443
+
444
+
445
+ =begin rdoc
446
+ *Name*:: check_filesystem
447
+ *Access*:: private
448
+ *Description*:: check for files and directories
449
+ *Last_Edited*:: Thu Dec 13 11:22:03 PST 2007
450
+ =end
451
+ def check_filesystem
452
+ errors = 0
453
+
454
+ @configs["filesystem"].each do |path|
455
+ if File.file?(path)
456
+ record("FOUND (file): #{path}")
457
+ elsif File.directory?(path)
458
+ record("FOUND (directory): #{path}")
459
+ elsif File.exists?(path)
460
+ record("FOUND: #{path}")
461
+ else
462
+ record("NOT FOUND: #{path}", :error)
463
+ errors += 1
464
+ end
465
+ end
466
+
467
+ return errors
468
+ end
469
+
470
+
471
+ =begin rdoc
472
+ *Name*:: check_urls
473
+ *Access*:: private
474
+ *Description*::
475
+ *Last_Edited*:: Thu Dec 13 12:24:06 PST 2007
476
+ =end
477
+ def check_urls
478
+ errors = 0
479
+
480
+ @configs["urls"].each do |site|
481
+ uri = URI.parse site.chomp
482
+ http = Net::HTTP.new(uri.host, uri.port)
483
+ #TODO mute SSL "peer certificate verification" message
484
+ http.use_ssl = true if uri.scheme == "https"
485
+ uri.path = "/" if uri.path.empty?
486
+
487
+ begin
488
+ response, data = http.get(uri.path)
489
+ http_code = response.code.to_i
490
+
491
+ if @options[:strict] && http_code == 200
492
+ record("CONNECTED (#{http_code}): #{uri}")
493
+ elsif http_code >= 200 && http_code < 300
494
+ record("CONNECTED (#{http_code}): #{uri}", ((http_code != 200)? :warning : nil))
495
+ else
496
+ errors += 1
497
+ record("UNAVAILABLE (#{http_code}): #{uri}", :error)
498
+ end
499
+ rescue Exception => e
500
+ errors += 1
501
+ record("An exception occurred: #{e.message} while connecting to: #{uri}", :error)
502
+ end
503
+ end
504
+
505
+ return errors
506
+ end
507
+
508
+ def load_ruby_scripts
509
+ errors = 0
510
+
511
+ begin
512
+ scripts_path = File.join(@options[:configs],"scripts","ruby","")
513
+
514
+ #Load PreScript
515
+ pre_script = File.join(scripts_path,"pre.rb")
516
+ begin
517
+ require pre_script if File.exists? pre_script
518
+ rescue
519
+ record "Failed to load: #{pre_script}", :fatal
520
+ errors +=1
521
+ end
522
+
523
+ Dir.new(scripts_path).each { |script|
524
+ #Dont get hidden files or pre_,post_ scripts
525
+ unless script =~ /^\./i || script =~ /^post_/i || script =~ /^pre_/i || script =~ /^pre.rb/i || script =~ /^post.rb/i
526
+
527
+ #Require a file and its pre_, post_
528
+ [File.join(scripts_path,%{pre_#{script}}),
529
+ File.join(scripts_path,script),
530
+ File.join(scripts_path,%{post_#{script}})].each {|s|
531
+ begin
532
+ require s if File.exists? s
533
+ rescue
534
+ record "Failed to load: #{s}",:fatal
535
+ errors +=1
536
+ end
537
+ }
538
+
539
+ end
540
+ }
541
+
542
+ #Load PostScript
543
+ post_script = File.join(scripts_path,"post.rb")
544
+ begin
545
+ require post_script if File.exists? post_script
546
+ rescue
547
+ record "Failed to load: #{pre_script}", :fatal
548
+ errors +=1
549
+ end
550
+ rescue Exception => e
551
+ record e
552
+ record "Script directory not found, try running 'warning-shot --templates=PATH'", :warning
553
+ end
554
+
555
+ return errors
556
+ end
557
+
558
+ def test_ruby_scripts
559
+ errors = 0
560
+ #Execute #run on each child
561
+ TestScript.children.each do |test|
562
+ begin
563
+ result, message = test.run()
564
+
565
+ unless result
566
+ record %{#{test.class} test failed!},:error
567
+ record(%{\tMessage from #{test.class} test: #{message}}) unless message.nil?
568
+ errors += 1
569
+ else
570
+ record(%{#{test.class} test passed!},:info)
571
+ record(%{\tMessage from #{test.class} test: #{message}}) unless message.nil?
572
+ end
573
+ rescue Exception => e
574
+ record %{An error occured while processing: #{test.class}\n#{e}}, :fatal
575
+ errors += 1
576
+ end
577
+ end
578
+
579
+ return errors
580
+ end
581
+
582
+ end
583
+ end
584
+ end