right_scraper 1.0.26 → 3.0.0

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 (92) hide show
  1. data/Gemfile +16 -0
  2. data/README.rdoc +9 -28
  3. data/Rakefile +51 -39
  4. data/lib/right_scraper/builders/base.rb +64 -0
  5. data/lib/right_scraper/builders/filesystem.rb +96 -0
  6. data/lib/right_scraper/builders/union.rb +57 -0
  7. data/lib/right_scraper/logger.rb +102 -0
  8. data/lib/right_scraper/loggers/noisy.rb +85 -0
  9. data/lib/right_scraper/processes/ssh.rb +188 -0
  10. data/lib/right_scraper/repositories/base.rb +299 -0
  11. data/lib/right_scraper/repositories/download.rb +90 -0
  12. data/lib/right_scraper/repositories/git.rb +92 -0
  13. data/lib/right_scraper/repositories/mock.rb +70 -0
  14. data/lib/right_scraper/repositories/svn.rb +96 -0
  15. data/lib/right_scraper/resources/base.rb +70 -0
  16. data/{spec/scraper_base_spec.rb → lib/right_scraper/resources/cookbook.rb} +9 -23
  17. data/lib/right_scraper/resources/workflow.rb +55 -0
  18. data/lib/right_scraper/retrievers/base.rb +114 -0
  19. data/lib/right_scraper/retrievers/checkout.rb +79 -0
  20. data/lib/right_scraper/retrievers/download.rb +97 -0
  21. data/lib/right_scraper/retrievers/git.rb +140 -0
  22. data/lib/right_scraper/retrievers/svn.rb +87 -0
  23. data/lib/right_scraper/scanners/base.rb +111 -0
  24. data/lib/right_scraper/scanners/cookbook_manifest.rb +59 -0
  25. data/lib/right_scraper/scanners/cookbook_metadata.rb +69 -0
  26. data/lib/right_scraper/scanners/cookbook_s3_upload.rb +84 -0
  27. data/lib/right_scraper/scanners/union.rb +89 -0
  28. data/lib/right_scraper/scanners/workflow_manifest.rb +86 -0
  29. data/lib/right_scraper/scanners/workflow_metadata.rb +70 -0
  30. data/lib/right_scraper/scanners/workflow_s3_upload.rb +85 -0
  31. data/lib/right_scraper/scraper.rb +81 -57
  32. data/lib/right_scraper/scraper_logger.rb +61 -0
  33. data/lib/right_scraper/scrapers/base.rb +262 -0
  34. data/lib/right_scraper/scrapers/cookbook.rb +73 -0
  35. data/lib/right_scraper/scrapers/workflow.rb +88 -0
  36. data/lib/right_scraper/svn_client.rb +101 -0
  37. data/lib/right_scraper/version.rb +28 -0
  38. data/lib/right_scraper.rb +35 -11
  39. data/right_scraper.gemspec +26 -13
  40. data/right_scraper.rconf +13 -0
  41. data/spec/builder_spec.rb +50 -0
  42. data/spec/cookbook_helper.rb +73 -0
  43. data/spec/cookbook_manifest_spec.rb +55 -0
  44. data/spec/cookbook_s3_upload_spec.rb +152 -0
  45. data/spec/download/download_retriever_spec.rb +118 -0
  46. data/spec/download/download_retriever_spec_helper.rb +72 -0
  47. data/spec/download/download_spec.rb +130 -0
  48. data/spec/download/multi_dir_spec.rb +106 -0
  49. data/spec/download/multi_dir_spec_helper.rb +40 -0
  50. data/spec/git/cookbook_spec.rb +166 -0
  51. data/spec/git/demokey +27 -0
  52. data/spec/git/demokey.pub +1 -0
  53. data/spec/git/password_key +30 -0
  54. data/spec/git/password_key.pub +1 -0
  55. data/spec/git/repository_spec.rb +110 -0
  56. data/spec/git/retriever_spec.rb +505 -0
  57. data/spec/git/retriever_spec_helper.rb +112 -0
  58. data/spec/git/scraper_spec.rb +136 -0
  59. data/spec/git/ssh_spec.rb +170 -0
  60. data/spec/git/url_spec.rb +103 -0
  61. data/spec/logger_spec.rb +185 -0
  62. data/spec/repository_spec.rb +89 -23
  63. data/spec/{scraper_spec_helper_base.rb → retriever_spec_helper.rb} +41 -27
  64. data/spec/scanner_spec.rb +61 -0
  65. data/spec/scraper_helper.rb +96 -0
  66. data/spec/scraper_spec.rb +123 -45
  67. data/spec/spec_helper.rb +87 -14
  68. data/spec/svn/cookbook_spec.rb +97 -0
  69. data/spec/svn/multi_svn_spec.rb +64 -0
  70. data/spec/svn/multi_svn_spec_helper.rb +40 -0
  71. data/spec/svn/repository_spec.rb +72 -0
  72. data/spec/svn/retriever_spec.rb +261 -0
  73. data/spec/svn/scraper_spec.rb +90 -0
  74. data/spec/svn/{svn_scraper_spec_helper.rb → svn_retriever_spec_helper.rb} +46 -27
  75. data/spec/svn/url_spec.rb +47 -0
  76. data/spec/url_spec.rb +164 -0
  77. metadata +203 -31
  78. data/lib/right_scraper/linux/process_monitor.rb +0 -84
  79. data/lib/right_scraper/repository.rb +0 -78
  80. data/lib/right_scraper/scraper_base.rb +0 -175
  81. data/lib/right_scraper/scrapers/download_scraper.rb +0 -67
  82. data/lib/right_scraper/scrapers/git_scraper.rb +0 -283
  83. data/lib/right_scraper/scrapers/svn_scraper.rb +0 -119
  84. data/lib/right_scraper/watcher.rb +0 -158
  85. data/lib/right_scraper/win32/process_monitor.rb +0 -98
  86. data/spec/download/download_scraper_spec.rb +0 -94
  87. data/spec/git/git_scraper_spec.rb +0 -165
  88. data/spec/git/git_scraper_spec_helper.rb +0 -72
  89. data/spec/rcov.opts +0 -1
  90. data/spec/spec.opts +0 -2
  91. data/spec/svn/svn_scraper_spec.rb +0 -148
  92. data/spec/watcher_spec.rb +0 -74
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "json", "~> 1.4.5"
4
+ gem "blackwinter-git", "~> 1.2.7"
5
+ gem "libarchive", "~> 0.1.2"
6
+ gem "right_aws", "~> 2.0"
7
+ gem "process_watcher", "~> 0.3"
8
+
9
+ group :development do
10
+ gem "rspec", "~> 2.3"
11
+ gem "rake"
12
+ gem "flexmock"
13
+ gem "ruby-debug", :platform=>"ruby_18"
14
+ gem "ruby-debug19", :platform=>"ruby_19"
15
+ gem "rdoc", "~> 2.4"
16
+ end
data/README.rdoc CHANGED
@@ -4,24 +4,11 @@
4
4
 
