warningshot 0.9.4 → 0.9.5

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 (51) hide show
  1. data/CHANGELOG +8 -0
  2. data/CONTRIBUTORS +2 -1
  3. data/README +86 -6
  4. data/Rakefile +4 -3
  5. data/TODO +1 -147
  6. data/bin/warningshot +11 -7
  7. data/lib/resolvers/core_lib_resolver.rb +2 -3
  8. data/lib/resolvers/directory_resolver.rb +1 -1
  9. data/lib/resolvers/file_resolver.rb +35 -17
  10. data/lib/resolvers/gem_resolver.rb +81 -60
  11. data/lib/resolvers/integrity_resolver.rb +10 -11
  12. data/lib/resolvers/manual_resolver.rb +15 -3
  13. data/lib/resolvers/permission_resolver.rb +6 -8
  14. data/lib/resolvers/symlink_resolver.rb +13 -8
  15. data/lib/resolvers/url_resolver.rb +28 -41
  16. data/lib/warningshot.rb +10 -7
  17. data/lib/warningshot/config.rb +254 -0
  18. data/lib/{warning_shot → warningshot}/dependency_resolver.rb +38 -17
  19. data/lib/{warning_shot → warningshot}/growl.rb +2 -0
  20. data/lib/{warning_shot → warningshot}/logger.rb +2 -0
  21. data/lib/{warning_shot → warningshot}/resolver.rb +177 -89
  22. data/lib/warningshot/suite.rb +4 -0
  23. data/lib/{warning_shot → warningshot}/template_generator.rb +4 -1
  24. data/lib/{warning_shot → warningshot}/version.rb +3 -1
  25. data/lib/warningshot/warning_shot.rb +187 -0
  26. data/tasks/gemspec.rb +3 -16
  27. data/tasks/yard.rb +1 -1
  28. data/templates/gems.yml +1 -0
  29. data/test/data/faux_test.yml +5 -0
  30. data/test/data/faux_test_resolver.rb +21 -0
  31. data/test/data/mock_resolver.rb +11 -5
  32. data/test/log/warningshot.log +3051 -532
  33. data/test/spec/unit/resolvers/core_lib_resolver_spec.rb +1 -1
  34. data/test/spec/unit/resolvers/directory_resolver_spec.rb +1 -1
  35. data/test/spec/unit/resolvers/file_resolver_spec.rb +9 -13
  36. data/test/spec/unit/resolvers/gem_resolver_spec.rb +108 -32
  37. data/test/spec/unit/resolvers/integrity_resolver_spec.rb +6 -6
  38. data/test/spec/unit/resolvers/permission_resolver_spec.rb +2 -2
  39. data/test/spec/unit/resolvers/symlink_resolver_spec.rb +8 -1
  40. data/test/spec/unit/resolvers/url_resolver_spec.rb +10 -10
  41. data/test/spec/unit/warningshot/config_spec.rb +57 -0
  42. data/test/spec/unit/{warning_shot → warningshot}/dependency_resolver_spec.rb +18 -9
  43. data/test/spec/unit/{warning_shot → warningshot}/resolver_spec.rb +54 -79
  44. data/test/spec/unit/{warning_shot → warningshot}/template_generator_spec.rb +1 -1
  45. data/test/spec/unit/{warning_shot → warningshot}/version_spec.rb +0 -0
  46. data/test/spec/unit/{warning_shot → warningshot}/warning_shot_spec.rb +0 -0
  47. metadata +24 -26
  48. data/lib/warning_shot/config.rb +0 -132
  49. data/lib/warning_shot/warning_shot.rb +0 -130
  50. data/test/spec/spec.opts.zoiks +0 -0
  51. data/test/spec/unit/warning_shot/config_spec.rb +0 -35
@@ -1,58 +1,77 @@
1
- require 'rubygems/dependency_installer'
2
1
  class WarningShot::GemResolver
3
2
  include WarningShot::Resolver
3
+ add_dependency :core, 'rubygems'
4
+ add_dependency :core, 'rubygems/dependency_installer'
5
+ add_dependency :core, 'rubygems/uninstaller'
6
+ add_dependency :core, 'rubygems/dependency'
4
7
 
5
8
  order 100
6
9
  branch :gem
7
10
  description 'Installs ruby gems and their dependencies'
8
-
9
- # Matches >, <, >=, <=
10
- CONDITIONAL_RGX = /[^\d]*/.freeze
11
-
12
- # Matches digits in version
13
- VERSION_RGX = /[\d\.]+/.freeze
14
-
11
+
15
12
  # Default version to install
