warning-shot 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
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