right_scraper 3.0.4 → 3.2.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,15 +1,14 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
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"
3
+ gemspec
4
+
5
+ gem 'right_popen', :git => 'git@github.com:rightscale/right_popen.git',
6
+ :branch => "master"
7
+
8
+ gem 'right_support', '2.7'
8
9
 
9
10
  group :development do
10
- gem "rspec", "~> 2.3"
11
11
  gem "rake", "0.8.7"
12
- gem "flexmock"
13
12
  gem "ruby-debug", :platform=>"ruby_18"
14
13
  gem "ruby-debug19", :platform=>"ruby_19"
15
14
  gem "rdoc", "~> 2.4"
data/README.rdoc CHANGED
@@ -10,6 +10,8 @@ may specify only the functionality (and required libraries and gems) you require
10
10
  This gem depends on all available RightScraper modules, enabling full support at the
11
11
  cost of requiring some systems administration work external to Ruby.
12
12
 
13
+ Maintained by the RightScale Teal Team
14
+
13
15
  == USAGE
14
16
 
15
17
  === Simple Example
@@ -17,7 +19,7 @@ cost of requiring some systems administration work external to Ruby.
17
19
  require 'rubygems'
18
20
  require 'right_scraper'
19
21
 
20
- scraper = RightScale::Scraper.new(:basedir => '/tmp', :kind => :cookbook)
22
+ scraper = RightScraper::Scraper.new(:basedir => '/tmp', :kind => :cookbook)
21
23
  scraper.scrape(:type => :git, :url => 'git://github.com/rightscale/right_scraper.git')
22
24
 
23
25
  == INSTALLATION
@@ -53,8 +53,8 @@ module RightScraper
53
53
  result = yield
54
54
  note_phase(:commit, type, explanation)
55
55
  result
56
- rescue
57
- note_phase(:abort, type, explanation, $!)
56
+ rescue Exception => e
57
+ note_phase(:abort, type, explanation, e)
58
58
  raise
59
59
  end
60
60
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright: Copyright (c) 2010 RightScale, Inc.
2
+ # Copyright: Copyright (c) 2010-2013 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
@@ -20,14 +20,19 @@
20
20
  # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
21
  # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
+
23
24
  require 'tempfile'
24
- require 'process_watcher'
25
25
  require 'tmpdir'
26
+ require 'right_popen'
27
+ require 'right_popen/safe_output_buffer'
26
28
 
27
29
  module RightScraper
28
30
  module Processes
29
31
  # Manage a dedicated SSH agent.
30
32
  class SSHAgent
33
+
34
+ class SSHAgentError < Exception; end
35
+
31
36
  def initialize
32
37
  @display = ENV['DISPLAY']
33
38
  @askpass = ENV['SSH_ASKPASS']
@@ -46,26 +51,31 @@ module RightScraper
46
51
  ENV['HOME'] = "/dev/null"
47
52
  @dir = Dir.mktmpdir
48
53
  @socketfile = File.join(@dir, "agent")
49
- @monitor = ProcessWatcher::ProcessMonitor.new
50
- @pid = @monitor.spawn('ssh-agent', '-a', @socketfile, '-d') {}
51
- timeout = 0
52
- until File.exists?(@socketfile)
53
- timeout += 1
54
- sleep 0.1
55
- if timeout > 100
56
- raise "Couldn't find SSH agent control socket in time. Timing out"
57
- end
54
+ @process = nil
55
+ @interupted_to_close = false
56
+ @ssh_agent_output = ::RightScale::RightPopen::SafeOutputBuffer.new
57
+ cmd = ['ssh-agent', '-a', @socketfile, '-d']
58
+ ::RightScale::RightPopen.popen3_sync(
59
+ cmd,
60
+ :target => self,
61
+ :inherit_io => true, # avoid killing any rails connection
62
+ :watch_handler => :watch_ssh_agent,
63
+ :stderr_handler => :output_ssh_agent,
64
+ :stdout_handler => :output_ssh_agent,
65
+ :timeout_handler => :timeout_ssh_agent,
66
+ :exit_handler => :exit_ssh_agent,
67
+ :timeout_seconds => 10)
68
+ if @process
69
+ ENV['SSH_AGENT_PID'] = @process.pid.to_s
70
+ ENV['SSH_AUTH_SOCK'] = @socketfile
58
71
  end