5
5
  === Synopsis
6
6
 
7
- RightScraper provides a simple interface to download and keep repositories up-to-date
8
- using various protocols.
9
-
10
- The supported protocols include:
11
- - *git*: RightScraper will clone then pull repos from git
12
- - *SVN*: RightScraper will checkout then update SVN repositories
13
- - *tarballs*: Includes uncompressed (.tar), gzip (.tgz, .gzip) and bzip (.bzip, .bzip2) tar files.
14
-
15
- The scraper first inspects the local directory to see if the repo has already been scraped
16
- and if so runs some basic checks before it tries to update it. Incremental updates are not
17
- supported with tar files.
18
-
19
- === Rationale
20
-
21
- The idea is to have many repos that need to be downloaded/kept up-to-date in a central
22
- place. Point the scraper to this central place and it will take care of creating unique
23
- local directories for each remote repository and keep that mapping to download changes
24
- incrementally upon request.
7
+ RightScraper provides a simple interface to download and keep repositories up-to-date
8
+ using various protocols. It has been decomposed into various modules so that you
9
+ may specify only the functionality (and required libraries and gems) you require.
10
+ This gem depends on all available RightScraper modules, enabling full support at the
11
+ cost of requiring some systems administration work external to Ruby.
25
12
 
26
13
  == USAGE
