class Berkshelf::CommunityREST

Constants

V1_API

Attributes

api_uri[R]

@return [String]

connection[R]

@return [Berkshelf::RidleyCompat]

retries[R]

@return [Integer]

how many retries to attempt on HTTP requests
retry_interval[R]

@return [Float]

time to wait between retries

Public Class Methods

new(uri = V1_API, options = {}) click to toggle source

@param [String] uri (CommunityREST::V1_API)

location of community site to connect to

@option options [Integer] :retries (5)

retry requests on 5XX failures

@option options [Float] :retry_interval (0.5)

how often we should pause between retries
# File lib/berkshelf/community_rest.rb, line 70
def initialize(uri = V1_API, options = {})
  options = options.dup
  options = { retries: 5, retry_interval: 0.5, ssl: Berkshelf::Config.instance.ssl }.merge(options)
  @api_uri = uri
  options[:server_url] = uri
  @retries = options.delete(:retries)
  @retry_interval = options.delete(:retry_interval)

  @connection = Berkshelf::RidleyCompatJSON.new(**options)
end
unpack(target, destination) click to toggle source

@param [String] target

file path to the tar.gz archive on disk

@param [String] destination

file path to extract the contents of the target to

@return [String]

# File lib/berkshelf/community_rest.rb, line 13
def unpack(target, destination)
  if is_gzip_file(target) || is_tar_file(target)
    Mixlib::Archive.new(target).extract(destination)
  else
    raise Berkshelf::UnknownCompressionType.new(target, destination)
  end

  destination
end
uri_escape_version(version) click to toggle source

@param [String] version

@return [String]

# File lib/berkshelf/community_rest.rb, line 26
def uri_escape_version(version)
  version.to_s.tr(".", "_")
end
version_from_uri(uri) click to toggle source

@param [String] uri

@return [String]

# File lib/berkshelf/community_rest.rb, line 33
def version_from_uri(uri)
  File.basename(uri.to_s).tr("_", ".")
end

Private Class Methods

is_gzip_file(path) click to toggle source
# File lib/berkshelf/community_rest.rb, line 39
def is_gzip_file(path)
  # You cannot write "\x1F\x8B" because the default encoding of
  # ruby >= 1.9.3 is UTF-8 and 8B is an invalid in UTF-8.
  IO.binread(path, 2) == [0x1F, 0x8B].pack("C*")
end
is_tar_file(path) click to toggle source
# File lib/berkshelf/community_rest.rb, line 45
def is_tar_file(path)
  IO.binread(path, 8, 257).to_s == "ustar\x0000"
end

Public Instance Methods

download(name, version) click to toggle source

Download and extract target cookbook archive to the local file system, returning its filepath.

@param [String] name

the name of the cookbook

@param [String] version

the targeted version of the cookbook

@return [String, nil]

cookbook filepath, or nil if archive does not contain a cookbook
# File lib/berkshelf/community_rest.rb, line 91
def download(name, version)
  archive = stream(find(name, version)["file"])
  scratch = Dir.mktmpdir
  extracted = self.class.unpack(archive.path, scratch)

  if File.cookbook?(extracted)
    extracted
  else
    Dir.glob("#{extracted}/*").find do |dir|
      File.cookbook?(dir)
    end
  end
ensure
  archive.unlink unless archive.nil?
end
find(name, version) click to toggle source
# File lib/berkshelf/community_rest.rb, line 107
def find(name, version)
  body = connection.get("cookbooks/#{name}/versions/#{self.class.uri_escape_version(version)}")

  # Artifactory responds with a 200 and blank body for unknown cookbooks.
  raise CookbookNotFound.new(name, nil, "at `#{api_uri}'") if body.nil?

  body
rescue CookbookNotFound
  raise
rescue Berkshelf::APIClient::ServiceNotFound
  raise CookbookNotFound.new(name, nil, "at `#{api_uri}'")
rescue
  raise CommunitySiteError.new(api_uri, "'#{name}' (#{version})")
end
latest_version(name) click to toggle source

Returns the latest version of the cookbook and its download link.

@return [String]

# File lib/berkshelf/community_rest.rb, line 125
def latest_version(name)
  body = connection.get("cookbooks/#{name}")

  # Artifactory responds with a 200 and blank body for unknown cookbooks.
  raise CookbookNotFound.new(name, nil, "at `#{api_uri}'") if body.nil?

  self.class.version_from_uri body["latest_version"]
rescue Berkshelf::APIClient::ServiceNotFound
  raise CookbookNotFound.new(name, nil, "at `#{api_uri}'")
rescue
  raise CommunitySiteError.new(api_uri, "the latest version of '#{name}'")
end
satisfy(name, constraint) click to toggle source

@param [String] name @param [String, Semverse::Constraint] constraint

@return [String]

# File lib/berkshelf/community_rest.rb, line 161
def satisfy(name, constraint)
  Semverse::Constraint.satisfy_best(constraint, versions(name)).to_s
rescue Semverse::NoSolutionError
  nil
end
stream(target) click to toggle source

Stream the response body of a remote URL to a file on the local file system

@param [String] target

a URL to stream the response body from

@return [Tempfile]

# File lib/berkshelf/community_rest.rb, line 173
def stream(target)
  local = Tempfile.new("community-rest-stream")
  local.binmode
  Retryable.retryable(tries: retries, on: Berkshelf::APIClientError, sleep: retry_interval) do
    connection.streaming_request(target, {}, local)
  end
ensure
  local.close(false) unless local.nil?
end
versions(name) click to toggle source

@param [String] name

@return [Array]

# File lib/berkshelf/community_rest.rb, line 141
def versions(name)
  body = connection.get("cookbooks/#{name}")

  # Artifactory responds with a 200 and blank body for unknown cookbooks.
  raise CookbookNotFound.new(name, nil, "at `#{api_uri}'") if body.nil?

  body["versions"].collect do |version_uri|
    self.class.version_from_uri(version_uri)
  end

rescue Berkshelf::APIClient::ServiceNotFound
  raise CookbookNotFound.new(name, nil, "at `#{api_uri}'")
rescue
  raise CommunitySiteError.new(api_uri, "versions of '#{name}'")
end