16
- DEFAULT_VERSION = ">=0.0.0".freeze
17
-
18
- cli(
19
- :long => "--gempath",
20
- :description => "Alternate gem path ':' separated to check. First in path is where gems will be installed",
21
- :name => "gem_path",
22
- :default => nil
23
- )
13
+ DEFAULT_VERSION = ">= 0.0.0".freeze
14
+
15
+ cli("--gempath=PATH", String, "Alternate gem path ':' separated to check. First in path is where gems will be installed") do |gpath|
16
+ options[:gem_path] = gpath
17
+ end
18
+
19
+ cli("--update-sources","Update gem sources before installing") do |no_up_src|
20
+ options[:update_sources] = no_up_src
21
+ end
22
+
23
+ #cli("-m","--resolver-gems=GEMS", String,"Names of gems containing add'l resolvers (':' seperated)") do |resolver_gems|
24
+ # options[:resolver_gems] = resolver_gems.split(':')
25
+ #end
26
+
27
+ GemResource = Struct.new(:name,:version,:source) do
28
+ def installed?
29
+ return !!(Gem.source_index.find_name(self.name, self.version).first)
30
+ end
24
31
 
25
- cli(
26
- :long => "--minigems",
27
- :description => "Not supported yet.",
28
- :name => "minigems",
29
- :default => false
30
- )
31
-
32
- GemResource = Struct.new(:name,:version) do
33
- def installed?
34
- self.version ||= DEFAULT_VERSION
35
- installed_versions = Gem::cache.search self.name
36
- installed = false
32
+ def install!
33
+ orig_gem_sources = Gem.sources.clone
37
34
 
38
- required_version = Gem::Requirement.new self.version
35
+ installer = Gem::DependencyInstaller.new({
36
+ :user_install => false,
37
+ :install_dir => Gem.path.first
38
+ })
39
39
 
40
- installed_versions.each do |i_gem|
41
- installed = case(required_version <=> Gem::Requirement.new(i_gem.version))
42
- when 1,0
43
- true
44
- else
45
- false
46
- end
47
-
48
- break if installed
40
+ begin
41
+ Gem.sources.replace(self.source.kind_of?(Array) ? self.source : [self.source]) if self.source
42
+ installer.install(self.name,self.version)
43
+ rescue Gem::InstallError => ex
44
+ WarningShot::GemResolver.logger.error " ~ Could not install gem: #{self.name}:#{self.version}%s" % [self.source ? " from #{self.source}" : ""]
45
+ rescue Gem::GemNotFoundException => ex
46
+ WarningShot::GemResolver.logger.error " ~ Gem (#{self.name}:#{self.version}) was not found%s" % [self.source ? " from #{self.source}" : ""]
47
+ ensure
48
+ Gem.sources.replace orig_gem_sources # replace our gem sources
49
49
  end
50
- installed
50
+
51
+ !installer.installed_gems.empty?
52
+ end
53
+
54
+ def uninstall!
55
+ opts = {
56
+ :user_install => false,
57
+ :install_dir => Gem.path.first,
58
+ :version => self.version
59
+ }
60
+ WarningShot::GemResolver.update_source_index(opts[:install_dir])
61
+ Gem::Uninstaller.new(self.name, opts).uninstall rescue false
51
62
  end
52
63
  end #End GemResource
53
64
 
54
- cast(String){ |yaml| GemResource.new(yaml,DEFAULT_VERSION) }
55
- cast(Hash){ |yaml| GemResource.new yaml[:name], yaml[:version] }
65
+ typecast(String){ |yaml|
66
+ _ver = Gem::Requirement.new [DEFAULT_VERSION]
67
+ GemResource.new yaml, _ver
68
+ }
69
+
70
+ typecast(Hash){ |yaml|
71
+ _ver = (yaml[:version].nil? || yaml[:version].empty?) ? DEFAULT_VERSION : yaml[:version]
72
+ _ver = Gem::Requirement.new [_ver]
73
+ GemResource.new yaml[:name], _ver, yaml[:source]
74
+ }
56
75
 
57
76
  register :test do |dep|
58
77
  if gem_found = dep.installed?
@@ -64,31 +83,33 @@ class WarningShot::GemResolver
64
83
  end
65
84
 
66
85
  register :resolution do |dep|
