lib/geminabox/server.rb in geminabox-0.12.4 vs lib/geminabox/server.rb in geminabox-0.13.0
- old
+ new
@@ -14,11 +14,14 @@
:incremental_updates,
:views,
:allow_replace,
:gem_permissions,
:allow_delete,
- :rubygems_proxy
+ :lockfile,
+ :retry_interval,
+ :rubygems_proxy,
+ :ruby_gems_url
)
if Server.rubygems_proxy
use Proxy::Hostess
else
@@ -51,16 +54,19 @@
require 'geminabox/indexer'
updated_gemspecs = Geminabox::Indexer.updated_gemspecs(indexer)
Geminabox::Indexer.patch_rubygems_update_index_pre_1_8_25(indexer)
indexer.update_index
updated_gemspecs.each { |gem| dependency_cache.flush_key(gem.name) }
+ rescue Errno::ENOENT
+ reindex(:force_rebuild)
rescue => e
puts "#{e.class}:#{e.message}"
puts e.backtrace.join("\n")
reindex(:force_rebuild)
end
end
+ rescue Gem::SystemExitException
end
def indexer
Gem::Indexer.new(data, :build_legacy => build_legacy)
end
@@ -98,12 +104,14 @@
get '/upload' do
erb :upload
end
get '/reindex' do
- self.class.reindex(:force_rebuild)
- redirect url("/")
+ serialize_update do
+ self.class.reindex(:force_rebuild)
+ redirect url("/")
+ end
end
get '/gems/:gemname' do
gems = Hash[load_gems.by_name]
@gem = gems[params[:gemname]]
@@ -113,35 +121,62 @@
delete '/gems/*.gem' do
unless self.class.allow_delete?
error_response(403, 'Gem deletion is disabled - see https://github.com/cwninja/geminabox/issues/115')
end
- File.delete file_path if File.exists? file_path
- self.class.reindex(:force_rebuild)
- redirect url("/")
+
+ serialize_update do
+ File.delete file_path if File.exists? file_path
+ self.class.reindex(:force_rebuild)
+ redirect url("/")
+ end
+
end
post '/upload' do
- unless params[:file] && params[:file][:filename] && (tmpfile = params[:file][:tempfile])
+ if params[:file] && params[:file][:filename] && (tmpfile = params[:file][:tempfile])
+ serialize_update do
+ handle_incoming_gem(Geminabox::IncomingGem.new(tmpfile))
+ end
+ else
@error = "No file selected"
halt [400, erb(:upload)]
end
- handle_incoming_gem(Geminabox::IncomingGem.new(tmpfile))
end
post '/api/v1/gems' do
begin
- handle_incoming_gem(Geminabox::IncomingGem.new(request.body))
+ serialize_update do
+ handle_incoming_gem(Geminabox::IncomingGem.new(request.body))
+ end
rescue Object => o
File.open "/tmp/debug.txt", "a" do |io|
io.puts o, o.backtrace
end
end
end
private
+ def serialize_update(&block)
+ with_lock(&block)
+ rescue AlreadyLocked
+ halt 503, { 'Retry-After' => settings.retry_interval }, 'Repository lock is held by another process'
+ end
+
+ def with_lock
+ file_class.open(settings.lockfile, File::RDWR | File::CREAT) do |f|
+ raise AlreadyLocked unless f.flock(File::LOCK_EX | File::LOCK_NB)
+ yield
+ end
+ end
+
+ # This method provides a test hook, as stubbing File is painful...
+ def file_class
+ File
+ end
+
def handle_incoming_gem(gem)
begin
GemStore.create(gem, params[:overwrite])
rescue GemStoreError => error
error_response error.code, error.reason
@@ -153,10 +188,10 @@
redirect url("/")
end
end
def api_request?
- request.accept.first != "text/html"
+ request.accept.first.to_s != "text/html"
end
def error_response(code, message)
halt [code, message] if api_request?
html = <<HTML