class Jekyll::RemoteTheme::Downloader

Constants

MAX_FILE_SIZE
NET_HTTP_ERRORS
PROJECT_URL
USER_AGENT

Attributes

theme[R]

Public Class Methods

new(theme) click to toggle source
# File lib/jekyll-remote-theme/downloader.rb, line 14
def initialize(theme)
  @theme = theme
end

Public Instance Methods

downloaded?() click to toggle source
# File lib/jekyll-remote-theme/downloader.rb, line 28
def downloaded?
  @downloaded ||= theme_dir_exists? && !theme_dir_empty?
end
run() click to toggle source
# File lib/jekyll-remote-theme/downloader.rb, line 18
def run
  if downloaded?
    Jekyll.logger.debug LOG_KEY, "Using existing #{theme.name_with_owner}"
    return
  end

  download
  unzip
end

Private Instance Methods

download() click to toggle source
# File lib/jekyll-remote-theme/downloader.rb, line 40
def download
  Jekyll.logger.debug LOG_KEY, "Downloading #{zip_url} to #{zip_file.path}"
  Net::HTTP.start(zip_url.host, zip_url.port, :use_ssl => true) do |http|
    http.request(request) do |response|
      raise_unless_sucess(response)
      enforce_max_file_size(response.content_length)
      response.read_body do |chunk|
        zip_file.write chunk
      end
    end
  end
  @downloaded = true
rescue *NET_HTTP_ERRORS => e
  raise DownloadError, e.message
end
enforce_max_file_size(size) click to toggle source
# File lib/jekyll-remote-theme/downloader.rb, line 70
def enforce_max_file_size(size)
  return unless size && size > MAX_FILE_SIZE

  raise DownloadError, "Maximum file size of #{MAX_FILE_SIZE} bytes exceeded"
end
path_without_name_and_ref(path) click to toggle source

Codeload generated zip files contain a top level folder in the form of THEME_NAME-GIT_REF/. While requests for Git repos are case insensitive, the zip subfolder will respect the case in the repository's name, thus making it impossible to predict the true path to the theme. In case we're on a case-sensitive file system, strip the parent folder from all paths.

# File lib/jekyll-remote-theme/downloader.rb, line 112
def path_without_name_and_ref(path)
  Jekyll.sanitized_path theme.root, path.split("/").drop(1).join("/")
end
raise_unless_sucess(response) click to toggle source
# File lib/jekyll-remote-theme/downloader.rb, line 64
def raise_unless_sucess(response)
  return if response.is_a?(Net::HTTPSuccess)

  raise DownloadError, "#{response.code} - #{response.message} - Loading URL: #{zip_url}"
end
request() click to toggle source
# File lib/jekyll-remote-theme/downloader.rb, line 56
def request
  return @request if defined? @request

  @request = Net::HTTP::Get.new zip_url.request_uri
  @request["User-Agent"] = USER_AGENT
  @request
end
theme_dir_empty?() click to toggle source
# File lib/jekyll-remote-theme/downloader.rb, line 103
def theme_dir_empty?
  Dir["#{theme.root}/*"].empty?
end
theme_dir_exists?() click to toggle source
# File lib/jekyll-remote-theme/downloader.rb, line 99
def theme_dir_exists?
  theme.root && Dir.exist?(theme.root)
end
unzip() click to toggle source
# File lib/jekyll-remote-theme/downloader.rb, line 76
def unzip
  Jekyll.logger.debug LOG_KEY, "Unzipping #{zip_file.path} to #{theme.root}"

  # File IO is already open, rewind pointer to start of file to read
  zip_file.rewind

  Zip::File.open(zip_file) do |archive|
    archive.each { |file| file.extract path_without_name_and_ref(file.name) }
  end
ensure
  zip_file.close
  zip_file.unlink
end
zip_file() click to toggle source
# File lib/jekyll-remote-theme/downloader.rb, line 36
def zip_file
  @zip_file ||= Tempfile.new([TEMP_PREFIX, ".zip"], :binmode => true)
end
zip_url() click to toggle source

Full URL to codeload zip download endpoint for the given theme

# File lib/jekyll-remote-theme/downloader.rb, line 91
def zip_url
  @zip_url ||= Addressable::URI.new(
    :scheme => theme.scheme,
    :host   => "codeload.#{theme.host}",
    :path   => [theme.owner, theme.name, "zip", theme.git_ref].join("/")
  ).normalize
end