59
- ENV['SSH_AGENT_PID'] = @pid.to_s
60
- ENV['SSH_AUTH_SOCK'] = @socketfile
61
72
  end
62
73
 
63
74
  # Close the connection to the SSH agent, and restore +ENV+.
64
75
  def close
65
76
  begin
66
77
  FileUtils.remove_entry_secure @dir
67
- lay_to_rest(@pid) if @pid
68
- @monitor.cleanup if @monitor
78
+ lay_to_rest
69
79
  ensure
70
80
  setvar 'SSH_AGENT_PID', @agentpid
71
81
  setvar 'DISPLAY', @display
@@ -75,71 +85,35 @@ module RightScraper
75
85
  end
76
86
  end
77
87
 
78
- # Kill +pid+. Initially use SIGTERM to be kind and a good
79
- # citizen. If it doesn't die after +timeout+ seconds, use
80
- # SIGKILL instead. In any case, the process will die. The
81
- # status information is accessible in $?.
82
- #
83
- # === Parameters
84
- # pid(Fixnum):: pid of process to kill
85
- # timeout(Fixnum):: time in seconds to wait before forcing
86
- # process to die. Defaults to 10 seconds.
87
- def lay_to_rest(pid, timeout=10)
88
- #refuse to kill ourselves, or to pass a bad arg to Process.kill
89
- return 0 unless pid.is_a?(Integer) && pid > 0
90
-
91
- Process.kill('TERM', pid)
92
- time_waited = 0
93
- loop do
94
- if time_waited >= timeout
95
- Process.kill('KILL', pid)
96
- # can't waitpid here, because the ssh-agent isn't our
97
- # child. Still, after SIGKILL it will die and init will
98
- # reap it, so continue
99
- return
100
- end
101
- # still can't waitpid here, so we see if it's still alive
102
- return unless still_alive?(pid)
103
- sleep 1
104
- time_waited += 1
105
- end
88
+ def output_ssh_agent(data)
89
+ @ssh_agent_output.safe_buffer_data(data)
106
90
  end
107
91
 
108
- # Check to see if the process +pid+ is still alive, by sending
109
- # the 0 signal and checking for an exception.
92
+ # abandons watch when socket file appears
110
93
  #
111
- # === Parameters
112
- # pid(Fixnum):: pid of process to check on
113
- #
114
- # === Return
115
- # Boolean:: true if process is still alive
116
- def still_alive?(pid)
117
- begin
118
- Process.kill(0, pid)
94
+ # @return [TrueClass|FalseClass] true to continue watch, false to abandon
95
+ def watch_ssh_agent(process)
96
+ if @interupted_to_close
119
97
  true
120
- rescue Errno::ESRCH
121
- false
98
+ else
99
+ @process = process
100
+ !::File.exists?(@socketfile)
122
101
  end
123
102
  end
124
103
 
125
- # Set an environment variable to a value. If +value+ is nil,
126
- # delete the variable instead.
127
- #
128
- # === Parameters
129
- # key(String):: environment variable name
130
- # value(String or nil):: proposed new value
131
- #
132
- # === Return
133
- # true
134
- def setvar(key, value)
135
- if value.nil?
136
- ENV.delete(key)
137
- else
138
- ENV[key] = value
104
+ def timeout_ssh_agent
105
+ unless @interupted_to_close
106
+ raise SSHAgentError, 'Timed out waiting for ssh-agent control socket to appear'
107
+ end
108
+ end
109
+
110
+ def exit_ssh_agent(status)
111
+ unless @interupted_to_close || status.success?
112
+ @ssh_agent_output.safe_buffer_data("Exit code = #{status.exitstatus}")
113
+ raise SSHAgentError, "ssh-agent failed: #{@ssh_agent_output.display_text}"
139
114
  end
140
115
  true
141
116
  end
142
- private :setvar
143
117
 
144
118
  # Add the given key data to the ssh agent.
145
119
  #
@@ -162,7 +136,33 @@ module RightScraper
162
136
  # === Parameters
163
137
  # file(String):: file containing key data