27
14
 
@@ -30,22 +17,16 @@ incrementally upon request.
30
17
  require 'rubygems'
31
18
  require 'right_scraper'
32
19
 
33
- scraper = RightScale::Scraper.new('/tmp')
20
+ scraper = RightScale::Scraper.new(:basedir => '/tmp', :kind => :cookbook)
34
21
  scraper.scrape(:type => :git, :url => 'git://github.com/rightscale/right_scraper.git')
35
22
 
36
23
  == INSTALLATION
37
24
 
38
- RightScraper can be installed by entering the following at the command prompt:
25
+ This module for RightScraper can be installed by entering the following at the command
26
+ prompt:
39
27
 
40
28
  gem install right_scraper
41
29
 
42
- == DEPENDENCIES
43
-
44
- RightScraper relies on the following tools:
45
- - git
46
- - svn
47
- - curl
48
-
49
30
  == TESTING
50
31
 
51
32
  Install the following RubyGems required for testing:
@@ -59,7 +40,7 @@ The build can be tested using the RSpec gem.
59
40
 
60
41
  <b>RightScraper</b>
61
42
 
62
- Copyright:: Copyright (c) 2010 RightScale, Inc.
43
+ Copyright:: Copyright (c) 2010 RightScale, Inc.
63
44
 
64
45
  Permission is hereby granted, free of charge, to any person obtaining
65
46
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -1,18 +1,18 @@
1
- #--
2
- # Copyright: Copyright (c) 2010 RightScale, Inc.
1
+ #-- -*-ruby-*-
2
+ # Copyright: Copyright (c) 2010-2011 RightScale, Inc.
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
6
6
  # 'Software'), to deal in the Software without restriction, including
7
7
  # without limitation the rights to use, copy, modify, merge, publish,
8
- # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
9
  # permit persons to whom the Software is furnished to do so, subject to
10
10
  # the following conditions:
11
11
  #
12
12
  # The above copyright notice and this permission notice shall be
13
13
  # included in all copies or substantial portions of the Software.
14
14
  #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
16
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
17
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
18
  # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
@@ -22,56 +22,68 @@
22
22
  #++
23
23
 
24
24
  require 'rubygems'
25
+ require 'rubygems/package_task'
26
+ require 'bundler/setup'
27
+
25
28
  require 'fileutils'
26
29
  require 'rake'
27
- require 'spec/rake/spectask'
30
+ require 'rspec/core/rake_task'
31
+ require 'rdoc/task'
32
+ require 'rake/clean'
28
33
 
29
34
  task :default => 'spec'
30
35
 
36
+ # == Gem packaging == #
37
+
38
+ desc "Build right_scraper gem"
39
+ Gem::PackageTask.new(Gem::Specification.load("right_scraper.gemspec")) do |package|
40
+ package.need_zip = true
41
+ package.need_tar = true
42
+ end
43
+
44
+ CLEAN.include('pkg')
45
+
31
46
  # == Unit Tests == #
32
47
 
33
- desc "Run unit tests"
34
- Spec::Rake::SpecTask.new do |t|
35
- t.spec_files = Dir['**/*_spec.rb']
36
- t.spec_opts = lambda do
37
- IO.readlines(File.join(File.dirname(__FILE__), 'spec', 'spec.opts')).map {|l| l.chomp.split " "}.flatten
38
- end
48
+ task :specs => :spec
49
+
50
+ # == Unit Tests == #
51
+
52
+ desc 'Run unit tests'
53
+ RSpec::Core::RakeTask.new do |t|
54
+ t.pattern = 'spec/**/*_spec.rb'
55
+ t.rspec_opts = ["--color", "--format", "nested"]
39
56
  end
40
57
 
