warningshot 0.9.4 → 0.9.5

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