164
138
  def add_keyfile(file)
165
- ProcessWatcher.watch("ssh-add", [file], nil, -1, 10)
139
+ @ssh_add_output = ::RightScale::RightPopen::SafeOutputBuffer.new
140
+ cmd = ['ssh-add', file]
141
+ ::RightScale::RightPopen.popen3_sync(
142
+ cmd,
143
+ :target => self,
144
+ :inherit_io => true, # avoid killing any rails connection
145
+ :stderr_handler => :output_ssh_add,
146
+ :stdout_handler => :output_ssh_add,
147
+ :timeout_handler => :timeout_ssh_add,
148
+ :exit_handler => :exit_ssh_add,
149
+ :timeout_seconds => 10)
150
+ end
151
+
152
+ def output_ssh_add(data)
153
+ @ssh_add_output.safe_buffer_data(data)
154
+ end
155
+
156
+ def timeout_ssh_add
157
+ raise SSHAgentError, 'ssh-add timed out'
158
+ end
159
+
160
+ def exit_ssh_add(status)
161
+ unless status.success?
162
+ @ssh_add_output.safe_buffer_data("Exit code = #{status.exitstatus}")
163
+ raise SSHAgentError, "ssh-add failed: #{@ssh_add_output.display_text}"
164
+ end
165
+ true
166
166
  end
167
167
 
168
168
  # Execute the block in a new ssh agent.
@@ -183,6 +183,38 @@ module RightScraper
183
183
  agent.close
184
184
  end
185
185
  end
186
+
187
+ private
188
+
189
+ def lay_to_rest
190
+ if @process
191
+ if @process.interrupt
192
+ @interupted_to_close = true
193
+ @process.sync_exit_with_target
194
+ else
195
+ @process.safe_close_io
196
+ end
197
+ end
198
+ end
199
+
200
+ # Set an environment variable to a value. If +value+ is nil,
201
+ # delete the variable instead.
202
+ #
203
+ # === Parameters
204
+ # key(String):: environment variable name
205
+ # value(String or nil):: proposed new value
206
+ #
207
+ # === Return
208
+ # true
209
+ def setvar(key, value)
210
+ if value.nil?
211
+ ENV.delete(key)
212
+ else
213
+ ENV[key] = value
214
+ end
215
+ true
216
+ end
217
+
186
218
  end
187
219
  end
188
220
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright: Copyright (c) 2010-2011 RightScale, Inc.
2
+ # Copyright: Copyright (c) 2010-2012 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
@@ -21,12 +21,45 @@
21
21
  # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
23
 
24
+ require 'digest/md5'
25
+ require 'json'
26
+ require 'right_support'
27
+
24
28
  module RightScraper
25
29
 
26
30
  module Resources
27
31
 
28
32
  class Cookbook < Base
29
- end
30
33
 
34
+ EMPTY_MANIFEST_JSON = ::JSON.dump(:manifest => {}).freeze
35
+
36
+ def manifest=(value)
37
+ @manifest_json = nil
38
+ @resource_hash = nil
39
+ @manifest = value
40
+ end
41
+
42
+ def manifest_json
43
+ unless @manifest_json
44
+ if manifest && !manifest.empty?
45
+ # note that we are preserving the :manifest key at the root only to
46
+ # avoid having to change how the manifest is interpreted by Repose.
47
+ manifest_hash = { :manifest => manifest }
48
+ @manifest_json = ::RightSupport::Data::HashTools.deep_sorted_json(manifest_hash, pretty=true).freeze
49
+ else
50
+ @manifest_json = EMPTY_MANIFEST_JSON
51
+ end
52
+ end
53
+ @manifest_json
54
+ end
55
+
56
+ def resource_hash
57
+ unless @resource_hash
58
+ @resource_hash = ::Digest::MD5.hexdigest(manifest_json).freeze
59
+ end
60
+ @resource_hash
61
+ end
62
+
63
+ end
31
64
  end
32
65
  end
@@ -40,9 +40,9 @@ module RightScraper
40
40
  @logger.operation(:updating) do
41
41
  do_update
42
42
  end