41
- desc "Run unit tests with RCov"
42
- Spec::Rake::SpecTask.new(:rcov) do |t|
43
- t.spec_files = Dir['**/*_spec.rb']
44
- t.rcov = true
45
- t.rcov_opts = lambda do
46
- IO.readlines(File.join(File.dirname(__FILE__), 'spec', 'rcov.opts')).map {|l| l.chomp.split " "}.flatten
58
+ namespace :spec do
59
+ desc "Run unit tests with RCov"
60
+ RSpec::Core::RakeTask.new(:rcov) do |t|
61
+ t.pattern = '*/spec/**/*_spec.rb'
62
+ t.rcov = true
63
+ t.rcov_opts = %q[--exclude "spec"]
47
64
  end
48
- end
49
65
 
50
- desc "Print Specdoc for unit tests"
51
- Spec::Rake::SpecTask.new(:doc) do |t|
52
- t.spec_opts = ["--format", "specdoc", "--dry-run"]
53
- t.spec_files = Dir['**/*_spec.rb']
66
+ desc "Print Specdoc for unit tests"
67
+ RSpec::Core::RakeTask.new(:doc) do |t|
68
+ t.pattern = '*/spec/**/*_spec.rb'
69
+ t.rspec_opts = ["--format", "documentation"]
70
+ end
54
71
  end
55
72
 
56
- # == Gem Management == #
73
+ # == Documentation == #
57
74
 
58
- desc "Build right_scraper gem"
59
- task :gem do
60
- ruby 'right_scraper.gemspec'
61
- pkg_dir = File.join(File.dirname(__FILE__), 'pkg')
62
- FileUtils.mkdir_p(pkg_dir)
63
- FileUtils.mv(Dir.glob(File.join(File.dirname(__FILE__), '*.gem')), pkg_dir)
64
- end
75
+ desc "Generate API documentation to doc/rdocs/index.html"
76
+ RDoc::Task.new do |rd|
77
+ rd.rdoc_dir = 'doc/rdocs'
78
+ rd.main = 'README.rdoc'
79
+ rd.rdoc_files.include 'README.rdoc', 'lib/**/*.rb'
65
80
 
66
- desc 'Install the right_scraper library as a gem'
67
- task :install => [:gem] do
68
- file = Dir["pkg/*.gem"].last
69
- sh "gem install #{file}"
81
+ rd.options << '--all'
82
+ rd.options << '--diagram'
70
83
  end
71
84
 
72
- desc 'Uninstalls and reinstalls the right_scraper library as a gem'
73
- task :reinstall do
74
- sh "gem uninstall right_scraper"
75
- sh "rake install"
85
+ # == Emacs integration == #
86
+ desc "Rebuild TAGS file"
87
+ task :tags do
88
+ sh "rtags -R */{lib,spec}"
76
89
  end
