# 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}

    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