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
@@ -0,0 +1,140 @@
|
|
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
|
+
require 'git'
|
24
|
+
|
25
|
+
module RightScraper
|
26
|
+
module Retrievers
|
27
|
+
# Retriever for resources stored in a git repository.
|
28
|
+
class Git < CheckoutBasedRetriever
|
29
|
+
# In addition to normal retriever initialization, if the
|
30
|
+
# underlying repository has a credential we need to initialize a
|
31
|
+
# fresh SSHAgent and add the credential to it.
|
32
|
+
def retrieve
|
33
|
+
RightScraper::Processes::SSHAgent.with do |agent|
|
34
|
+
agent.add_key(@repository.first_credential) unless
|
35
|
+
@repository.first_credential.nil?
|
36
|
+
super
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Return true if a checkout exists. Currently tests for .git in
|
41
|
+
# the checkout.
|
42
|
+
#
|
43
|
+
# === Returns ===
|
44
|
+
# Boolean:: true if the checkout already exists (and thus
|
45
|
+
# incremental updating can occur).
|
46
|
+
def exists?
|
47
|
+
File.exists?(File.join(@repo_dir, '.git'))
|
48
|
+
end
|
49
|
+
|
50
|
+
def do_fetch(git)
|
51
|
+
@logger.operation(:fetch) do
|
52
|
+
git.tags.each {|tag| git.lib.tag(['-d', tag.name])}
|
53
|
+
git.fetch(['--all', '--prune', '--tags'])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Incrementally update the checkout. The operations are as follows:
|
58
|
+
# * checkout #tag
|
59
|
+
# * if #tag is the head of a branch:
|
60
|
+
# * find that branch's remote
|
61
|
+
# * fetch it
|
62
|
+
# * merge changes
|
63
|
+
# * update @repository#tag
|
64
|
+
# Note that if #tag is a SHA revision or a tag that exists in the
|
65
|
+
# current repository, no fetching is done.
|
66
|
+
def do_update
|
67
|
+
git = ::Git.open(@repo_dir)
|
68
|
+
do_fetch(git)
|
69
|
+
git.reset_hard
|
70
|
+
do_checkout_revision(git)
|
71
|
+
do_update_tag(git)
|
72
|
+
end
|
73
|
+
|
74
|
+
def do_update_tag(git)
|
75
|
+
@repository = @repository.clone
|
76
|
+
@repository.tag = git.gtree("HEAD").sha
|
77
|
+
end
|
78
|
+
|
79
|
+
# Clone the remote repository. The operations are as follows:
|
80
|
+
# * clone repository to @repo_dir
|
81
|
+
# * checkout #tag
|
82
|
+
# * update @repository#tag
|
83
|
+
def do_checkout
|
84
|
+
super
|
85
|
+
git = @logger.operation(:cloning, "to #{@repo_dir}") do
|
86
|
+
::Git.clone(@repository.url, @repo_dir)
|
87
|
+
end
|
88
|
+
do_fetch(git)
|
89
|
+
do_checkout_revision(git)
|
90
|
+
do_update_tag git
|
91
|
+
end
|
92
|
+
|
93
|
+
def do_checkout_revision(git)
|
94
|
+
@logger.operation(:checkout_revision) do
|
95
|
+
case
|
96
|
+
when tag?(git, repo_tag) && branch?(git, repo_tag) then
|
97
|
+
raise "Ambiguous reference: '#{repo_tag}' denotes both a branch and a tag"
|
98
|
+
when branch = find_remote_branch(git, repo_tag) then
|
99
|
+
branch.checkout
|
100
|
+
when branch = find_local_branch(git, repo_tag) then
|
101
|
+
branch.checkout
|
102
|
+
else
|
103
|
+
git.checkout(repo_tag)
|
104
|
+
end
|
105
|
+
end if repo_tag
|
106
|
+
end
|
107
|
+
|
108
|
+
def tag?(git, name)
|
109
|
+
git.tags.find {|t| t.name == name}
|
110
|
+
end
|
111
|
+
|
112
|
+
def branch?(git, name)
|
113
|
+
git.branches.find {|t| t.name == name}
|
114
|
+
end
|
115
|
+
|
116
|
+
def repo_tag
|
117
|
+
name = (@repository.tag || "master").chomp
|
118
|
+
name = "master" if name.empty?
|
119
|
+
name
|
120
|
+
end
|
121
|
+
|
122
|
+
def find_branch(git, tag)
|
123
|
+
find_local_branch(git, tag) || find_remote_branch(git, tag)
|
124
|
+
end
|
125
|
+
|
126
|
+
def find_local_branch(git, name)
|
127
|
+
git.branches.local.find {|b| b.name == name}
|
128
|
+
end
|
129
|
+
|
130
|
+
def find_remote_branch(git, name)
|
131
|
+
git.branches.remote.find {|b| b.name == name}
|
132
|
+
end
|
133
|
+
|
134
|
+
# Ignore .git directories.
|
135
|
+
def ignorable_paths
|
136
|
+
['.git']
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,87 @@
|
|
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
|
+
require File.join(File.dirname(__FILE__), '..', 'svn_client')
|
24
|
+
|
25
|
+
require 'process_watcher'
|
26
|
+
|
27
|
+
module RightScraper
|
28
|
+
module Retrievers
|
29
|
+
# Retriever for svn repositories
|
30
|
+
class Svn < CheckoutBasedRetriever
|
31
|
+
|
32
|
+
include RightScraper::SvnClient
|
33
|
+
|
34
|
+
# Return true if a checkout exists. Currently tests for .svn in
|
35
|
+
# the checkout.
|
36
|
+
#
|
37
|
+
# === Returns
|
38
|
+
# Boolean:: true if the checkout already exists (and thus
|
39
|
+
# incremental updating can occur).
|
40
|
+
def exists?
|
41
|
+
File.exists?(File.join(@repo_dir, '.svn'))
|
42
|
+
end
|
43
|
+
|
44
|
+
# Incrementally update the checkout. The operations are as follows:
|
45
|
+
# * update to #tag
|
46
|
+
# In theory if #tag is a revision number that already exists no
|
47
|
+
# update is necessary. It's not clear if the SVN client libraries
|
48
|
+
# are bright enough to notice this.
|
49
|
+
def do_update
|
50
|
+
@logger.operation(:update) do
|
51
|
+
run_svn("update", get_tag_argument)
|
52
|
+
end
|
53
|
+
do_update_tag
|
54
|
+
end
|
55
|
+
|
56
|
+
# Update our idea of what the head of the repository is. We
|
57
|
+
# would like to use svn info, but that doesn't do the right
|
58
|
+
# thing all the time; the right thing to do is to run log and
|
59
|
+
# pick out the first tag.
|
60
|
+
def do_update_tag
|
61
|
+
@repository = @repository.clone
|
62
|
+
log = run_svn("log", "-r", 'HEAD')
|
63
|
+
log.split(/\n/).each do |line|
|
64
|
+
if line =~ /^r(\d+)/
|
65
|
+
@repository.tag = $1
|
66
|
+
break
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Check out the remote repository. The operations are as follows:
|
72
|
+
# * checkout repository at #tag to @repo_dir
|
73
|
+
def do_checkout
|
74
|
+
super
|
75
|
+
@logger.operation(:checkout_revision) do
|
76
|
+
run_svn_no_chdir("checkout", @repository.url, @repo_dir, get_tag_argument)
|
77
|
+
end
|
78
|
+
do_update_tag
|
79
|
+
end
|
80
|
+
|
81
|
+
# Ignore .svn directories.
|
82
|
+
def ignorable_paths
|
83
|
+
['.svn']
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,111 @@
|
|
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 Scanners
|
26
|
+
# Base class for scanning filesystems. Subclasses should override
|
27
|
+
# #notice and may override #new, #begin, #end and
|
28
|
+
# #notice_dir.
|
29
|
+
#
|
30
|
+
# Overriding #new is useful for getting
|
31
|
+
# additional arguments. Overriding #begin allows you to do
|
32
|
+
# processing before the scan of a given resource begins;
|
33
|
+
# overriding #end allows you to do processing after it completes.
|
34
|
+
#
|
35
|
+
# Most processing will occur in #notice, which notifies you that a
|
36
|
+
# file has been detected, and in #notice_dir. In #notice you are
|
37
|
+
# handed the relative position of the file from the start of the
|
38
|
+
# resource; so if you were scanning <tt>/a/resource</tt> and
|
39
|
+
# noticed a file <tt>b/c</tt>, #notice would be called with
|
40
|
+
# <tt>"b/c"</tt>, even though the full pathname is
|
41
|
+
# <tt>/a/resource/b/c</tt>. If you decide you need the actual
|
42
|
+
# data, #notice takes a block which will return that data to you
|
43
|
+
# if you +yield+.
|
44
|
+
#
|
45
|
+
# In #notice_dir you are handed the relative position of a
|
46
|
+
# directory. The return value determines whether you find the
|
47
|
+
# directory worth recursing into, or not--as an example, when
|
48
|
+
# looking for the <tt>metadata.json</tt> file it is never
|
49
|
+
# necessary to descend past the topmost directory of the resource,
|
50
|
+
# but the same is not true when building a manifest.
|
51
|
+
class Base
|
52
|
+
# Create a new Scanner. Recognizes options as given. Some
|
53
|
+
# options may be required, others optional. This class recognizes
|
54
|
+
# only _:logger_.
|
55
|
+
#
|
56
|
+
# === Options ===
|
57
|
+
# _:logger_:: Optional. Logger currently being used
|
58
|
+
#
|
59
|
+
# === Parameters ===
|
60
|
+
# options(Hash):: scanner options
|
61
|
+
def initialize(options={})
|
62
|
+
@logger = options.fetch(:logger, RightScraper::Logger.new)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Notification that all scans for this repository have
|
66
|
+
# completed.
|
67
|
+
def finish
|
68
|
+
end
|
69
|
+
|
70
|
+
# Begin a scan for the given resource.
|
71
|
+
#
|
72
|
+
# === Parameters ===
|
73
|
+
# resource(RightScraper::Resource::Base):: resource to scan
|
74
|
+
def begin(resource)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Finish a scan for the given resource.
|
78
|
+
#
|
79
|
+
# === Parameters ===
|
80
|
+
# resource(RightScraper::Resource::Base):: resource that just finished
|
81
|
+
# scanning
|
82
|
+
def end(resource)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Notice a file during scanning.
|
86
|
+
#
|
87
|
+
# === Block ===
|
88
|
+
# Return the data for this file. We use a block because it may
|
89
|
+
# not always be necessary to read the data.
|
90
|
+
#
|
91
|
+
# === Parameters ===
|
92
|
+
# relative_position(String):: relative pathname for _pathname_
|
93
|
+
# from root of resource
|
94
|
+
def notice(relative_position)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Notice a directory during scanning. Returns true if the scanner
|
98
|
+
# should recurse into the directory (the default behavior)
|
99
|
+
#
|
100
|
+
# === Parameters ===
|
101
|
+
# relative_position(String):: relative pathname for the directory
|
102
|
+
# from root of resource
|
103
|
+
#
|
104
|
+
# === Returns ===
|
105
|
+
# Boolean:: should the scanning recurse into the directory
|
106
|
+
def notice_dir(relative_position)
|
107
|
+
true
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,59 @@
|
|
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
|
+
require 'digest/sha1'
|
26
|
+
|
27
|
+
module RightScraper
|
28
|
+
module Scanners
|
29
|
+
# Build manifests from a filesystem.
|
30
|
+
class CookbookManifest < Base
|
31
|
+
# Create a new manifest scanner. Does not accept any new arguments.
|
32
|
+
def initialize(*args)
|
33
|
+
super
|
34
|
+
@manifest = {}
|
35
|
+
end
|
36
|
+
|
37
|
+
# Complete a scan for the given resource.
|
38
|
+
#
|
39
|
+
# === Parameters ===
|
40
|
+
# resource(RightScraper::Resources::Base):: resource to scan
|
41
|
+
def end(resource)
|
42
|
+
resource.manifest = @manifest
|
43
|
+
@manifest = {}
|
44
|
+
end
|
45
|
+
|
46
|
+
# Notice a file during scanning.
|
47
|
+
#
|
48
|
+
# === Block ===
|
49
|
+
# Return the data for this file. We use a block because it may
|
50
|
+
# not always be necessary to read the data.
|
51
|
+
#
|
52
|
+
# === Parameters ===
|
53
|
+
# relative_position(String):: relative pathname for file from root of resource
|
54
|
+
def notice(relative_position)
|
55
|
+
@manifest[relative_position] = Digest::SHA1.hexdigest(yield)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,69 @@
|
|
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 'json'
|
25
|
+
|
26
|
+
module RightScraper
|
27
|
+
module Scanners
|
28
|
+
# Load cookbook metadata from a filesystem.
|
29
|
+
class CookbookMetadata < Base
|
30
|
+
# Begin a scan for the given cookbook.
|
31
|
+
#
|
32
|
+
# === Parameters
|
33
|
+
# cookbook(RightScraper::Resources::Cookbook):: cookbook to scan
|
34
|
+
def begin(cookbook)
|
35
|
+
@cookbook = cookbook
|
36
|
+
end
|
37
|
+
|
38
|
+
# Notice a file during scanning.
|
39
|
+
#
|
40
|
+
# === Block
|
41
|
+
# Return the data for this file. We use a block because it may
|
42
|
+
# not always be necessary to read the data.
|
43
|
+
#
|
44
|
+
# === Parameters
|
45
|
+
# relative_position(String):: relative pathname for the file from root of cookbook
|
46
|
+
def notice(relative_position)
|
47
|
+
if relative_position == "metadata.json"
|
48
|
+
@logger.operation(:metadata_parsing) do
|
49
|
+
@cookbook.metadata = JSON.parse(yield)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Notice a directory during scanning. Since metadata.json is by
|
55
|
+
# definition only in the root directory we don't need to recurse,
|
56
|
+
# but we do need to go into the first directory (identified by
|
57
|
+
# +relative_position+ being +nil+).
|
58
|
+
#
|
59
|
+
# === Parameters
|
60
|
+
# relative_position(String):: relative pathname for the directory from root of cookbook
|
61
|
+
#
|
62
|
+
# === Returns
|
63
|
+
# Boolean:: should the scanning recurse into the directory
|
64
|
+
def notice_dir(relative_position)
|
65
|
+
relative_position == nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,84 @@
|
|
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
|
+
require 'right_aws'
|
24
|
+
require 'json'
|
25
|
+
|
26
|
+
module RightScraper
|
27
|
+
module Scanners
|
28
|
+
# Upload scanned files to an S3 bucket.
|
29
|
+
class CookbookS3Upload < Base
|
30
|
+
# Create a new S3Upload. In addition to the options recognized
|
31
|
+
# by Scanner, this class recognizes <tt>:s3_key</tt>,
|
32
|
+
# <tt>:s3_secret</tt>, and <tt>:s3_bucket</tt> and requires all
|
33
|
+
# of those.
|
34
|
+
#
|
35
|
+
# === Options
|
36
|
+
# <tt>:s3_key</tt>:: Required. S3 access key.
|
37
|
+
# <tt>:s3_secret</tt>:: Required. S3 secret key.
|
38
|
+
# <tt>:s3_bucket</tt>:: Required. Bucket to upload cookbooks to.
|
39
|
+
#
|
40
|
+
# === Parameters
|
41
|
+
# options(Hash):: scanner options
|
42
|
+
def initialize(options={})
|
43
|
+
super
|
44
|
+
s3_key = options.fetch(:s3_key)
|
45
|
+
s3_secret = options.fetch(:s3_secret)
|
46
|
+
s3 = RightAws::S3.new(aws_access_key_id=s3_key,
|
47
|
+
aws_secret_access_key=s3_secret,
|
48
|
+
:logger => Logger.new)
|
49
|
+
@bucket = s3.bucket(options.fetch(:s3_bucket))
|
50
|
+
raise "Need an actual, existing S3 bucket!" if @bucket.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
# Upon ending a scan for a cookbook, upload the cookbook
|
54
|
+
# contents to S3.
|
55
|
+
#
|
56
|
+
# === Parameters
|
57
|
+
# cookbook(RightScraper::Cookbook):: cookbook to scan
|
58
|
+
def end(cookbook)
|
59
|
+
@bucket.put(File.join('Cooks', cookbook.resource_hash),
|
60
|
+
{
|
61
|
+
:metadata => cookbook.metadata,
|
62
|
+
:manifest => cookbook.manifest
|
63
|
+
}.to_json)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Upload a file during scanning.
|
67
|
+
#
|
68
|
+
# === Block
|
69
|
+
# Return the data for this file. We use a block because it may
|
70
|
+
# not always be necessary to read the data.
|
71
|
+
#
|
72
|
+
# === Parameters
|
73
|
+
# relative_position(String):: relative pathname for file from root of cookbook
|
74
|
+
def notice(relative_position)
|
75
|
+
contents = yield
|
76
|
+
name = Digest::SHA1.hexdigest(contents)
|
77
|
+
path = File.join('Files', name)
|
78
|
+
unless @bucket.key(path).exists?
|
79
|
+
@bucket.put(path, contents)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,89 @@
|
|
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 Scanners
|
26
|
+
# Union scanner, to permit running multiple scanners while only
|
27
|
+
# walking the fs once.
|
28
|
+
class Union
|
29
|
+
# Create a new union scanner. Recognizes no new options.
|
30
|
+
#
|
31
|
+
# === Parameters
|
32
|
+
# classes(List):: List of Scanner classes to run
|
33
|
+
# options(Hash):: scanner options
|
34
|
+
def initialize(classes, options={})
|
35
|
+
@subscanners = classes.map {|klass| klass.new(options)}
|
36
|
+
end
|
37
|
+
|
38
|
+
# Notify subscanners that all scans have completed.
|
39
|
+
def finish
|
40
|
+
@subscanners.each {|scanner| scanner.finish}
|
41
|
+
end
|
42
|
+
|
43
|
+
# Begin a scan for the given resource.
|
44
|
+
#
|
45
|
+
# === Parameters
|
46
|
+
# resource(RightScraper::Resource::Base):: resource to scan
|
47
|
+
def begin(resource)
|
48
|
+
@subscanners.each {|scanner| scanner.begin(resource)}
|
49
|
+
end
|
50
|
+
|
51
|
+
# Finish a scan for the given resource.
|
52
|
+
#
|
53
|
+
# === Parameters
|
54
|
+
# resource(RightScraper::Resource::Base):: resource that just finished scanning
|
55
|
+
def end(resource)
|
56
|
+
@subscanners.each {|scanner| scanner.end(resource)}
|
57
|
+
end
|
58
|
+
|
59
|
+
# Notice a file during scanning.
|
60
|
+
#
|
61
|
+
# === Block
|
62
|
+
# Return the data for this file. We use a block because it may
|
63
|
+
# not always be necessary to read the data.
|
64
|
+
#
|
65
|
+
# === Parameters
|
66
|
+
# relative_position(String):: relative pathname for the file from the root of resource
|
67
|
+
def notice(relative_position)
|
68
|
+
data = nil
|
69
|
+
@subscanners.each {|scanner| scanner.notice(relative_position) {
|
70
|
+
data = yield if data.nil?
|
71
|
+
data
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
# Notice a directory during scanning. Returns true if any of the
|
77
|
+
# subscanners report that they should recurse into the directory.
|
78
|
+
#
|
79
|
+
# === Parameters
|
80
|
+
# relative_position(String):: relative pathname for directory from root of resource
|
81
|
+
#
|
82
|
+
# === Returns
|
83
|
+
# Boolean:: should the scanning recurse into the directory
|
84
|
+
def notice_dir(relative_position)
|
85
|
+
@subscanners.any? {|scanner| scanner.notice_dir(relative_position)}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|