class Geminabox::Server

def all_gems

def all_gems
  all_gems_with_duplicates.inject(:|)
end

def all_gems_with_duplicates

def all_gems_with_duplicates
  specs_files_paths.map do |specs_file_path|
    if File.exist?(specs_file_path)
      Marshal.load(Gem::Util.gunzip(Gem.read_binary(specs_file_path)))
    else
      []
    end
  end
end

def allow_delete?

def allow_delete?
  Geminabox.allow_delete
end

def allow_upload?

def allow_upload?
  Geminabox.allow_upload
end

def api_request?

def api_request?
  request.accept.first.to_s != "text/html"
end

def combined_gem_list

def combined_gem_list
  GemListMerge.merge(local_gem_list, remote_gem_list, strategy: Geminabox.rubygems_proxy_merge_strategy)
end

def default_platform

def default_platform
  'ruby'
end

def dependency_cache

def dependency_cache
  @dependency_cache ||= Geminabox::DiskCache.new(File.join(Geminabox.data, "_cache"))
end

def dependency_cache

def dependency_cache
  self.class.dependency_cache
end

def disallow_replace?

def disallow_replace?
  ! Geminabox.allow_replace
end

def error_response(code, message)

def error_response(code, message)
  halt [code, message] if api_request?
  html = <<HTML
l>
ead><title>Error - #{code}</title></head>
ody>
<h1>Error - #{code}</h1>
<p>#{message}</p>
body>
ml>

  halt [code, html]
end

def file_class

This method provides a test hook, as stubbing File is painful...
def file_class
  @file_class ||= File
end

def file_class=(klass)

def file_class=(klass)
  @file_class = klass
end

def file_path

def file_path
  File.expand_path(File.join(Geminabox.data, *request.path_info))
end

def fixup_bundler_rubygems!

def fixup_bundler_rubygems!
  return if @post_reset_hook_applied
  Gem.post_reset{ Gem::Specification.all = nil } if defined? Bundler and Gem.respond_to? :post_reset
  @post_reset_hook_applied = true
end

def gem_dependencies(gem_name)

Return a list of versions of gem 'gem_name' with the dependencies of each version.
def gem_dependencies(gem_name)
  dependency_cache.marshal_cache(gem_name) do
    load_gems.
      select { |gem| gem_name == gem.name }.
      map    { |gem| [gem, spec_for(gem.name, gem.number, gem.platform)] }.
      reject { |(_, spec)| spec.nil? }.
      map do |(gem, spec)|
        {
          :name => gem.name,
          :number => gem.number.version,
          :platform => gem.platform,
          :dependencies => runtime_dependencies(spec)
        }
      end
  end
end

def gem_list

def gem_list
  Geminabox.rubygems_proxy ? combined_gem_list : local_gem_list
end

def h(text)

def h(text)
  Rack::Utils.escape_html(text)
end

def handle_incoming_gem(gem)

def handle_incoming_gem(gem)
  begin
    GemStore.create(gem, params[:overwrite])
  rescue GemStoreError => error
    error_response error.code, error.reason
  end
  begin
    Geminabox.on_gem_received.call(gem) if Geminabox.on_gem_received
  rescue
    # ignore errors which occur within the hook
  end
  if api_request?
    "Gem #{gem.name} received and indexed."
  else
    redirect url("/")
  end
end

def href(text)

def href(text)
  if text && (text.start_with?('http://') || text.start_with?('https://'))
    Rack::Utils.escape_html(text)
  else
    '#'
  end
end

def index_gems(gems)

def index_gems(gems)
  Set.new(gems.map{|gem| gem.name[0..0].downcase})
end

def indexer

def indexer
  Gem::Indexer.new(Geminabox.data, :build_legacy => Geminabox.build_legacy)
end

def load_gems

def load_gems
  @loaded_gems ||= Geminabox::GemVersionCollection.new(all_gems)
end

def local_gem_list

def local_gem_list
  query_gems.map{|query_gem| gem_dependencies(query_gem) }.flatten(1)
end

def name_and_requirements_for(dep)

def name_and_requirements_for(dep)
  name = dep.name.kind_of?(Array) ? dep.name.first : dep.name
  [name, dep.requirement.to_s]
end

def query_gems

def query_gems
  params[:gems].to_s.split(',')
end

def reindex(force_rebuild = false)

def reindex(force_rebuild = false)
  fixup_bundler_rubygems!
  force_rebuild = true unless Geminabox.incremental_updates
  if force_rebuild
    indexer.generate_index
    dependency_cache.flush
  else
    begin
      require 'geminabox/indexer'
      updated_gemspecs = Geminabox::Indexer.updated_gemspecs(indexer)
      return if updated_gemspecs.empty?
      indexer.update_index
      updated_gemspecs.each { |gem| dependency_cache.flush_key(gem.name) }
    rescue Errno::ENOENT
      with_rlock { reindex(:force_rebuild) }
    rescue => e
      puts "#{e.class}:#{e.message}"
      puts e.backtrace.join("\n")
      with_rlock { reindex(:force_rebuild) }
    end
  end
rescue Gem::SystemExitException
end

def remote_gem_list

def remote_gem_list
  RubygemsDependency.for(*query_gems)
end

def runtime_dependencies(spec)

def runtime_dependencies(spec)
  spec.
    dependencies.
    select { |dep| dep.type == :runtime }.
    map    { |dep| name_and_requirements_for(dep) }
end

def serialize_update(&block)

def serialize_update(&block)
  with_rlock(&block)
rescue ReentrantFlock::AlreadyLocked
  halt 503, { 'Retry-After' => Geminabox.retry_interval.to_s }, 'Repository lock is held by another process'
end

def spec_file_name(specs_file_type)

def spec_file_name(specs_file_type)
  [specs_file_type, Gem.marshal_version, 'gz'].join('.')
end

def spec_for(gem_name, version, platform = default_platform)

def spec_for(gem_name, version, platform = default_platform)
  filename = [gem_name, version]
  filename.push(platform) if platform != default_platform
  spec_file = File.join(Geminabox.data, "quick", "Marshal.#{Gem.marshal_version}", "#{filename.join("-")}.gemspec.rz")
  File::open(spec_file, 'r') do |unzipped_spec_file|
    unzipped_spec_file.binmode
    Marshal.load(Gem::Util.inflate(unzipped_spec_file.read))
  end if File.exist? spec_file
end

def specs_file_types

def specs_file_types
  [:specs, :prerelease_specs]
end

def specs_files_paths

def specs_files_paths
  specs_file_types.map do |specs_file_type|
    File.join(Geminabox.data, spec_file_name(specs_file_type))
  end
end

def with_rlock(&block)

def with_rlock(&block)
  file_class.open(Geminabox.lockfile, File::RDWR | File::CREAT) do |f|
    ReentrantFlock.synchronize(f, File::LOCK_EX | File::LOCK_NB, &block)
  end
end

def with_rlock(&block)

def with_rlock(&block)
  self.class.with_rlock(&block)
end