67
- begin
68
- dep_inst = Gem::DependencyInstaller.new({:install_dir => Gem.path.first})
69
- dep_inst.install(dep.name,Gem::Requirement.new(dep.version))
70
- rescue Exception => ex
71
- logger.error " ~ Could not install gem: #{dep.name}:#{dep.version}"
72
- end
73
- dep.installed?
86
+ dep.install!
74
87
  end
75
88
 
76
89
  class << self
77
- # loads gem paths from WarningShot::Config
78
- def load_paths
79
- if WarningShot::Config.configuration.key?(:gem_path) && !WarningShot::Config.configuration[:gem_path].nil?
80
- WarningShot::Config.configuration[:gem_path].split(":").reverse.each do |path|
81
- Gem.path.unshift path
82
- end
83
-
84
- Gem::cache.class.from_gems_in WarningShot::Config.configuration[:gem_path].split(":")
85
- Gem::cache.refresh!
86
- end
90
+ def update_source_index(*dirs)
91
+ spec_dirs = dirs.inject([]){|memo,dir|
92
+ memo << File.join(File.expand_path(dir), 'specifications')
93
+ }
94
+
95
+ Gem.send :class_variable_set, "@@source_index", Gem::SourceIndex.from_gems_in(*spec_dirs)
96
+ Gem::cache.refresh!
87
97
  end
88
98
  end
89
99
 
90
- def initialize(*params)
100
+ def initialize(config,*params)
91
101
  super
92
- WarningShot::GemResolver.load_paths
102
+
103
+ Gem.configuration.update_sources = !!(self.config[:update_sources])
104
+
105
+ if self.config.key?(:gem_path) && !self.config[:gem_path].nil?
106
+ gem_dirs = self.config[:gem_path].split(':')
107
+ gem_dirs.reverse.each do |path|
108
+ Gem.path.unshift File.expand_path(path)
109
+ end
110
+
111
+ WarningShot::GemResolver.update_source_index *gem_dirs
112
+ end
93
113
  end
114
+
94
115
  end
@@ -1,10 +1,9 @@
1
- require 'digest/md5'
2
- require 'digest/sha1'
3
-
4
1
  class WarningShot::IntegrityResolver
5
2
  include WarningShot::Resolver
3
+ add_dependency :core, 'digest/md5', :disable => false, :unregister => [:md5_digest_test]
4
+ add_dependency :core, 'digest/sha1', :disable => false, :unregister => [:sha1_digest_test]
5
+
6
6
  order 600
7
- #disable!
8
7
 
9
8
  # Uses the same config files as file resolver, just add md5 field to config YML
10
9
  branch :file
@@ -12,14 +11,14 @@ class WarningShot::IntegrityResolver
12
11
 
13
12
  # Define FileResource struct
14
13
  FileResource = Struct.new(:source,:target,:digest,:digest_method) do
15
- def exists?;File.exists?(target.path);end;
14
+ def exists?;File.exists?(File.expand_path(target.path));end;
16
15
  end
17
16
 
18
- cast String do |file|
17
+ typecast String do |file|
19
18
  FileResource.new URI.parse(''), URI.parse(file), nil, nil
20
19
  end
21
20
 
