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.
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
@@ -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