Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 39 additions & 17 deletions lib/sqldef.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
require 'stringio'
require 'uri'
require 'zlib'
require 'zip'
require_relative 'sqldef/version'

module Sqldef
Expand All @@ -24,6 +25,13 @@ module Sqldef
]
private_constant :COMMANDS

OS_ARCHIVE = {
'linux' => 'tar.gz',
'windows' => 'zip',
'darwin' => 'zip',
}
private_constant :OS_ARCHIVE

@bin = Dir.pwd

class << self
Expand Down Expand Up @@ -79,16 +87,24 @@ def download(command)
return path if File.executable?(path)

print("Downloading '#{command}' under '#{bin}'... ")
resp = get(build_url(command), code: 302) # Latest
resp = get(resp['location'], code: 302) # vX.Y.Z
resp = get(resp['location'], code: 200) # Binary

gzip = Zlib::GzipReader.new(StringIO.new(resp.body))
Gem::Package::TarReader.new(gzip) do |tar|
unless file = tar.find { |f| f.full_name == command }
raise "'#{command}' was not found in the archive"
url = build_url(command)
resp = get(url, code: 200, max_retries: 4)

if url.end_with?('.zip')
Zip::File.open_buffer(resp.body) do |zip|
unless entry = zip.find_entry(command)
raise "'#{command}' was not found in the archive"
end
File.binwrite(path, zip.read(entry))
end
else
gzip = Zlib::GzipReader.new(StringIO.new(resp.body))
Gem::Package::TarReader.new(gzip) do |tar|
unless file = tar.find { |f| f.full_name == command }
raise "'#{command}' was not found in the archive"
end
File.binwrite(path, file.read)
end
File.binwrite(path, file.read)
end

FileUtils.chmod('+x', path)
Expand All @@ -109,20 +125,26 @@ def build_url(command)
raise "Unexpected sqldef command: #{command}"
end
os = Etc.uname.fetch(:sysname).downcase
arch = GOARCH.fetch(Etc.uname.fetch(:machine))
"https://github.com/k0kubun/sqldef/releases/latest/download/#{command}_#{os}_#{arch}.tar.gz"
archive = OS_ARCHIVE.fetch(os)
arch = Etc.uname.fetch(:machine)
goarch = GOARCH.fetch(arch, arch)
"https://github.com/sqldef/sqldef/releases/latest/download/#{command}_#{os}_#{goarch}.#{archive}"
end

# TODO: Retry transient errors
def get(url, code: nil)
def get(url, code: nil, max_retries:)
uri = URI.parse(url)
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
resp = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.get("#{uri.path}?#{uri.query}")
end.tap do |resp|
if code && resp.code != code.to_s
raise "Expected '#{url}' to return #{code}, but got #{resp.code}: #{resp.body}"
end
end
if resp.is_a?(Net::HTTPRedirection) && max_retries > 0
# Follow redirects that lead to the current repository (if sqldef/sqldef is moved),
# Latest, vX.Y.Z, and to the binary
return get(resp['location'], code: code, max_retries: max_retries - 1)
elsif code && resp.code != code.to_s
raise "Expected '#{url}' to return #{code}, but got #{resp.code}: #{resp.body}"
end
resp
end
end
end
2 changes: 2 additions & 0 deletions sqldef.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Gem::Specification.new do |spec|
spec.metadata['homepage_uri'] = spec.homepage
spec.metadata['source_code_uri'] = spec.homepage

spec.add_runtime_dependency 'rubyzip'

# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path(__dir__)) do
Expand Down