43
- rescue
44
- @logger.note_error($!, :updating, "switching to using checkout")
45
- FileUtils.remove_entry_secure @repo_dir
43
+ rescue Exception => e
44
+ @logger.note_error(e, :updating, "switching to using checkout")
45
+ FileUtils.remove_entry_secure basedir
46
46
  @logger.operation(:checkout) do
47
47
  do_checkout
48
48
  end
@@ -20,9 +20,11 @@
20
20
  # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
21
  # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
- require 'process_watcher'
23
+
24
24
  require 'tempfile'
25
25
  require 'digest/sha1'
26
+ require 'right_popen'
27
+ require 'right_popen/safe_output_buffer'
26
28
 
27
29
  module RightScraper
28
30
  module Retrievers
@@ -30,6 +32,8 @@ module RightScraper
30
32
  # somewhere. Uses command line curl and command line tar.
31
33
  class Download < Base
32
34
 
35
+ class DownloadError < Exception; end
36
+
33
37
  @@available = false
34
38
 
35
39
  # Determines if downloader is available.
@@ -54,32 +58,48 @@ module RightScraper
54
58
 
55
59
  # Directory used to download tarballs
56
60
  def workdir
57
- File.join(@basedir, @repository.repository_hash)
58
- end
59
-
60
- # Path to directory where files are retrieved
61
- def repo_dir
62
- File.join(workdir, "archive")
61
+ @workdir ||= ::File.join(::File.dirname(@repo_dir), 'download')
63
62
  end
64
63
 
65
64
  # Download tarball and unpack it
66
65
  def retrieve
67
66
  raise RetrieverError.new("download retriever is unavailable") unless available?
67
+ FileUtils.remove_entry_secure @repo_dir if File.exists?(@repo_dir)
68
68
  FileUtils.remove_entry_secure workdir if File.exists?(workdir)
69
- FileUtils.mkdir_p repo_dir
69
+ FileUtils.mkdir_p @repo_dir
70
+ FileUtils.mkdir_p workdir
70
71
  file = File.join(workdir, "package")
71
72
 
72
73
  @logger.operation(:downloading) do
73
74
  credential_command = if @repository.first_credential && @repository.second_credential
74
- ["-u", "#{@repository.first_credential}:#{@repository.second_credential}"]
75
+ ['-u', "#{@repository.first_credential}:#{@repository.second_credential}"]
75
76
  else
76
77
  []
77
78
  end
78
- ProcessWatcher.watch("curl", ["--silent", "--show-error", "--location", "--fail",
79
- "--location-trusted", "-o", file,
80
- credential_command, @repository.url].flatten,
81
- workdir, @max_bytes || -1, @max_seconds || -1) do |phase, command, exception|
82
- @logger.note_phase(phase, :running_command, command, exception)
79
+ @output = ::RightScale::RightPopen::SafeOutputBuffer.new
80
+ @cmd = [
81
+ 'curl',
82
+ '--silent', '--show-error', '--location', '--fail',
83
+ '--location-trusted', '-o', file, credential_command,
84
+ @repository.url
85
+ ].flatten
86
+ begin
87
+ ::RightScale::RightPopen.popen3_sync(
88
+ @cmd,
89
+ :target => self,
90
+ :pid_handler => :pid_download,
91
+ :timeout_handler => :timeout_download,
92
+ :size_limit_handler => :size_limit_download,
93
+ :exit_handler => :exit_download,
94
+ :stderr_handler => :output_download,
95
+ :stdout_handler => :output_download,
96
+ :inherit_io => true, # avoid killing any rails connection
97
+ :watch_directory => workdir,
98
+ :size_limit_bytes => @max_bytes,
99
+ :timeout_seconds => @max_seconds)
100
+ rescue Exception => e
101
+ @logger.note_phase(:abort, :running_command, 'curl', e)
102
+ raise
83
103
  end
84
104
  end
85
105
 
@@ -94,15 +114,58 @@ module RightScraper
94
114
  else
95
115
  extraction = "xf"
96
116
  end
