class RedmineInstaller::Package

Constants

SUPPORTED_ARCHIVE_FORMATS

Attributes

package[R]
temp_dir[R]

Public Class Methods

new(task, package) click to toggle source
Calls superclass method
# File lib/redmine-installer/package.rb, line 14
def initialize(task, package)
  super(task)
  @package = package.to_s
end

Public Instance Methods

clean_up() click to toggle source
# File lib/redmine-installer/package.rb, line 80
def clean_up
  @temp_dir && FileUtils.remove_entry_secure(@temp_dir)
  @temp_file && FileUtils.remove_entry_secure(@temp_file)
end
ensure_and_valid_package() click to toggle source
# File lib/redmine-installer/package.rb, line 19
def ensure_and_valid_package
  if package.empty?
    @package = prompt.ask('Path to package:', required: true)
  end

  if !File.exist?(@package)
    if @package =~ /\Av?(\d\.\d\.\d)\Z/
      @package = download_redmine_version($1)
    elsif valid_url?(@package)
      @package = download_from_url(@package)
    else
      error "File doesn't exist #{@package}"
    end
  end

  @type = File.extname(@package)
  unless SUPPORTED_ARCHIVE_FORMATS.include?(@type)
    error "File #{@package} must have format: #{SUPPORTED_ARCHIVE_FORMATS.join(', ')}"
  end
end
extract() click to toggle source
# File lib/redmine-installer/package.rb, line 40
def extract
  print_title('Extracting redmine package')

  @temp_dir = Dir.mktmpdir

  case @type
  when '.zip'
    extract_zip
  when '.gz', '.tgz'
    extract_tar_gz
  end

  logger.info("Package was loaded into #{@temp_dir}.")
end
redmine_root() click to toggle source

Move files from temp dir to target. First check if folder contains redmine or contains folder which contains redmine.

Package can have format: |– redmine-2

|-- app
`-- config

# File lib/redmine-installer/package.rb, line 64
def redmine_root
  root = @temp_dir

  loop {
    ls = Dir.glob(File.join(root, '*'))

    if ls.size == 1
      root = ls.first
    else
      break
    end
  }

  root
end

Private Instance Methods

download_from_url(url) click to toggle source
# File lib/redmine-installer/package.rb, line 99
def download_from_url(url)
  uri = URI.parse(url)

  @temp_file = Tempfile.new(['redmine', '.zip'])
  @temp_file.binmode

  Net::HTTP.start(uri.host, uri.port) do |http|
    head = http.request_head(uri)

    unless head.is_a?(Net::HTTPSuccess)
      error "Cannot download #{uri}"
    end

    print_title("Downloading #{uri}")
    progressbar = TTY::ProgressBar.new(PROGRESSBAR_FORMAT, total: head['content-length'].to_i, frequency: 2, clear: true)

    http.get(uri) do |data|
      @temp_file.write(data)
      progressbar.advance(data.size)
    end

    progressbar.finish
  end

  logger.info("#{uri} downloaded")

  @temp_file.close
  @temp_file.path
end
download_redmine_version(version) click to toggle source
# File lib/redmine-installer/package.rb, line 94
def download_redmine_version(version)
  url = "http://www.redmine.org/releases/redmine-#{version}.zip"
  download_from_url(url)
end
extract_tar_gz() click to toggle source

Extract .tar.gz archive based on dracoater.blogspot.cz/2013/10/extracting-files-from-targz-with-ruby.html

Originally tar did not support paths longer than 100 chars. GNU tar is better and they implemented support for longer paths, but it was made through a hack called ././@LongLink. Shortly speaking, if you stumble upon an entry in tar archive which path equals to above mentioned ././@LongLink, that means that the following entry path is longer than 100 chars and is truncated. The full path of the following entry is actually the value of the current entry.

# File lib/redmine-installer/package.rb, line 156
def extract_tar_gz
  Gem::Package::TarReader.new(Zlib::GzipReader.open(@package)) do |tar|

    # Progressbar
    progressbar = TTY::ProgressBar.new(PROGRESSBAR_FORMAT, total: tar.count, frequency: 2, clear: true)

    # tar.count move position pointer to end
    tar.rewind

    dest_file = nil
    tar.each do |entry|

      if entry.full_name == TAR_LONGLINK
        dest_file = File.join(@temp_dir, entry.read.strip)
        next
      end

      # Pax header
      # "%d %s=%s\n", <length>, <keyword>, <value>
      if entry.header.typeflag == 'x'

        pax_headers = entry.read.split("\n")
        pax_headers.each do |header|
          meta, value = header.split('=', 2)
          length, keyword = meta.split(' ', 2)

          if keyword == 'path'
            dest_file = File.join(@temp_dir, value)
            next
          end
        end

        # If there is no header with keyword "path"
        next
      end

      dest_file ||= File.join(@temp_dir, entry.full_name)
      if entry.directory?
        FileUtils.rm_rf(dest_file) unless File.directory?(dest_file)
        FileUtils.mkdir_p(dest_file, mode: entry.header.mode, verbose: false)
      elsif entry.file?
        FileUtils.rm_rf(dest_file) unless File.file?(dest_file)
        File.open(dest_file, 'wb') do |f|
          f.write(entry.read)
        end
        FileUtils.chmod(entry.header.mode, dest_file, verbose: false)
      elsif entry.header.typeflag == '2' # symlink
        File.symlink(entry.header.linkname, dest_file)
      end

      dest_file = nil
      progressbar.advance(1)
    end

    progressbar.finish
  end
end
extract_zip() click to toggle source
# File lib/redmine-installer/package.rb, line 129
def extract_zip
  Zip::File.open(@package) do |zip_file|
    # Progressbar
    progressbar = TTY::ProgressBar.new(PROGRESSBAR_FORMAT, total: zip_file.size, frequency: 2, clear: true)

    zip_file.each do |entry|
      dest_file = File.join(@temp_dir, entry.name)
      FileUtils.mkdir_p(File.dirname(dest_file))

      entry.extract(dest_file)
      progressbar.advance(1)
    end

    progressbar.finish
  end

end
valid_url?(string) click to toggle source
# File lib/redmine-installer/package.rb, line 87
def valid_url?(string)
  uri = URI.parse(string)
  ['http', 'https'].include?(uri.scheme)
rescue URI::BadURIError, URI::InvalidURIError
  false
end