wip: extract tarball downloading into separate command

This commit is contained in:
2021-04-09 00:38:35 +01:00
parent 2054c8c0aa
commit 9c977a75b5
7 changed files with 258 additions and 0 deletions

46
bin/download-tarball Executable file
View File

@@ -0,0 +1,46 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'optparse'
require_relative '../lib/download_tarball'
require_relative '../lib/errors'
options = {
repo: 'emacs-mirror/emacs',
output: File.expand_path('../tarballs', __dir__),
log_level: :info
}
OptionParser.new do |opts|
opts.banner = <<~TXT
Usage: ./download-tarball [options] <branch/tag/sha>
Download a tarball of given GitHub repository branch, tag, or SHA.
Options:
TXT
opts.on('-r', '--repo STRING',
"GitHub repository (default: #{options[:repo]})") do |v|
options[:repo] = v
end
opts.on('-o', '--output DIR', 'Directory to save tarball in ' \
"(default: #{options[:output]})") do |v|
options[:output] = v
end
opts.on('-l', '--log-level LEVEL', 'Log level ' \
"(default: #{options[:log_level]})") do |v|
options[:log_level] = v.to_sym
end
end.parse!
begin
tarball = DownloadTarball.new(ref: ARGV[0], **options).perform
puts tarball.to_yaml
rescue Error => e
handle_error(e)
end

29
lib/commit.rb Normal file
View File

@@ -0,0 +1,29 @@
# frozen_string_literal: true
require 'yaml'
class Commit
attr_reader :sha
attr_reader :time
def initialize(sha:, time:)
@sha = sha
@time = time
end
def sha_short
sha[0..6]
end
def to_hash
{
'sha' => sha,
'sha_short' => sha_short,
'time' => time
}
end
def to_yaml
to_hash.to_yaml
end
end

19
lib/common.rb Normal file
View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
require 'net/http'
module Common
private
def run_cmd(*args)
info "executing: #{args.join(' ')}"
system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}")
end
def http_get(url)
response = Net::HTTP.get_response(URI.parse(url))
return unless response.code == '200'
response.body
end
end

83
lib/download_tarball.rb Normal file
View File

@@ -0,0 +1,83 @@
# frozen_string_literal: true
require 'fileutils'
require 'json'
require 'time'
require_relative './common'
require_relative './commit'
require_relative './output'
require_relative './tarball'
class DownloadTarball
include Common
include Output
logger_name 'download-tarball'
TARBALL_URL = 'https://github.com/%s/tarball/%s'
COMMIT_URL = 'https://api.github.com/repos/%s/commits/%s'
attr_reader :ref
attr_reader :repo
attr_reader :output
attr_reader :log_level
def initialize(ref:, repo:, output:, log_level:)
@ref = ref
@repo = repo
@output = output
@log_level = log_level
err 'branch/tag/sha argument cannot be empty' if ref.nil? || ref.empty?
end
def perform
FileUtils.mkdir_p(output)
tarball = Tarball.new(file: target, commit: commit)
if File.exist?(target)
info "#{filename} already exists locally, attempting to use."
return tarball
end
info 'Downloading tarball from GitHub. This could take a while, ' \
'please be patient.'
result = run_cmd('curl', '-L', url, '-o', target)
err 'Download failed.' if !result || !File.exist?(target)
tarball
end
def url
@url ||= format(TARBALL_URL, repo, commit.sha)
end
def filename
@filename ||= "#{repo.gsub(/[^\w]/, '-')}-#{commit.sha_short}.tgz"
end
def target
@target ||= File.join(output, filename)
end
def commit
return @commit if @commit
info "Fetching info for git ref: #{ref}"
url = format(COMMIT_URL, repo, ref)
commit_json = http_get(url)
err "Failed to get commit info about: #{ref}" if commit_json.nil?
parsed = JSON.parse(commit_json)
commit = Commit.new(
sha: parsed&.dig('sha'),
time: Time.parse(parsed&.dig('commit', 'committer', 'date'))
)
err 'Failed to get commit SHA' if commit.sha.nil? || commit.sha.empty?
err 'Failed to get commit time' if commit.time.nil?
@commit = commit
end
end

8
lib/errors.rb Normal file
View File

@@ -0,0 +1,8 @@
# frozen_string_literal: true
def handle_error(err)
warn "ERROR: #{err.message}"
Process.exit 1
end
class Error < StandardError; end

49
lib/output.rb Normal file
View File

@@ -0,0 +1,49 @@
# frozen_string_literal: true
require 'forwardable'
require 'logger'
require_relative './errors'
module Output
extend Forwardable
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def logger_name(name = nil)
return @logger_name if name.nil?
@logger_name = name
end
end
def_delegators :logger, :debug, :info, :warn, :error, :fatal, :unkonwn
def err(msg = nil)
raise Error, msg
end
private
# override to set custom log level
def log_level
:info
end
def logger
@logger ||= Logger.new($stderr).tap do |l|
l.progname = self.class.logger_name
l.level = log_level
l.formatter = log_formatter
end
end
def log_formatter
proc do |severity, _datetime, progname, msg|
"==> [#{progname}] #{severity}: #{msg}\n"
end
end
end

24
lib/tarball.rb Normal file
View File

@@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'yaml'
class Tarball
attr_reader :file
attr_reader :commit
def initialize(file:, commit:)
@file = file
@commit = commit
end
def to_hash
{
'file' => file,
'commit' => commit.to_hash
}
end
def to_yaml
to_hash.to_yaml
end
end