Skip to content

Commit

Permalink
Merge pull request #585 from heroku/retry-failed-downloads
Browse files Browse the repository at this point in the history
Retry failed downlads for untar
  • Loading branch information
schneems authored Jul 26, 2017
2 parents a46dcce + 68e9d32 commit cebdf68
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 21 deletions.
4 changes: 3 additions & 1 deletion lib/language_pack/fetcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ def fetch(path)

def fetch_untar(path, files_to_extract = nil)
curl = curl_command("#{@host_url.join(path)} -s -o")
run!("#{curl} - | tar zxf - #{files_to_extract}", error_class: FetchError)
run! "#{curl} - | tar zxf - #{files_to_extract}",
error_class: FetchError,
max_attempts: 3
end

def fetch_bunzip2(path, files_to_extract = nil)
Expand Down
23 changes: 17 additions & 6 deletions lib/language_pack/shell_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,25 @@ def self.initialize_env(path)
end
end

# run a shell command (deferring to #run), and raise an error if it fails
# @param [String] command to be run
# @return [String] result of #run
# @option options [Error] :error_class Class of error to raise, defaults to Standard Error
# @option options [Integer] :max_attempts Number of times to attempt command before raising
def run!(command, options = {})
result = run(command, options)
error_class = options.delete(:error_class) || StandardError
unless $?.success?
message = "Command: '#{command}' failed unexpectedly:\n#{result}"
raise error_class, message
max_attempts = options[:max_attempts] || 1
error_class = options[:error_class] || StandardError
max_attempts.times do |attempt_number|
result = run(command, options)
if $?.success?
return result
end
if attempt_number == max_attempts - 1
raise error_class, "Command: '#{command}' failed unexpectedly:\n#{result}"
else
puts "Command: '#{command}' failed on attempt #{attempt_number + 1} of #{max_attempts}."
end
end
return result
end

# doesn't do any special piping. stderr won't be redirected.
Expand Down
49 changes: 35 additions & 14 deletions spec/helpers/shell_spec.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,44 @@
require 'spec_helper'

describe "ShellHelpers" do
module RecordPuts
attr_reader :puts_calls
def puts(*args)
@puts_calls ||= []
@puts_calls << args
end
end

class FakeShell
include LanguagePack::ShellHelpers
end
class FakeShell
include RecordPuts
include LanguagePack::ShellHelpers
end

describe "#command_options_to_string" do
it "formats ugly keys correctly" do
env = {%Q{ un"matched } => "bad key"}
result = FakeShell.new.command_options_to_string("bundle install", env: env)
expected = %r{env \\ un\\\"matched\\ =bad\\ key bash -c bundle\\ install 2>&1}
expect(result.strip).to match(expected)
end

describe "ShellHelpers" do
it "format ugly keys correctly" do
env = {%Q{ un"matched } => "bad key"}
result = FakeShell.new.command_options_to_string("bundle install", env: env)
expected = %r{env \\ un\\\"matched\\ =bad\\ key bash -c bundle\\ install 2>&1}
expect(result.strip).to match(expected)
it "formats ugly values correctly" do
env = {"BAD VALUE" => %Q{ )(*&^%$#'$'\n''@!~\'\ }}
result = FakeShell.new.command_options_to_string("bundle install", env: env)
expected = %r{env BAD\\ VALUE=\\ \\\)\\\(\\\*\\&\\\^\\%\\\$\\#\\'\\\$\\''\n'\\'\\'@\\!\\~\\'\\ bash -c bundle\\ install 2>&1}
expect(result.strip).to match(expected)
end
end

it "formats ugly values correctly" do
env = {"BAD VALUE" => %Q{ )(*&^%$#'$'\n''@!~\'\ }}
result = FakeShell.new.command_options_to_string("bundle install", env: env)
expected = %r{env BAD\\ VALUE=\\ \\\)\\\(\\\*\\&\\\^\\%\\\$\\#\\'\\\$\\''\n'\\'\\'@\\!\\~\\'\\ bash -c bundle\\ install 2>&1}
expect(result.strip).to match(expected)
describe "#run!" do
it "retries failed commands when passed max_attempts: > 1" do
sh = FakeShell.new
expect { sh.run!("false", max_attempts: 3) }.to raise_error(StandardError)

expect(sh.puts_calls).to eq([
[" Command: 'false' failed on attempt 1 of 3."],
[" Command: 'false' failed on attempt 2 of 3."],
])
end
end
end

0 comments on commit cebdf68

Please sign in to comment.