22
- cast Hash do |file|
21
+ typecast Hash do |file|
23
22
  file[:source].sub!(/file:\/\//i,'') unless file[:source].nil?
24
23
 
25
24
  if file[:sha1] && file[:md5]
@@ -33,10 +32,10 @@ class WarningShot::IntegrityResolver
33
32
  FileResource.new URI.parse(file[:source] || ''), URI.parse(file[:target]), digest, digest_method
34
33
  end
35
34
 
36
- register(:test,{:name=>:sha1_digest,
35
+ register(:test,{:name=>:sha1_digest_test,
37
36
  :if => lambda{|dep| dep.digest_method == :sha1}
38
37
  })do |dep|
39
- dep_ok = (dep.exists? ? Digest::SHA1.hexdigest(File.read(dep.target.path)) == dep.digest : false)
38
+ dep_ok = (dep.exists? ? Digest::SHA1.hexdigest(File.read(File.expand_path(dep.target.path))) == dep.digest : false)
40
39
 
41
40
  if dep_ok
42
41
  logger.debug " ~ [PASSED] checksum #{dep.target}"
@@ -47,10 +46,10 @@ class WarningShot::IntegrityResolver
47
46
  dep_ok
48
47
  end
49
48
 
50
- register(:test,{:name=>:md5_digest,
49
+ register(:test,{:name=>:md5_digest_test,
51
50
  :if => lambda{|dep| dep.digest_method == :md5}
52
51
  })do |dep|
53
- dep_ok = (dep.exists? ? Digest::MD5.hexdigest(File.read(dep.target.path)) == dep.digest : false)
52
+ dep_ok = (dep.exists? ? Digest::MD5.hexdigest(File.read(File.expand_path(dep.target.path))) == dep.digest : false)
54
53
 
55
54
  if dep_ok
56
55
  logger.debug " ~ [PASSED] checksum #{dep.target}"
@@ -1,15 +1,27 @@
1
1
  class WarningShot::ManualResolver
2
2
  include WarningShot::Resolver
3
3
  order 10000
4
- #disable!
5
-
6
4
  branch :manual
5
+
7
6
  description 'A glorified todo list of things that need to be resolved manually'
8
7
 
8
+ cli("--notes", "List all the notes in the manual branch") do |val|
9
+ WarningShot::Resolver.descendants.each{|d| d.disable!}
10
+ self.enable!
11
+
12
+ config = WarningShot::Config.parse_args
13
+ config[:verbose] = true
14
+
15
+ dr = WarningShot::DependencyResolver.new(config)
16
+ dr.dependency_tree[:manual].each { |note| puts "~ #{note}" }
17
+
18
+ exit
19
+ end
20
+
9
21
  #Encapsulated in a struct so Resolver doesn't freak out when we instance_eval #met & #resolved
10
22
  NoteResource = Struct.new(:msg)
11
23
 
12
- cast do |note|
24
+ typecast do |note|
13
25
  NoteResource.new(note)
14
26
  end
15
27
 
@@ -39,14 +39,12 @@ class WarningShot::PermissionResolver
39
39
  end
40
40
  end
41
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
42
+ typecast Hash do |yaml|
43
+ PermissionResource.new yaml.delete(:path),
44
+ yaml.delete(:mode) || '0755',
45
+ yaml.delete(:user) || 'nobody',
46
+ yaml.delete(:group) || 'nobody',
47
+ yaml.delete(:recursive) || 'none'
50
48
  end
51
49
 
52
50
  register :test do |resource|
@@ -1,5 +1,6 @@
1
1
  class WarningShot::SymlinkResolver
2
2
  include WarningShot::Resolver
3
+ add_dependency :core, 'fileutils'
3
4
 
4
5
  order 50
5
6
  branch :symlink
@@ -11,25 +12,29 @@ class WarningShot::SymlinkResolver
11
12
  def exists?
12
13
  self.target ? File.symlink?(self.target) : false
13
14
  end
15
+
16
+ # Determines if link points at correct file
17
+ def correct?
18
+ File.identical? self.source, self.target
19
+ end
20
+
14
21
  end
15
22
 
16
- cast String do |yaml|
17
- SymlinkResource.new yaml, nil, false
18
- end
19
-
20
- cast Hash do |yaml|
23
+ typecast do |yaml|
21
24
  use_force = yaml[:force].nil? ? true : yaml[:force]
22
- SymlinkResource.new yaml[:source],yaml[:target], use_force
25
+ _src = File.expand_path yaml[:source]
26
+ _trg = File.expand_path yaml[:target]
27
+ SymlinkResource.new _src, _trg, use_force
23
28
  end
24
29
 
25
30
  # If the target wasn't specified, it doesn't exist
26
31
  register :test do |dep|
27
- if symlink_found = dep.exists?
32
+ if symlink_correct = dep.exists? && dep.correct?
28
33
  logger.debug " ~ [PASSED] symlink #{dep.target}"
29
34
  else
30
35
  logger.warn " ~ [FAILED] symlink #{dep.target}"
31
36
  end
32
- symlink_found
37
+ symlink_correct
33
38
  end
34
39
 
35
40
  register :resolution do |dep|
@@ -1,74 +1,61 @@
1
- require 'uri'
2
- require 'net/http'
3
- require 'net/https'
4
-
5
1
  module WarningShot
6
2
  class UrlResolver
7
3
  include WarningShot::Resolver
4
+ add_dependency :core, 'uri'
5
+ add_dependency :core, 'net/http'
6
+ add_dependency :core, 'net/https'
7
+
8
8
  order 900
9
- #disable!
10
9
 
11
10
  branch :url
12
11
  description 'Validates that URLs are reachable.'
13
12
 
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
- )
13
+ cli("--strict", "Success is only for 200 instead of 2xx|3xx") do |val|
14
+ options[:url_strict] = val
15
+ end
27
16
 
28
- cli(
29
- :long => "--vdepth",
30
- :description => "SSL Verify Peer Depth",
31
- :name => "ssl_verify_depth",
32
- :default => 5
33
- )
17
+ cli("--rootcert", "Path to root ca certificate") do |val|
18
+ options[:root_ca] = val
19
+ end
34
20
 
35
- UrlResource = Struct.new(:uri)
36
- cast do |dep|
37
- UrlResource.new URI.parse(dep)
21
+ cli("--vdepth", "SSL Verify Peer Depth") do |val|
22
+ options[:ssl_verify_depth] = val
38
23
  end
24
+
25
+ typecast{ |dep| URI.parse(dep) }
39
26
 
40
- register :test do |dep|
27
+ register :test do |uri,config|
41
28
  begin
42
- http = Net::HTTP.new(dep.uri.host,dep.uri.port)
29
+ http = Net::HTTP.new(uri.host,uri.port)
43
30
 
44
- if dep.uri.scheme == 'https'
31
+ if uri.scheme == 'https'
45
32
  http.use_ssl = true
46
33
 
47
- if WarningShot::Config.configuration[:root_ca] && File.exist?(WarningShot::Config.configuration[:root_ca])
48
- http.ca_file = WarningShot::Config.configuration[:root_ca]
34
+ if config[:root_ca] && File.exist?(config[:root_ca])
35
+ http.ca_file = config[:root_ca]
49
36
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
50
- http.verify_depth = WarningShot::Config.configuration[:ssl_verify_depth]
37
+ http.verify_depth = config[:ssl_verify_depth]
51
38
  else
52
39
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
53
40
  end
54
41
  end
55
42
 
56
- dep.uri.path = '/' if dep.uri.path.empty?
57
- resp = http.head(dep.uri.path)
43
+ uri.path = '/' if uri.path.empty?
44
+ resp = http.head(uri.path)
58
45
 
59
- valid_codes = WarningShot::Config.configuration[:url_strict] ? /200/ : /^[23][0-9][0-9]$/
46
+ valid_codes = config[:url_strict] ? /200/ : /^[23][0-9][0-9]$/
60
47
 
61
48
  page_found = (resp.code =~ valid_codes)
62
-
49
+
63
50
  if page_found
64
- logger.debug " ~ [PASSED] url #{dep.uri.to_s}"
51
+ logger.debug " ~ [PASSED] url #{uri.to_s}"
65
52
  else
66
- logger.warn " ~ [FAILED] url #{dep.uri.to_s}"
53
+ logger.warn " ~ [FAILED] url #{uri.to_s}"
67
54
  end
68
55
 
69
56
  page_found
70
- rescue Exception
71
- logger.error "Could not reach #{dep.uri.to_s}"
57
+ rescue Exception => ex
58
+ logger.error "Could not reach #{uri.to_s}"
72
59
  false
73
60
  end
74
61
  end
@@ -1,16 +1,19 @@
1
- require 'rubygems'
2
1
  require 'fileutils'
3
2
  require 'yaml'
4
- require 'optparse'
5
3
  require 'logger'
6
4
  require 'set'
7
5
  require 'rbconfig'
6
+ require 'optparse'
8
7
 
9
8
  # Load core extensions
10
- Dir.glob(File.join(File.dirname(__FILE__), "core_ext", "**", "*.rb")).each {|f| require f}
9
+ Dir.glob(File.join(File.dirname(__FILE__), 'core_ext', '**', '*.rb')).each {|f| require f}
11
10
 
12
11
  # Load WarningShot
13
- Dir.glob(File.dirname(__FILE__) / "warning_shot" / "**" / "*.rb").each {|f| require f}
14
-
15
- # Load resolvers
16
- Dir.glob(File.dirname(__FILE__) / "resolvers" / "**" / "*.rb").each {|f| require f}
12
+ require File.dirname(__FILE__) / 'warningshot' / 'warning_shot'
13
+ require File.dirname(__FILE__) / 'warningshot' / 'version'
14
+ require File.dirname(__FILE__) / 'warningshot' / 'config'
15
+ require File.dirname(__FILE__) / 'warningshot' / 'logger'
16
+ require File.dirname(__FILE__) / 'warningshot' / 'resolver'
17
+ require File.dirname(__FILE__) / 'warningshot' / 'dependency_resolver'
18
+ require File.dirname(__FILE__) / 'warningshot' / 'growl'
19
+ require File.dirname(__FILE__) / 'warningshot' / 'template_generator'