# encoding: utf-8
#--
# Copyright (C) 2012-2013 Gitorious AS
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#++
require "json"
require "time"
require "cgi"
module Dolt
module Sinatra
module Actions
def redirect(url, status = 302)
response.status = status
response["Location"] = url
body ""
end
def error(error, repo, ref)
template = error.class.to_s == "Rugged::IndexerError" ? :"404" : :"500"
add_headers(response)
body(renderer.render(template, {
:error => error,
:repository_slug => repo,
:ref => ref
}))
rescue Exception => err
err_backtrace = err.backtrace.map { |s| "
#{s}" }
error_backtrace = error.backtrace.map { |s| "#{s}" }
body(<<-HTML)
Fatal Dolt Error
Dolt encountered an exception, and additionally
triggered another exception trying to render the error.
Error: #{err.class} #{err.message}
Original error: #{error.class} #{error.message}
#{error_backtrace.join()}
HTML
end
def raw(repo, ref, path, custom_data = {})
if oid = lookup_ref_oid(repo, ref)
redirect(raw_url(repo, oid, path), 307) and return
end
blob(repo, ref, path, custom_data, {
:template => :raw,
:content_type => "text/plain",
:template_options => { :layout => nil }
})
end
def blob(repo, ref, path, custom_data = {}, options = { :template => :blob })
if oid = lookup_ref_oid(repo, ref)
redirect(blob_url(repo, oid, path), 307) and return
end
data = (custom_data || {}).merge(actions.blob(repo, u(ref), path))
blob = data[:blob]
return redirect(tree_url(repo, ref, path)) if blob.class.to_s !~ /\bBlob/
add_headers(response, options.merge(:ref => ref))
tpl_options = options[:template_options] || {}
body(renderer.render(options[:template], data, tpl_options))
end
def tree(repo, ref, path, custom_data = {})
if oid = lookup_ref_oid(repo, ref)
redirect(tree_url(repo, oid, path), 307) and return
end
data = (custom_data || {}).merge(actions.tree(repo, u(ref), path))
tree = data[:tree]
return redirect(blob_url(repo, ref, path)) if tree.class.to_s !~ /\bTree/
add_headers(response, :ref => ref)
body(renderer.render(:tree, data))
end
def tree_entry(repo, ref, path, custom_data = {})
if oid = lookup_ref_oid(repo, ref)
redirect(tree_entry_url(repo, oid, path), 307) and return
end
data = (custom_data || {}).merge(actions.tree_entry(repo, u(ref), path))
add_headers(response, :ref => ref)
body(renderer.render(data.key?(:tree) ? :tree : :blob, data))
end
def blame(repo, ref, path, custom_data = {})
if oid = lookup_ref_oid(repo, ref)
redirect(blame_url(repo, oid, path), 307) and return
end
data = (custom_data || {}).merge(actions.blame(repo, u(ref), path))
add_headers(response, :ref => ref)
body(renderer.render(:blame, data))
end
def history(repo, ref, path, count, custom_data = {})
if oid = lookup_ref_oid(repo, ref)
redirect(history_url(repo, oid, path), 307) and return
end
data = (custom_data || {}).merge(actions.history(repo, u(ref), path, count))
add_headers(response, :ref => ref)
body(renderer.render(:commits, data))
end
def refs(repo, custom_data = {})
data = (custom_data || {}).merge(actions.refs(repo))
add_headers(response, :content_type => "application/json")
body(renderer.render(:refs, data, :layout => nil))
end
def tree_history(repo, ref, path, count = 1, custom_data = {})
if oid = lookup_ref_oid(repo, ref)
redirect(tree_history_url(repo, oid, path), 307) and return
end
data = (custom_data || {}).merge(actions.tree_history(repo, u(ref), path, count))
add_headers(response, :content_type => "application/json", :ref => ref)
body(renderer.render(:tree_history, data, :layout => nil))
end
def resolve_repository(repo)
@cache ||= {}
@cache[repo] ||= actions.resolve_repository(repo)
end
def lookup_ref_oid(repo, ref)
return if !respond_to?(:redirect_refs?) || !redirect_refs? || ref.length == 40
actions.rev_parse_oid(repo, ref)
end
private
def u(str)
# Temporarily swap the + out with a magic byte, so
# filenames/branches with +'s won't get unescaped to a space
CGI.unescape(str.gsub("+", "\001")).gsub("\001", '+')
end
def add_headers(response, headers = {})
default_ct = "text/html; charset=utf-8"
response["Content-Type"] = headers[:content_type] || default_ct
response["X-UA-Compatible"] = "IE=edge"
if headers[:ref] && headers[:ref].length == 40
response["Cache-Control"] = "max-age=315360000, public"
year = 60*60*24*365
response["Expires"] = (Time.now + year).httpdate
end
end
end
end
end