right_scraper 1.0.26 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +16 -0
- data/README.rdoc +9 -28
- data/Rakefile +51 -39
- data/lib/right_scraper/builders/base.rb +64 -0
- data/lib/right_scraper/builders/filesystem.rb +96 -0
- data/lib/right_scraper/builders/union.rb +57 -0
- data/lib/right_scraper/logger.rb +102 -0
- data/lib/right_scraper/loggers/noisy.rb +85 -0
- data/lib/right_scraper/processes/ssh.rb +188 -0
- data/lib/right_scraper/repositories/base.rb +299 -0
- data/lib/right_scraper/repositories/download.rb +90 -0
- data/lib/right_scraper/repositories/git.rb +92 -0
- data/lib/right_scraper/repositories/mock.rb +70 -0
- data/lib/right_scraper/repositories/svn.rb +96 -0
- data/lib/right_scraper/resources/base.rb +70 -0
- data/{spec/scraper_base_spec.rb → lib/right_scraper/resources/cookbook.rb} +9 -23
- data/lib/right_scraper/resources/workflow.rb +55 -0
- data/lib/right_scraper/retrievers/base.rb +114 -0
- data/lib/right_scraper/retrievers/checkout.rb +79 -0
- data/lib/right_scraper/retrievers/download.rb +97 -0
- data/lib/right_scraper/retrievers/git.rb +140 -0
- data/lib/right_scraper/retrievers/svn.rb +87 -0
- data/lib/right_scraper/scanners/base.rb +111 -0
- data/lib/right_scraper/scanners/cookbook_manifest.rb +59 -0
- data/lib/right_scraper/scanners/cookbook_metadata.rb +69 -0
- data/lib/right_scraper/scanners/cookbook_s3_upload.rb +84 -0
- data/lib/right_scraper/scanners/union.rb +89 -0
- data/lib/right_scraper/scanners/workflow_manifest.rb +86 -0
- data/lib/right_scraper/scanners/workflow_metadata.rb +70 -0
- data/lib/right_scraper/scanners/workflow_s3_upload.rb +85 -0
- data/lib/right_scraper/scraper.rb +81 -57
- data/lib/right_scraper/scraper_logger.rb +61 -0
- data/lib/right_scraper/scrapers/base.rb +262 -0
- data/lib/right_scraper/scrapers/cookbook.rb +73 -0
- data/lib/right_scraper/scrapers/workflow.rb +88 -0
- data/lib/right_scraper/svn_client.rb +101 -0
- data/lib/right_scraper/version.rb +28 -0
- data/lib/right_scraper.rb +35 -11
- data/right_scraper.gemspec +26 -13
- data/right_scraper.rconf +13 -0
- data/spec/builder_spec.rb +50 -0
- data/spec/cookbook_helper.rb +73 -0
- data/spec/cookbook_manifest_spec.rb +55 -0
- data/spec/cookbook_s3_upload_spec.rb +152 -0
- data/spec/download/download_retriever_spec.rb +118 -0
- data/spec/download/download_retriever_spec_helper.rb +72 -0
- data/spec/download/download_spec.rb +130 -0
- data/spec/download/multi_dir_spec.rb +106 -0
- data/spec/download/multi_dir_spec_helper.rb +40 -0
- data/spec/git/cookbook_spec.rb +166 -0
- data/spec/git/demokey +27 -0
- data/spec/git/demokey.pub +1 -0
- data/spec/git/password_key +30 -0
- data/spec/git/password_key.pub +1 -0
- data/spec/git/repository_spec.rb +110 -0
- data/spec/git/retriever_spec.rb +505 -0
- data/spec/git/retriever_spec_helper.rb +112 -0
- data/spec/git/scraper_spec.rb +136 -0
- data/spec/git/ssh_spec.rb +170 -0
- data/spec/git/url_spec.rb +103 -0
- data/spec/logger_spec.rb +185 -0
- data/spec/repository_spec.rb +89 -23
- data/spec/{scraper_spec_helper_base.rb → retriever_spec_helper.rb} +41 -27
- data/spec/scanner_spec.rb +61 -0
- data/spec/scraper_helper.rb +96 -0
- data/spec/scraper_spec.rb +123 -45
- data/spec/spec_helper.rb +87 -14
- data/spec/svn/cookbook_spec.rb +97 -0
- data/spec/svn/multi_svn_spec.rb +64 -0
- data/spec/svn/multi_svn_spec_helper.rb +40 -0
- data/spec/svn/repository_spec.rb +72 -0
- data/spec/svn/retriever_spec.rb +261 -0
- data/spec/svn/scraper_spec.rb +90 -0
- data/spec/svn/{svn_scraper_spec_helper.rb → svn_retriever_spec_helper.rb} +46 -27
- data/spec/svn/url_spec.rb +47 -0
- data/spec/url_spec.rb +164 -0
- metadata +203 -31
- data/lib/right_scraper/linux/process_monitor.rb +0 -84
- data/lib/right_scraper/repository.rb +0 -78
- data/lib/right_scraper/scraper_base.rb +0 -175
- data/lib/right_scraper/scrapers/download_scraper.rb +0 -67
- data/lib/right_scraper/scrapers/git_scraper.rb +0 -283
- data/lib/right_scraper/scrapers/svn_scraper.rb +0 -119
- data/lib/right_scraper/watcher.rb +0 -158
- data/lib/right_scraper/win32/process_monitor.rb +0 -98
- data/spec/download/download_scraper_spec.rb +0 -94
- data/spec/git/git_scraper_spec.rb +0 -165
- data/spec/git/git_scraper_spec_helper.rb +0 -72
- data/spec/rcov.opts +0 -1
- data/spec/spec.opts +0 -2
- data/spec/svn/svn_scraper_spec.rb +0 -148
- 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
|
-
|
11
|
-
|
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
|
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 '
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
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
|
-
# ==
|
73
|
+
# == Documentation == #
|
57
74
|
|
58
|
-
desc "
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
-
|
67
|
-
|
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
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|