warningshot 0.9.4

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 (72) hide show
  1. data/CHANGELOG +0 -0
  2. data/CONTRIBUTORS +2 -0
  3. data/LICENSE +22 -0
  4. data/README +101 -0
  5. data/Rakefile +28 -0
  6. data/TODO +148 -0
  7. data/bin/warningshot +19 -0
  8. data/bin/ws-stage.bat +3 -0
  9. data/bin/ws-stage.sh +3 -0
  10. data/images/warning_shot.png +0 -0
  11. data/images/warning_shot_sml.png +0 -0
  12. data/images/warningshot_green.png +0 -0
  13. data/images/warningshot_red.png +0 -0
  14. data/lib/core_ext/hash.rb +14 -0
  15. data/lib/core_ext/kernel.rb +8 -0
  16. data/lib/core_ext/object.rb +7 -0
  17. data/lib/core_ext/string.rb +5 -0
  18. data/lib/resolvers/core_lib_resolver.rb +76 -0
  19. data/lib/resolvers/directory_resolver.rb +31 -0
  20. data/lib/resolvers/file_resolver.rb +87 -0
  21. data/lib/resolvers/gem_resolver.rb +94 -0
  22. data/lib/resolvers/integrity_resolver.rb +69 -0
  23. data/lib/resolvers/manual_resolver.rb +19 -0
  24. data/lib/resolvers/permission_resolver.rb +72 -0
  25. data/lib/resolvers/symlink_resolver.rb +43 -0
  26. data/lib/resolvers/url_resolver.rb +76 -0
  27. data/lib/warning_shot/config.rb +132 -0
  28. data/lib/warning_shot/dependency_resolver.rb +155 -0
  29. data/lib/warning_shot/growl.rb +14 -0
  30. data/lib/warning_shot/logger.rb +27 -0
  31. data/lib/warning_shot/resolver.rb +542 -0
  32. data/lib/warning_shot/template_generator.rb +28 -0
  33. data/lib/warning_shot/version.rb +7 -0
  34. data/lib/warning_shot/warning_shot.rb +130 -0
  35. data/lib/warningshot.rb +16 -0
  36. data/tasks/gemspec.rb +48 -0
  37. data/tasks/rpsec.rb +58 -0
  38. data/tasks/yard.rb +4 -0
  39. data/templates/binaries.yml +26 -0
  40. data/templates/core_libs.yml +18 -0
  41. data/templates/directories.yml +23 -0
  42. data/templates/files.yml +18 -0
  43. data/templates/gems.yml +26 -0
  44. data/templates/manual.yml +29 -0
  45. data/templates/mounts.yml +8 -0
  46. data/templates/permissions.yml +31 -0
  47. data/templates/symlinks.yml +30 -0
  48. data/templates/urls.yml +21 -0
  49. data/test/data/mock.yaml +16 -0
  50. data/test/data/mock.yml +10 -0
  51. data/test/data/mock_resolver.rb +16 -0
  52. data/test/data/permission_test.txt +1 -0
  53. data/test/data/resolvers/file/src/that.txt +1 -0
  54. data/test/log/warningshot.log +643 -0
  55. data/test/spec/spec.opts.zoiks +0 -0
  56. data/test/spec/spec_helper.rb +11 -0
  57. data/test/spec/unit/resolvers/core_lib_resolver_spec.rb +39 -0
  58. data/test/spec/unit/resolvers/directory_resolver_spec.rb +39 -0
  59. data/test/spec/unit/resolvers/file_resolver_spec.rb +134 -0
  60. data/test/spec/unit/resolvers/gem_resolver_spec.rb +74 -0
  61. data/test/spec/unit/resolvers/integrity_resolver_spec.rb +103 -0
  62. data/test/spec/unit/resolvers/manual_resolver_spec.rb +17 -0
  63. data/test/spec/unit/resolvers/permission_resolver_spec.rb +56 -0
  64. data/test/spec/unit/resolvers/symlink_resolver_spec.rb +44 -0
  65. data/test/spec/unit/resolvers/url_resolver_spec.rb +64 -0
  66. data/test/spec/unit/warning_shot/config_spec.rb +35 -0
  67. data/test/spec/unit/warning_shot/dependency_resolver_spec.rb +43 -0
  68. data/test/spec/unit/warning_shot/resolver_spec.rb +347 -0
  69. data/test/spec/unit/warning_shot/template_generator_spec.rb +21 -0
  70. data/test/spec/unit/warning_shot/version_spec.rb +7 -0
  71. data/test/spec/unit/warning_shot/warning_shot_spec.rb +3 -0
  72. metadata +143 -0