97
- Dir.chdir(repo_dir) do
98
- ProcessWatcher.watch("tar", [extraction, file], repo_dir,
99
- @max_bytes || -1, @max_seconds || -1) do |phase, command, exception|
100
- @logger.note_phase(phase, :running_command, command, exception)
117
+ Dir.chdir(@repo_dir) do
118
+ @output = ::RightScale::RightPopen::SafeOutputBuffer.new
119
+ @cmd = ['tar', extraction, file]
120
+ begin
121
+ ::RightScale::RightPopen.popen3_sync(
122
+ @cmd,
123
+ :target => self,
124
+ :pid_handler => :pid_download,
125
+ :timeout_handler => :timeout_download,
126
+ :size_limit_handler => :size_limit_download,
127
+ :exit_handler => :exit_download,
128
+ :stderr_handler => :output_download,
129
+ :stdout_handler => :output_download,
130
+ :inherit_io => true, # avoid killing any rails connection
131
+ :watch_directory => @repo_dir,
132
+ :size_limit_bytes => @max_bytes,
133
+ :timeout_seconds => @max_seconds)
134
+ rescue Exception => e
135
+ @logger.note_phase(:abort, :running_command, @cmd.first, e)
136
+ raise
101
137
  end
102
138
  end
103
139
  end
104
140
  end
105
141
 
142
+ def pid_download(pid)
143
+ @logger.note_phase(:begin, :running_command, @cmd.first)
144
+ true
145
+ end
146
+
147
+ def output_download(data)
148
+ @output.safe_buffer_data(data)
149
+ end
150
+
151
+ def timeout_download
152
+ raise DownloadError, "Downloader timed out"
153
+ end
154
+
155
+ def size_limit_download
156
+ raise DownloadError, "Downloader exceeded size limit"
157
+ end
158
+
159
+ def exit_download(status)
160
+ unless status.success?
161
+ @output.safe_buffer_data("Exit code = #{status.exitstatus}")
162
+ raise DownloadError, "Downloader failed: #{@output.display_text}"
163
+ end
164
+ @logger.note_phase(:commit, :running_command, @cmd.first)
165
+ true
166
+ end
167
+
168
+
106
169
  # Amend @repository with the tag information from the downloaded
107
170
  # file.
108
171
  #
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright: Copyright (c) 2010-2011 RightScale, Inc.
2
+ # Copyright: Copyright (c) 2010-2013 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
@@ -23,6 +23,35 @@
23
23
 
24
24
  require 'tmpdir'
25
25
 
