Document download strategies.

This commit is contained in:
Markus Reiter 2020-08-26 10:50:34 +02:00
parent 5cd8b609f7
commit d558b9f9e2
2 changed files with 105 additions and 15 deletions

View File

@ -8,7 +8,6 @@ Style/Documentation:
- 'cask/macos.rb'
- 'cli/args.rb'
- 'cli/parser.rb'
- 'download_strategy.rb'
- 'global.rb'
- 'keg_relocate.rb'
- 'os/linux/global.rb'

View File

@ -10,11 +10,17 @@ require "lock_file"
require "mechanize/version"
require "mechanize/http/content_disposition_parser"
# @abstract Abstract superclass for all download strategies.
#
# @api private
class AbstractDownloadStrategy
extend Forwardable
include FileUtils
include Context
# Extension for bottle downloads.
#
# @api private
module Pourable
def stage
ohai "Pouring #{basename}"
@ -35,25 +41,25 @@ class AbstractDownloadStrategy
extend Pourable if meta[:bottle]
end
# Download and cache the resource as {#cached_location}.
# Download and cache the resource at {#cached_location}.
#
# @api public
def fetch; end
# Disable any output during downloading.
#
# TODO: Deprecate once we have an explicitly documented alternative.
#
# @api public
def shutup!
@quiet = true
end
def puts(*args)
super(*args) unless quiet?
end
def ohai(*args)
super(*args) unless quiet?
end
# Unpack {#cached_location} into the current working directory, and possibly
# chdir into the newly-unpacked directory.
# Unlike {Resource#stage}, this does not take a block.
#
# @api public
def stage
UnpackStrategy.detect(cached_location,
prioritise_extension: true,
@ -79,12 +85,16 @@ class AbstractDownloadStrategy
# @!attribute [r] source_modified_time
# Returns the most recent modified time for all files in the current working directory after stage.
#
# @api public
def source_modified_time
Pathname.pwd.to_enum(:find).select(&:file?).map(&:mtime).max
end
# Remove {#cached_location} and any other files associated with the resource
# from the cache.
#
# @api public
def clear_cache
rm_rf(cached_location)
end
@ -95,6 +105,14 @@ class AbstractDownloadStrategy
private
def puts(*args)
super(*args) unless quiet?
end
def ohai(*args)
super(*args) unless quiet?
end
def system_command(*args, **options)
super(*args, print_stderr: false, env: env, **options)
end
@ -115,6 +133,9 @@ class AbstractDownloadStrategy
end
end
# @abstract Abstract superclass for all download strategies downloading from a version control system.
#
# @api private
class VCSDownloadStrategy < AbstractDownloadStrategy
REF_TYPES = [:tag, :branch, :revisions, :revision].freeze
@ -125,6 +146,9 @@ class VCSDownloadStrategy < AbstractDownloadStrategy
@cached_location = @cache/"#{name}--#{cache_tag}"
end
# Download and cache the repository at {#cached_location}.
#
# @api public
def fetch
ohai "Cloning #{url}"
@ -167,6 +191,8 @@ class VCSDownloadStrategy < AbstractDownloadStrategy
# Return last commit's unique identifier for the repository.
# Return most recent modified timestamp unless overridden.
#
# @api public
def last_commit
source_modified_time.to_i.to_s
end
@ -193,11 +219,21 @@ class VCSDownloadStrategy < AbstractDownloadStrategy
end
end
# @abstract Abstract superclass for all download strategies downloading a single file.
#
# @api private
class AbstractFileDownloadStrategy < AbstractDownloadStrategy
# Path for storing an incomplete download while the download is still in progress.
#
# @api public
def temporary_path
@temporary_path ||= Pathname.new("#{cached_location}.incomplete")
end
# Path of the symlink (whose name includes the resource name, version and extension)
# pointing to {#cached_location}.
#
# @api public
def symlink_location
return @symlink_location if defined?(@symlink_location)
@ -205,6 +241,9 @@ class AbstractFileDownloadStrategy < AbstractDownloadStrategy
@symlink_location = @cache/"#{name}--#{version}#{ext}"
end
# Path for storing the completed download .
#
# @api public
def cached_location
return @cached_location if defined?(@cached_location)
@ -273,6 +312,9 @@ class AbstractFileDownloadStrategy < AbstractDownloadStrategy
end
end
# Strategy for downloading files using `curl`.
#
# @api public
class CurlDownloadStrategy < AbstractFileDownloadStrategy
attr_reader :mirrors
@ -281,6 +323,9 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
@mirrors = meta.fetch(:mirrors, [])
end
# Download and cache the file at {#cached_location}.
#
# @api public
def fetch
download_lock = LockFile.new(temporary_path.basename)
download_lock.lock
@ -443,7 +488,9 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
end
end
# Detect and download from Apache Mirror.
# Strategy for downloading a file from an Apache Mirror URL.
#
# @api public
class CurlApacheMirrorDownloadStrategy < CurlDownloadStrategy
def mirrors
return @combined_mirrors if defined?(@combined_mirrors)
@ -474,8 +521,10 @@ class CurlApacheMirrorDownloadStrategy < CurlDownloadStrategy
end
end
# Download via an HTTP POST.
# Strategy for downloading via an HTTP POST request using `curl`.
# Query parameters on the URL are converted into POST parameters.
#
# @api public
class CurlPostDownloadStrategy < CurlDownloadStrategy
private
@ -492,8 +541,10 @@ class CurlPostDownloadStrategy < CurlDownloadStrategy
end
end
# Use this strategy to download but not unzip a file.
# Useful for installing jars.
# Strategy for downloading archives without automatically extracting them.
# (Useful for downloading `.jar` files.)
#
# @api public
class NoUnzipCurlDownloadStrategy < CurlDownloadStrategy
def stage
UnpackStrategy::Uncompressed.new(cached_location)
@ -502,19 +553,27 @@ class NoUnzipCurlDownloadStrategy < CurlDownloadStrategy
end
end
# This strategy extracts local binary packages.
# Strategy for extracting local binary packages.
#
# @api private
class LocalBottleDownloadStrategy < AbstractFileDownloadStrategy
def initialize(path) # rubocop:disable Lint/MissingSuper
@cached_location = path
end
end
# Strategy for downloading a Subversion repository.
#
# @api public
class SubversionDownloadStrategy < VCSDownloadStrategy
def initialize(url, name, version, **meta)
super
@url = @url.sub("svn+http://", "")
end
# Download and cache the repository at {#cached_location}.
#
# @api public
def fetch
if @url.chomp("/") != repo_url || !system_command("svn", args: ["switch", @url, cached_location]).success?
clear_cache
@ -522,6 +581,7 @@ class SubversionDownloadStrategy < VCSDownloadStrategy
super
end
# (see AbstractDownloadStrategy#source_modified_time)
def source_modified_time
time = if Version.create(Utils::Svn.version) >= Version.create("1.9")
out, = system_command("svn", args: ["info", "--show-item", "last-changed-date"], chdir: cached_location)
@ -533,6 +593,7 @@ class SubversionDownloadStrategy < VCSDownloadStrategy
Time.parse time
end
# (see VCSDownloadStrategy#source_modified_time)
def last_commit
out, = system_command("svn", args: ["info", "--show-item", "revision"], chdir: cached_location)
out.strip
@ -606,6 +667,9 @@ class SubversionDownloadStrategy < VCSDownloadStrategy
alias update clone_repo
end
# Strategy for downloading a Git repository.
#
# @api public
class GitDownloadStrategy < VCSDownloadStrategy
SHALLOW_CLONE_ALLOWLIST = [
%r{git://},
@ -621,11 +685,13 @@ class GitDownloadStrategy < VCSDownloadStrategy
@shallow = meta.fetch(:shallow, true)
end
# (see AbstractDownloadStrategy#source_modified_time)
def source_modified_time
out, = system_command("git", args: ["--git-dir", git_dir, "show", "-s", "--format=%cD"])
Time.parse(out)
end
# (see VCSDownloadStrategy#source_modified_time)
def last_commit
out, = system_command("git", args: ["--git-dir", git_dir, "rev-parse", "--short=7", "HEAD"])
out.chomp
@ -803,6 +869,9 @@ class GitDownloadStrategy < VCSDownloadStrategy
end
end
# Strategy for downloading a Git repository from GitHub.
#
# @api public
class GitHubGitDownloadStrategy < GitDownloadStrategy
def initialize(url, name, version, **meta)
super
@ -859,6 +928,9 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy
end
end
# Strategy for downloading a CVS repository.
#
# @api public
class CVSDownloadStrategy < VCSDownloadStrategy
def initialize(url, name, version, **meta)
super
@ -873,6 +945,7 @@ class CVSDownloadStrategy < VCSDownloadStrategy
end
end
# (see AbstractDownloadStrategy#source_modified_time)
def source_modified_time
# Filter CVS's files because the timestamp for each of them is the moment
# of clone.
@ -928,12 +1001,16 @@ class CVSDownloadStrategy < VCSDownloadStrategy
end
end
# Strategy for downloading a Mercurial repository.
#
# @api public
class MercurialDownloadStrategy < VCSDownloadStrategy
def initialize(url, name, version, **meta)
super
@url = @url.sub(%r{^hg://}, "")
end
# (see AbstractDownloadStrategy#source_modified_time)
def source_modified_time
out, = system_command("hg",
args: ["tip", "--template", "{date|isodate}", "-R", cached_location])
@ -941,6 +1018,7 @@ class MercurialDownloadStrategy < VCSDownloadStrategy
Time.parse(out)
end
# (see VCSDownloadStrategy#source_modified_time)
def last_commit
out, = system_command("hg", args: ["parent", "--template", "{node|short}", "-R", cached_location])
out.chomp
@ -978,12 +1056,16 @@ class MercurialDownloadStrategy < VCSDownloadStrategy
end
end
# Strategy for downloading a Bazaar repository.
#
# @api public
class BazaarDownloadStrategy < VCSDownloadStrategy
def initialize(url, name, version, **meta)
super
@url.sub!(%r{^bzr://}, "")
end
# (see AbstractDownloadStrategy#source_modified_time)
def source_modified_time
out, = system_command("bzr", args: ["log", "-l", "1", "--timezone=utc", cached_location])
timestamp = out.chomp
@ -992,6 +1074,7 @@ class BazaarDownloadStrategy < VCSDownloadStrategy
Time.parse(timestamp)
end
# (see VCSDownloadStrategy#source_modified_time)
def last_commit
out, = system_command("bzr", args: ["revno", cached_location])
out.chomp
@ -1027,17 +1110,22 @@ class BazaarDownloadStrategy < VCSDownloadStrategy
end
end
# Strategy for downloading a Fossil repository.
#
# @api public
class FossilDownloadStrategy < VCSDownloadStrategy
def initialize(url, name, version, **meta)
super
@url = @url.sub(%r{^fossil://}, "")
end
# (see AbstractDownloadStrategy#source_modified_time)
def source_modified_time
out, = system_command("fossil", args: ["info", "tip", "-R", cached_location])
Time.parse(out[/^uuid: +\h+ (.+)$/, 1])
end
# (see VCSDownloadStrategy#source_modified_time)
def last_commit
out, = system_command("fossil", args: ["info", "tip", "-R", cached_location])
out[/^uuid: +(\h+) .+$/, 1]
@ -1066,6 +1154,9 @@ class FossilDownloadStrategy < VCSDownloadStrategy
end
end
# Helper class for detecting a download strategy from a URL.
#
# @api private
class DownloadStrategyDetector
def self.detect(url, using = nil)
if using.nil?