@@ -0,0 +1,69 @@
1
+ require 'digest/md5'
2
+ require 'digest/sha1'
3
+
4
+ class WarningShot::IntegrityResolver
5
+ include WarningShot::Resolver
6
+ order 600
7
+ #disable!
8
+
9
+ # Uses the same config files as file resolver, just add md5 field to config YML
10
+ branch :file
11
+ description 'Check file integrity via md5 or sha1 digest'
12
+
13
+ # Define FileResource struct
14
+ FileResource = Struct.new(:source,:target,:digest,:digest_method) do
15
+ def exists?;File.exists?(target.path);end;
16
+ end
17
+
18
+ cast String do |file|
19
+ FileResource.new URI.parse(''), URI.parse(file), nil, nil
20
+ end
21
+
22
+ cast Hash do |file|
23
+ file[:source].sub!(/file:\/\//i,'') unless file[:source].nil?
24
+
25
+ if file[:sha1] && file[:md5]
26
+ digest, digest_method = nil, nil
27
+ elsif file[:sha1]
28
+ digest, digest_method = file[:sha1], :sha1
29
+ elsif file[:md5]
30
+ digest, digest_method = file[:md5], :md5
31
+ end
32
+
33
+ FileResource.new URI.parse(file[:source] || ''), URI.parse(file[:target]), digest, digest_method
34
+ end
35
+
36
+ register(:test,{:name=>:sha1_digest,
37
+ :if => lambda{|dep| dep.digest_method == :sha1}
38
+ })do |dep|
39
+ dep_ok = (dep.exists? ? Digest::SHA1.hexdigest(File.read(dep.target.path)) == dep.digest : false)
40
+
41
+ if dep_ok
42
+ logger.debug " ~ [PASSED] checksum #{dep.target}"
43
+ else
44
+ logger.warn " ~ [FAILED] checksum #{dep.target}"
45
+ end
46
+
47
+ dep_ok
48
+ end
49
+
50
+ register(:test,{:name=>:md5_digest,
51
+ :if => lambda{|dep| dep.digest_method == :md5}
52
+ })do |dep|
53
+ dep_ok = (dep.exists? ? Digest::MD5.hexdigest(File.read(dep.target.path)) == dep.digest : false)
54
+
55
+ if dep_ok
56
+ logger.debug " ~ [PASSED] checksum #{dep.target}"
57
+ else
58
+ logger.warn " ~ [FAILED] checksum #{dep.target}"
59
+ end
60
+
61
+ dep_ok
62
+ end
63
+
64
+ register :test,{:name=>:no_digest,
65
+ :if => lambda{|dep| dep.digest_method == nil}
66
+ } do |dep|
67
+ true
68
+ end
69
+ end
@@ -0,0 +1,19 @@
1
+ class WarningShot::ManualResolver
2
+ include WarningShot::Resolver
3
+ order 10000
4
+ #disable!
5
+
6
+ branch :manual
7
+ description 'A glorified todo list of things that need to be resolved manually'
8
+
9
+ #Encapsulated in a struct so Resolver doesn't freak out when we instance_eval #met & #resolved
10
+ NoteResource = Struct.new(:msg)
11
+
12
+ cast do |note|
13
+ NoteResource.new(note)
14
+ end
15
+
16
+ register :test do |dep|
17
+ logger.info " ~ #{dep.msg}"
18
+ end
19
+ end
@@ -0,0 +1,72 @@
1
+ # TODO It would be really sweet if there was a way for FileResolver,
2
+ # DirectoryResolver, and SymlinkResolver inherited this functionality if
3
+ # mode, user, or group is set in its config file.
4
+ class WarningShot::PermissionResolver
5
+ include WarningShot::Resolver
6
+ order 100
7
+ branch :permission
8
+ description 'Validates mode, user, and group permission on files and directories'
9
+
10
+ module UnixPermissionsInterface;end;
11
+ module WindowsPermissionsInterface;end;
12
+
13
+ if WarningShot.platform != :windows
14
+ include WarningShot::PermissionResolver::UnixPermissionsInterface
15
+ #http://www.ruby-doc.org/core/classes/File/Stat.html
16
+ #http://www.ruby-doc.org/stdlib/libdoc/etc/rdoc/index.html
17
+ #http://www.ruby-doc.org/stdlib/libdoc/pathname/rdoc/index.html
18
+ #http://www.ruby-doc.org/stdlib/libdoc/fileutils/rdoc/index.html
19
+ #http://www.ruby-doc.org/core/classes/File.html#M002574
20
+ else
21
+ include WarningShot::PermissionResolver::WindowsPermissionsInterface
22
+ end
23
+
24
+ PermissionResource = Struct.new(:path,:target_mode,:target_user,:target_group,:recursive) do
25
+ def exists?
26
+ File.exist? self.path
27
+ end
28
+
29
+ def correct_owner?
30
+ false
31
+ end
32
+
33
+ def correct_group?
34
+ false
35
+ end
36
+
37
+ def correct_mode?
38
+ false
39
+ end
40
+ end
41
+
42
+ cast Hash do |yaml|
43
+ _path = yaml.delete(:path)
44
+ _mode = yaml.delete(:mode) || '0755'
45
+ _user = yaml.delete(:user) || 'nobody'
46
+ _group = yaml.delete(:group) || 'nobody'
47
+ _recursive = yaml.delete(:recursive) || 'none'
48
+
49
+ PermissionResource.new _path, _mode, _user, _group, _recursive
50
+ end
51
+
52
+ register :test do |resource|
53
+ _valid = resource.exists?
54
+
55
+ if _valid
56
+ _valid &= resource.correct_owner?
57
+ _valid &= resource.correct_group?
58
+ _valid &= resource.correct_mode?
59
+ end
60
+
61
+ if _valid
62
+ logger.debug " ~ [PASSED] permission: #{resource.path}"
63
+ else
64
+ logger.warn " ~ [FAILED] permission: #{resource.path}"
65
+ end
66
+
67
+ _valid
68
+ end
69
+
70
+ register :resolution do |resource|
71
+ end
72
+ end
@@ -0,0 +1,43 @@
1
+ class WarningShot::SymlinkResolver
2
+ include WarningShot::Resolver
3
+
4
+ order 50
5
+ branch :symlink
6
+ description 'Validates symlinks exist'
7
+
8
+ SymlinkResource = Struct.new(:source,:target,:force) do
9
+ def link!;FileUtils.ln_s(self.source,self.target,:force=>self.force);end;
10
+
11
+ def exists?
12
+ self.target ? File.symlink?(self.target) : false
13
+ end
14
+ end
15
+
16
+ cast String do |yaml|
17
+ SymlinkResource.new yaml, nil, false
18
+ end
19
+
20
+ cast Hash do |yaml|
21
+ use_force = yaml[:force].nil? ? true : yaml[:force]
22
+ SymlinkResource.new yaml[:source],yaml[:target], use_force
23
+ end
24
+
25
+ # If the target wasn't specified, it doesn't exist
26
+ register :test do |dep|
27
+ if symlink_found = dep.exists?
28
+ logger.debug " ~ [PASSED] symlink #{dep.target}"
29
+ else
30
+ logger.warn " ~ [FAILED] symlink #{dep.target}"
31
+ end
32
+ symlink_found
33
+ end
34
+
35
+ register :resolution do |dep|
36
+ begin
37
+ dep.link! if dep.target
38
+ rescue Errno::EEXIST, Errno::ENOTDIR => ex
39
+ logger.error " ~ Could not create symlink #{dep.source} => #{dep.target}"
40
+ end
41
+ dep.exists?
42
+ end
43
+ end
@@ -0,0 +1,76 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'net/https'
4
+
5
+ module WarningShot
6
+ class UrlResolver
7
+ include WarningShot::Resolver
8
+ order 900
9
+ #disable!
10
+
11
+ branch :url
12
+ description 'Validates that URLs are reachable.'
13
+
14
+ cli(
15
+ :long => "--strict",
16
+ :description => "Success is only for 200 instead of 2xx|3xx",
17
+ :name => "url_strict",
18
+ :default => false
19
+ )
20
+
21
+ cli(
22
+ :long => "--rootcert",
23
+ :description => "Path to root ca certificate",
24
+ :name => "root_ca",
25
+ :default => nil
26
+ )
27
+
28
+ cli(
29
+ :long => "--vdepth",
30
+ :description => "SSL Verify Peer Depth",
31
+ :name => "ssl_verify_depth",
32
+ :default => 5
33
+ )
34
+
35
+ UrlResource = Struct.new(:uri)
36
+ cast do |dep|
37
+ UrlResource.new URI.parse(dep)
38
+ end
39
+
40
+ register :test do |dep|
41
+ begin
42
+ http = Net::HTTP.new(dep.uri.host,dep.uri.port)
43
+
44
+ if dep.uri.scheme == 'https'
45
+ http.use_ssl = true
46
+
47
+ if WarningShot::Config.configuration[:root_ca] && File.exist?(WarningShot::Config.configuration[:root_ca])
48
+ http.ca_file = WarningShot::Config.configuration[:root_ca]
49
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
50
+ http.verify_depth = WarningShot::Config.configuration[:ssl_verify_depth]
51
+ else
52
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
53
+ end
54
+ end
55
+
56
+ dep.uri.path = '/' if dep.uri.path.empty?
57
+ resp = http.head(dep.uri.path)
58
+
59
+ valid_codes = WarningShot::Config.configuration[:url_strict] ? /200/ : /^[23][0-9][0-9]$/
60
+
61
+ page_found = (resp.code =~ valid_codes)
62
+
63
+ if page_found
64
+ logger.debug " ~ [PASSED] url #{dep.uri.to_s}"
65
+ else
66
+ logger.warn " ~ [FAILED] url #{dep.uri.to_s}"
67
+ end
68
+
69
+ page_found
70
+ rescue Exception
71
+ logger.error "Could not reach #{dep.uri.to_s}"
72
+ false
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,132 @@
1
+ # I pretty much goinked this from merb, you love merb, merb loves you.
2
+ # http://merbivore.com
3
+
4
+ module WarningShot
5
+ class Config
6
+
7
+ class << self
8
+ def defaults
9
+ @defaults ||= {
10
+ :environment => 'development',
11
+ :resolve => false,
12
+ :config_paths => ['.' / 'config' / 'warningshot', '~' / '.warningshot'],
13
+ :application => '.',
14
+ :log_path => '.' / 'log' / 'warningshot.log',
15
+ :log_level => :info,
16
+ :growl => false,
17
+ :verbose => false,
18
+ :colorize => true,
19
+ :resolvers => ['~' / '.warningshot' / '*.rb']
20
+ }
21
+ end
22
+
23
+ def use
24
+ @configuration ||= {}
25
+ yield @configuration
26
+ @configuration = defaults.merge(@configuration)
27
+ end
28
+
29
+ def [](key)
30
+ (@configuration||={})[key]
31
+ end
32
+
33
+ def []=(key,val)
34
+ (@configuration||={})[key] = val
35
+ #@configuration[key] = val
36
+ end
37
+
38
+ def setup(settings = {})
39
+ @configuration = defaults.merge(settings)
40
+ end
41
+
42
+ attr_accessor :configuration
43
+
44
+ def parse_args(argv = ARGV)
45
+ @configuration ||= {}
46
+ options = {}
47
+ options[:environment] = ENV["WARNING_SHOT_ENV"] if ENV["WARNING_SHOT_ENV"]
48
+
49
+ WarningShot.parser.banner = <<-BANNER
50
+ WarningShot v. #{WarningShot::VERSION}
51
+ Dependency Resolution Framework
52
+
53
+ Usage: warningshot [options]
54
+ BANNER
55
+ WarningShot.parser.separator '*'*80
56
+
57
+ WarningShot.parser.on("-e", "--environment=STRING", String, "Environment to test in","Default: #{defaults[:environment]}") do |env|
58
+ options[:environment] = env
59
+ end
60
+ WarningShot.parser.on("--resolve","Resolve missing dependencies (run as sudo)") do |resolve|
61
+ options[:resolve] = resolve
62
+ end
63
+ WarningShot.parser.on("-a","--app=PATH", String, "Path to application", "Default: #{defaults[:application]}") do |app|
64
+ options[:application] = app
65
+ end
66
+ WarningShot.parser.on("-c","--configs=PATH", String,"Path to config directories (':' seperated)","Default: #{defaults[:config_paths].join(':')}") do |config|
67
+ options[:config_paths] = config.split(':')
68
+ end
69
+ WarningShot.parser.on("-r","--resolvers=PATH", String,"Path to add'l resolvers (':' seperated)","Default: #{defaults[:resolvers].join(':')}") do |config|
70
+ options[:resolvers] = config.split(':')
71
+ end
72
+ WarningShot.parser.on("-t","--templates=PATH", String, "Generate template files", "Default: False") do |template_path|
73
+ template_path = options[:config_paths].first if template_path.nil? || template_path.empty?
74
+ WarningShot::TemplateGenerator.create(template_path)
75
+ exit
76
+ end
77
+ WarningShot.parser.on("-l","--log LOG", String, "Path to log file", "Default: #{defaults[:log_path]}") do |log_path|
78
+ options[:log_path] = log_path
79
+ end
80
+ WarningShot.parser.on("--loglevel [LEVEL]",[:debug, :info, :warn, :error, :fatal], "Default: #{defaults[:log_level]}") do |log_level|
81
+ options[:log_level] = log_level
82
+ end
83
+ WarningShot.parser.on("-g", "--growl", "Output results via growl (Requires growlnotify)") do |growl|
84
+ options[:growl] = growl
85
+ end
86
+ WarningShot.parser.on("-v", "--[no-]verbose", "Output verbose information") do |verbose|
87
+ options[:verbose] = verbose
88
+ end
89
+ WarningShot.parser.on("-p", "--[no-]prettycolors", "Colorize output") do |colorize|
90
+ options[:colorize] = colorize
91
+ end
92
+ WarningShot.parser.on_tail("--version", "Show version"){
93
+ WarningShot.parser.parse!(argv)
94
+ WarningShot::Config.setup(options)
95
+
96
+ WarningShot.load_app
97
+ WarningShot.load_addl_resolvers
98
+
99
+ puts "WarningShot v. #{WarningShot::VERSION}"
100
+ puts "Installed resolvers:"
101
+ Resolver.descendents.each { |klass|
102
+ puts "\n"
103
+ puts klass
104
+ puts " Tests: #{klass.tests.length}, Resolutions: #{klass.resolutions.length} [#{klass.resolutions.empty? ? 'irresolvable' : 'resolvable'}]"
105
+ puts " #{klass.description}"
106
+ puts " Command Line Options: #{klass.raw_cli_ext.inject([]){|m,c| m << c[:long]}.join(',')}" if klass.raw_cli_ext
107
+ }
108
+ exit
109
+ }
110
+ WarningShot.parser.on_tail("-h", "--help","Show this help message") { puts WarningShot.parser; exit }
111
+ WarningShot.parser.on_tail("--debugger","Enable debugging") do
112
+ begin
113
+ require "ruby-debug"
114
+ Debugger.start
115
+ Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
116
+ puts "Debugger enabled"
117
+ rescue LoadError => ex
118
+ puts "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
119
+ exit
120
+ end
121
+ end
122
+
123
+ WarningShot.parser.parse!(argv)
124
+ WarningShot::Config.setup(options)
125
+ rescue OptionParser::InvalidOption, OptionParser::InvalidArgument => op
126
+ puts op
127
+ puts WarningShot.parser #; exit;
128
+ end
129
+
130
+ end #End self
131
+ end #End Config
132
+ end#End WarningShot
@@ -0,0 +1,155 @@
1
+ module WarningShot
2
+ class DependencyResolver
3
+
4
+ attr_reader :environment, :dependency_tree, :resolvers
5
+ def initialize(config={})
6
+ @config = config
7
+ @environment = @config[:environment].to_sym
8
+ @dependency_tree = {}
9
+ @resolvers = []
10
+
11
+ init_logger
12
+
13
+ # Parsed yml files
14
+ self.load_configs
15
+ @dependency_tree.symbolize_keys!
16
+ end
17
+
18
+ # gets stats of all resolvers
19
+ # @return [Hash]
20
+ # :passed, :failed, :resolved, :unresolved
21
+ #
22
+ # @api public
23
+ def stats
24
+ _stats = {
25
+ :passed => 0, :failed => 0, :resolved => 0, :unresolved => 0
26
+ }
27
+
28
+ resolvers.each do |resolver|
29
+ _stats[:passed] += resolver.passed.size
30
+ _stats[:failed] += resolver.failed.size
31
+ _stats[:resolved] += resolver.resolved.size
32
+ _stats[:unresolved] += resolver.unresolved.size
33
+ end
34
+
35
+ _stats
36
+ end
37
+
38
+ # initializes the logger
39
+ #
40
+ # @api private
41
+ def init_logger
42
+ FileUtils.mkdir_p(File.dirname(File.expand_path(@config[:log_path]))) unless @config[:verbose]
43
+
44
+ @logger = Logger.new(
45
+ @config[:verbose] ? STDOUT : @config[:log_path], 10, 1024000
46
+ )
47
+ _log_level = (@config[:log_level] || :debug).to_s.upcase
48
+
49
+ _formatter = WarningShot::LoggerFormatter.new
50
+ _formatter.colorize = @config[:colorize]
51
+
52
+ @logger.formatter = _formatter
53
+ @logger.level = Object.class_eval("Logger::#{_log_level}")
54
+ end
55
+
56
+ # runs all loaded resolvers
57
+ #
58
+ # @api private
59
+ def run
60
+ @logger.info "WarningShot v. #{WarningShot::VERSION}"
61
+ @logger.info "Environment: #{WarningShot.environment}; Application: #{WarningShot.framework}"
62
+ @logger.info "On host: #{WarningShot.hostname}"
63
+
64
+ WarningShot::Resolver.descendents.each do |klass|
65
+ @logger.info "\n#{'-'*60}"
66
+
67
+ branch = @dependency_tree[klass.branch.to_sym]
68
+
69
+ if branch.nil?
70
+ @logger.info "No config file was found for branch #{klass.branch}"
71
+ next
72
+ end
73
+
74
+ klass.logger = @logger
75
+ resolver = klass.new(*branch)
76
+
77
+ @resolvers << resolver
78
+
79
+ @logger.info "#{resolver.class}; branch: #{klass.branch} [TESTING]"
80
+
81
+ # Start test
82
+ klass.before_filters(:test).each{|p| p.call}
83
+ resolver.test!
84
+ klass.after_filters(:test).each{|p| p.call}
85
+
86
+ @logger.info "Passed: #{resolver.passed.size} / Failed: #{resolver.failed.size}"
87
+
88
+ if WarningShot::Config.configuration[:resolve] && !klass.resolutions.empty?
89
+ @logger.info "#{resolver.class}; branch: #{klass.branch} [RESOLVING]"
90
+
91
+ klass.before_filters(:resolution).each{|p| p.call}
92
+ resolver.resolve!
93
+ klass.after_filters(:resolution).each{|p| p.call}
94
+
95
+ @logger.info "Resolved: #{resolver.resolved.size} / Unresolved: #{resolver.unresolved.size}"
96
+ end
97
+ end
98
+
99
+ @logger.info "\nResults:"
100
+ stats.each {|k,v| @logger.info(" ~ #{k}: \t#{v}")}
101
+ end
102
+
103
+ protected
104
+ # Loads configuration files
105
+ #
106
+ # @api protected
107
+ def load_configs
108
+ @config[:config_paths].each do |config_path|
109
+ #Parse the global/running env configs out of the YAML files.
110
+ Dir[config_path / WarningShot::ConfigExt].each do |config_file|
111
+ # Use WarningShot::ConfigExt & regexp on extension to make supporting add'l
112
+ # file types easier in the future
113
+ case File.extname(config_file)
114
+ when /.y(a)?ml/
115
+ parse_yml config_file
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ # parses dependencies info from a yaml file
122
+ #
123
+ # @param file [String]
124
+ # File path to parse
125
+ #
126
+ # @notes
127
+ # yaml file should contain an array of configs,
128
+ # get name of each config set, find global and current environment
129
+ # from set, merge into dependency_tree
130
+ #
131
+ # @api protected
132
+ def parse_yml(file)
133
+ #if only on branch is specified in a yaml file it may not come back as an array
134
+ branches = YAML::load(File.open(file,'r'))
135
+ branches = [branches] unless branches.is_a? Array
136
+
137
+ branches.each do |branch|
138
+ branch_name = branch[:branch]
139
+ dependency_tree[branch_name] ||= []
140
+
141
+ #Add current environment's configs to branch
142
+ current_env = branch[:environments][@environment]
143
+ @dependency_tree[branch_name].concat(current_env) unless current_env.nil?
144
+
145
+ #Add global environment's configs to branch
146
+ global = branch[:environments][:global]
147
+ @dependency_tree[branch_name].concat(global) unless global.nil?
148
+
149
+ #remove nil's if they made it into branch somehow (bad yaml probably)
150
+ @dependency_tree[branch_name].delete(nil)
151
+ end
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,14 @@
1
+ module WarningShot
2
+ class Growl
3
+
4
+ def Growl.say(msg)
5
+ img = WarningShot.dir_for(:images) / 'warning_shot_sml.png'
6
+
7
+ gmsg = %{growlnotify -t "WarningShot" -n "WarningShot" -m "#{msg}"}
8
+ gmsg += %{ --image #{img}} unless img.nil?
9
+
10
+ %x{#{gmsg}}
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,27 @@
1
+ module WarningShot
2
+ class LoggerFormatter < Logger::Formatter
3
+
4
+ ESCAPE_SEQ = {
5
+ "INFO" => "\e[37m%s\e[0m",
6
+ "WARN" => "\e[33m%s\e[0m",
7
+ "DEBUG" => "\e[34m%s\e[0m",
8
+ "ERROR" => "\e[31m%s\e[0m",
9
+ "FATAL" => "\e[1m%s\e[0m"
10
+ }
11
+
12
+ def call(severity, timestamp, progname, msg)
13
+ @colorize ? sprintf(ESCAPE_SEQ[severity],"#{msg}\n") : "#{msg}\n"
14
+ end
15
+
16
+ def time_format=(fmt)
17
+ @time_format = fmt
18
+ end
19
+
20
+ def colorize=(color)
21
+ @colorize = color
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+