26
+ # TEAL FIX: figure out a way to do this monkey-patch without always rquiring the
27
+ # blackwinter gem and/or create a rightscale-git fork with this fix.
28
+ #
29
+ # ADDENDUM: we can't unconditionally require the git gem because git is not
30
+ # always available.
31
+ begin
32
+ require 'git'
33
+ require 'git/lib'
34
+
35
+ module Git
36
+ class Lib
37
+ # Monkey patch to blackwinter-git that strips ANSI escape sequences
38
+ # from command output to avoid confusing the parser.
39
+ def run_command_with_color_stripping(git_cmd, &block)
40
+ out = run_command_without_color_stripping(git_cmd, &block)
41
+ out.gsub!(/\e\[[^m]*m/, '')
42
+ out
43
+ end
44
+
45
+ unless self.methods.include?('run_command_without_color_stripping')
46
+ alias :run_command_without_color_stripping :run_command
47
+ alias :run_command :run_command_with_color_stripping
48
+ end
49
+ end
50
+ end
51
+ rescue ::Git::GitExecuteError
52
+ # silently ignore git gem's failed attempt to execute git on load.
53
+ end
54
+
26
55
  module RightScraper
27
56
  module Retrievers
28
57
  # Retriever for resources stored in a git repository.
@@ -33,7 +62,6 @@ module RightScraper
33
62
  def available?
34
63
  unless @@available
35
64
  begin
36
- require 'git'
37
65
  # note that require 'git' does the same version check on load but
38
66
  # we don't want to assume any particular implementation.
39
67
  #
@@ -95,7 +123,13 @@ module RightScraper
95
123
  def do_update
96
124
  git = ::Git.open(@repo_dir)
97
125
  do_fetch(git)
98
- git.reset_hard
126
+ @logger.operation(:cleanup, "ensure no untracked files in #{@repo_dir}") do
127
+ git.reset_hard
128
+ Dir.chdir(@repo_dir) do
129
+ # ignore outcome; there is no way to record 'warnings'
130
+ system("git clean -f")
131
+ end
132
+ end
99
133
  do_checkout_revision(git)
100
134
  do_update_tag(git)
101
135
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright: Copyright (c) 2010-2011 RightScale, Inc.
2
+ # Copyright: Copyright (c) 2010-2013 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
@@ -22,8 +22,6 @@
22
22
  #++
23
23
  require File.join(File.dirname(__FILE__), '..', 'svn_client')
24
24
 
25
- require 'process_watcher'
26
-
27
25
  module RightScraper
28
26
  module Retrievers
29
27
  # Retriever for svn repositories
@@ -37,17 +35,10 @@ module RightScraper
37
35
  def available?
38
36
  unless @@available
39
37
  begin
40
- # FIX: we might want to parse the result and require a minimum svn
41
- # client version.
42
- cmd = "svn --version"
43
- `#{cmd}`
44
- if $?.success?
45
- @@available = true
46
- else
47
- raise RetrieverError, "\"#{cmd}\" exited with #{$?.exitstatus}"
48
- end
49
- rescue
50
- @logger.note_error($!, :available, "svn retriever is unavailable")
38
+ calculate_version
39
+ @@available = true
40
+ rescue SvnClientError => e
41
+ @logger.note_error(e, :available, "svn retriever is unavailable")
51
42
  end
52
43
  end
53
44
  @@available
@@ -81,8 +72,8 @@ module RightScraper
81
72
  # pick out the first tag.
82
73
  def do_update_tag
83
74
  @repository = @repository.clone
84
- log = run_svn("log", "-r", 'HEAD')
85
- log.split(/\n/).each do |line|
75
+ lines = run_svn_with_buffered_output("log", "-r", 'HEAD')
76
+ lines.each do |line|
86
77
  if line =~ /^r(\d+)/
87
78
  @repository.tag = $1
88
79
  break
@@ -22,7 +22,7 @@
22
22
  #++
23
23
 
24
24
  require File.expand_path(File.join(File.dirname(__FILE__), 'base'))
25
- require 'digest/sha1'
25
+ require 'digest/md5'
26
26
 
27
27
  module RightScraper
28
28
  module Scanners
@@ -52,7 +52,7 @@ module RightScraper
52
52
  # === Parameters ===
53
53
  # relative_position(String):: relative pathname for file from root of resource
54
54
  def notice(relative_position)
55
- @manifest[relative_position] = Digest::SHA1.hexdigest(yield)
55
+ @manifest[relative_position] = Digest::MD5.hexdigest(yield)
56
56
  end
57
57
  end
58
58
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright: Copyright (c) 2010-2011 RightScale, Inc.
2
+ # Copyright: Copyright (c) 2010-2012 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
@@ -22,6 +22,7 @@
22
22
  #++
23
23
  require 'right_aws'
24
24
  require 'json'
25
+ require 'digest/md5'
25
26
 
26
27
  module RightScraper
27
28
  module Scanners
@@ -56,11 +57,11 @@ module RightScraper
56
57
  # === Parameters
57
58
  # cookbook(RightScraper::Cookbook):: cookbook to scan
58
59
  def end(cookbook)
59
- @bucket.put(File.join('Cooks', cookbook.resource_hash),
60
- {
61
- :metadata => cookbook.metadata,
62
- :manifest => cookbook.manifest
63
- }.to_json)
60
+ path = File.join('Cooks', cookbook.resource_hash)
61
+ unless @bucket.key(path).exists?
62
+ contents = cookbook.manifest_json
63
+ @bucket.put(path, contents)
64
+ end
64
65
  end
65
66
 
66
67
  # Upload a file during scanning.
@@ -73,7 +74,7 @@ module RightScraper
73
74
  # relative_position(String):: relative pathname for file from root of cookbook
74
75
  def notice(relative_position)
75
76
  contents = yield
76
- name = Digest::SHA1.hexdigest(contents)
77
+ name = Digest::MD5.hexdigest(contents)
77
78
  path = File.join('Files', name)
78
79
  unless @bucket.key(path).exists?
79
80
  @bucket.put(path, contents)