77
-
@@ -0,0 +1,64 @@
1
+ #--
2
+ # Copyright: Copyright (c) 2010-2011 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'logger'))
25
+
26
+ module RightScraper
27
+ module Builders
28
+ # Base class for building additional metadata from filesystem
29
+ # based checkouts. Subclasses should override #go, and possibly
30
+ # #new if they require additional arguments.
31
+ #
32
+ # The lifecycle for a builder is as follows:
33
+ # - builder = Builder.new (once)
34
+ # - builder.go(dir, resource) (many times)
35
+ # - builder.finish (once)
36
+ class Builder
37
+ # Create a new Builder. Recognizes options as given. Some
38
+ # options may be required, others optional. This class recognizes
39
+ # only :logger.
40
+ #
41
+ # === Options
42
+ # <tt>:logger</tt>:: Optional. Logger currently being used
43
+ #
44
+ # === Parameters
45
+ # options(Hash):: builder options
46
+ def initialize(options={})
47
+ @logger = options.fetch(:logger, Logger.new)
48
+ end
49
+
50
+ # Run builder for this resource.
51
+ #
52
+ # === Parameters
53
+ # dir(String):: directory resource exists at
54
+ # resource(Object):: resource instance being built
55
+ def go(dir, resource)
56
+ end
57
+
58
+ # Notification that all scans for this repository have
59
+ # completed.
60
+ def finish
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,96 @@
1
+ #--
2
+ # Copyright: Copyright (c) 2010-2011 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require File.expand_path(File.join(File.dirname(__FILE__), 'base'))
25
+
26
+ module RightScraper
27
+ module Builders
28
+ # Build metadata by scanning the filesystem.
29
+ class Filesystem < Builder
30
+
31
+ # Create a new filesystem scanner. In addition to the options
32
+ # recognized by Builder, this class recognizes <tt>:retriever</tt> and
33
+ # <tt>:scanner</tt>.
34
+ #
35
+ # === Options
36
+ # <tt>:scanner</tt>:: Required. Scanner currently being used
37
+ # <tt>:ignorable_paths</tt>:: Ignore directories whose name belong to this list
38
+ #
39
+ # === Parameters
40
+ # options(Hash):: scraper options
41
+ def initialize(options={})
42
+ super
43
+ @scanner = options.fetch(:scanner)
44
+ @ignorable_paths = options[:ignorable_paths]
45
+ end
46
+
47
+ # Tell the scanner we're done.
48
+ def finish
49
+ super
50
+ @scanner.finish
51
+ end
52
+
53
+ # Run builder for this resource.
54
+ #
55
+ # === Parameters
56
+ # dir(String):: directory resource exists at
57
+ # resource(Object):: resource instance being built
58
+ def go(dir, resource)
59
+ @logger.operation(:scanning_filesystem, "rooted at #{dir}") do
60
+ @scanner.begin(resource)
61
+ maybe_scan(Dir.new(dir), nil)
62
+ @scanner.end(resource)
63
+ end
64
+ end
65
+
66
+ def maybe_scan(directory, position)
67
+ if @scanner.notice_dir(position)
68
+ scan(directory, position)
69
+ end
70
+ end
71
+
72
+ # Scan the contents of directory.
73
+ #
74
+ # === Parameters
75
+ # directory(Dir):: directory to scan
76
+ # position(String):: relative pathname for _directory_ from root of resource
77
+ def scan(directory, position)
78
+ directory.each do |entry|
79
+ next if entry == '.' || entry == '..'
80
+ next if @ignorable_paths && @ignorable_paths.include?(entry)
81
+
82
+ fullpath = File.join(directory.path, entry)
83
+ relative_position = position ? File.join(position, entry) : entry
84
+
85
+ if File.directory?(fullpath)
86
+ maybe_scan(Dir.new(fullpath), relative_position)
87
+ else
88
+ @scanner.notice(relative_position) do
89
+ open(fullpath) {|f| f.read}
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,57 @@
1
+ #--
2
+ # Copyright: Copyright (c) 2010-2011 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ module RightScraper
25
+ module Builders
26
+ # Union builder, to permit running multiple builders in sequence
27
+ # with the same interface as running one.
28
+ class Union
29
+ # (Array) subcomponents of this union
30
+ attr_reader :subbuilders
31
+
32
+ # Create a new union builder. Recognizes no new options.
33
+ #
34
+ # === Parameters
35
+ # classes(List):: List of Builder classes to run
36
+ # options(Hash):: options to initialize each Builder with
37
+ def initialize(classes, options={})
38
+ @subbuilders = classes.map {|klass| klass.new(options)}
39
+ end
40
+
41
+ # Run each builder for this resource.
42
+ #
43
+ # === Parameters
44
+ # dir(String):: directory resource exists at
45
+ # resource(RightScraper::Resources::Base):: resource instance being built
46
+ def go(dir, resource)
47
+ @subbuilders.each {|builder| builder.go(dir, resource)}
48
+ end
49
+
50
+ # Notify subbuilders that all scans for this repository have
51
+ # completed.
52
+ def finish
53
+ @subbuilders.each {|builder| builder.finish}
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,102 @@
1
+ #--
2
+ # Copyright: Copyright (c) 2010-2011 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require 'logger'
25
+
26
+ module RightScraper
27
+ # Very simplistic logger for scraper operations.
28
+ class Logger < ::Logger
29
+ # If no arguments, create a Logger that logs to nothing.
30
+ # Otherwise pass the arguments on to ::Logger.
31
+ def initialize(*args)
32
+ if args.empty?
33
+ super('/dev/null')
34
+ self.level = ::Logger::ERROR
35
+ else
36
+ super
37
+ end
38
+ @exceptional = false
39
+ end
40
+
41
+ # (RightScraper::Repositories::Base) Repository currently being examined.
42
+ attr_writer :repository
43
+
44
+ # Begin an operation that merits logging. Will call #note_error
45
+ # if an exception is raised during the operation.
46
+ #
47
+ # === Parameters
48
+ # type(Symbol):: operation type identifier
49
+ # explanation(String):: optional explanation
50
+ def operation(type, explanation="")
51
+ begin
52
+ note_phase(:begin, type, explanation)
53
+ result = yield
54
+ note_phase(:commit, type, explanation)
55
+ result
56
+ rescue
57
+ note_phase(:abort, type, explanation, $!)
58
+ raise
59
+ end
60
+ end
61
+
62
+ # Note an event to the log. In this base class this calls
63
+ # note_error when an error occurs, but subclasses will presumably
64
+ # want to override it.
65
+ #
66
+ # === Parameters
67
+ # phase(Symbol):: phase of operation; one of :begin, :commit, :abort
68
+ # type(Symbol):: operation type identifier
69
+ # explanation(String):: explanation of operation
70
+ # exception(Exception):: optional exception (only if +phase+ is :abort)
71
+ def note_phase(phase, type, explanation, exception=nil)
72
+ case phase
73
+ when :begin then @exceptional = false
74
+ when :abort then
75
+ unless @exceptional
76
+ note_error(exception, type, explanation)
77
+ @exceptional = true
78
+ end
79
+ end
80
+ end
81
+
82
+ # Log an error, with the given exception and explanation of what
83
+ # was going on.
84
+ #
85
+ # === Parameters
86
+ # exception(Exception):: exception raised
87
+ # type(Symbol):: operation type identifier
88
+ # explanation(String):: optional explanation
89
+ def note_error(exception, type, explanation="")
90
+ error("Saw #{exception} during #{type}#{maybe_explain(explanation)}")
91
+ end
92
+
93
+ protected
94
+ def maybe_explain(explanation)
95
+ if explanation.nil? || explanation.empty?
96
+ ""
97
+ else
98
+ ": #{explanation}"
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,85 @@
1
+ #--
2
+ # Copyright: Copyright (c) 2010 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'logger'))
25
+
26
+ module RightScraper
27
+ module Loggers
28
+ # A very noisy logger, useful for debugging.
29
+ class NoisyLogger < Logger
30
+ # Initialize the logger, setting the current operation depth to 1.
31
+ def initialize(*args)
32
+ super
33
+ @pending = []
34
+ end
35
+
36
+ # Note an event to the log, including a visual indicator of how
37
+ # many nested operations are currently pending.
38
+ #
39
+ # === Parameters
40
+ # phase(Symbol):: phase of operation; one of :begin, :commit, :abort
41
+ # type(Symbol):: operation type identifier
42
+ # explanation(String):: explanation of operation
43
+ # exception(Exception):: optional exception (only if +phase+ is :abort)
44
+ def note_phase(phase, type, explanation, exception=nil)
45
+ if phase == :begin
46
+ @pending.push [type, explanation]
47
+ end
48
+ super
49
+ debug("#{depth_str} #{phase} #{immediate_context}")
50
+ unless phase == :begin
51
+ @pending.pop
52
+ end
53
+ end
54
+
55
+ def note_error(exception, type, explanation="")
56
+ recordedtype, recordedexplanation = @pending[-1]
57
+ if recordedtype != type || recordedexplanation != explanation
58
+ @pending.push [type, explanation]
59
+ end
60
+ error("Saw #{exception} during #{context}")
61
+ if recordedtype != type || recordedexplanation != explanation
62
+ @pending.pop
63
+ end
64
+ end
65
+
66
+ private
67
+ def depth_str
68
+ '>' * @pending.size
69
+ end
70
+
71
+ def context
72
+ @pending.reverse.map {|pair| contextify(pair)}.join(" in ")
73
+ end
74
+
75
+ def immediate_context
76
+ contextify(@pending[-1])
77
+ end
78
+
79
+ def contextify(pair)
80
+ type, explanation = pair
81
+ "#{type}#{maybe_explain(explanation)}"
82
+ end
83
+ end
84
+ end
85
+ end