dolt 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile.lock +25 -5
- data/Readme.md +90 -16
- data/bin/dolt +22 -4
- data/dolt.gemspec +10 -2
- data/lib/dolt/disk_repo_resolver.rb +3 -5
- data/lib/dolt/git/blame.rb +112 -0
- data/lib/dolt/git/commit.rb +73 -0
- data/lib/dolt/git/repository.rb +26 -24
- data/lib/dolt/repo_actions.rb +32 -19
- data/lib/dolt/sinatra/actions.rb +51 -18
- data/lib/dolt/sinatra/multi_repo_browser.rb +30 -3
- data/lib/dolt/sinatra/single_repo_browser.rb +36 -2
- data/lib/dolt/template_renderer.rb +7 -8
- data/lib/dolt/version.rb +1 -1
- data/lib/dolt/view.rb +3 -61
- data/lib/dolt/view/blame.rb +57 -0
- data/lib/dolt/view/blob.rb +60 -0
- data/lib/dolt/view/breadcrumb.rb +10 -17
- data/lib/dolt/{git/blob.rb → view/commit.rb} +5 -11
- data/lib/dolt/view/gravatar.rb +29 -0
- data/lib/dolt/{git/shell.rb → view/markup.rb} +10 -16
- data/lib/dolt/view/multi_repository.rb +27 -0
- data/lib/dolt/{async/deferrable_child_process.rb → view/object.rb} +11 -24
- data/lib/dolt/view/single_repository.rb +27 -0
- data/lib/dolt/view/smart_blob_renderer.rb +33 -0
- data/lib/dolt/view/syntax_highlight.rb +86 -0
- data/lib/dolt/view/tree.rb +69 -0
- data/test/dolt/git/blame_test.rb +128 -0
- data/test/dolt/git/commit_test.rb +89 -0
- data/test/dolt/git/repository_test.rb +24 -73
- data/test/dolt/repo_actions_test.rb +77 -15
- data/test/dolt/sinatra/actions_test.rb +168 -8
- data/test/dolt/template_renderer_test.rb +44 -10
- data/test/dolt/templates/blame_test.rb +56 -0
- data/test/dolt/{views → templates}/blob_test.rb +44 -34
- data/test/dolt/templates/commits_test.rb +61 -0
- data/test/dolt/templates/raw_test.rb +41 -0
- data/test/dolt/templates/tree_test.rb +51 -0
- data/test/dolt/view/blame_test.rb +122 -0
- data/test/dolt/view/blob_test.rb +90 -0
- data/test/dolt/view/breadcrumb_test.rb +46 -0
- data/test/dolt/view/commit_test.rb +31 -0
- data/test/dolt/view/gravatar_test.rb +30 -0
- data/test/dolt/view/markup_test.rb +30 -0
- data/test/dolt/{git/blob_test.rb → view/multi_repository_test.rb} +10 -24
- data/test/dolt/view/object_test.rb +71 -0
- data/test/dolt/view/single_repository_test.rb +30 -0
- data/test/dolt/{view_test.rb → view/syntax_highlight_test.rb} +40 -27
- data/test/dolt/view/tree_test.rb +115 -0
- data/test/test_helper.rb +18 -13
- data/vendor/ui/css/gitorious.css +20 -8
- data/views/blame.erb +41 -0
- data/views/blob.erb +6 -9
- data/views/commits.erb +23 -0
- data/views/index.erb +25 -0
- data/views/raw.erb +19 -0
- data/views/tree.erb +28 -26
- metadata +156 -26
- data/lib/dolt/git/tree.rb +0 -65
- data/lib/dolt/view/highlighter.rb +0 -52
- data/test/dolt/git/shell_test.rb +0 -112
- data/test/dolt/git/tree_test.rb +0 -120
data/lib/dolt/git/repository.rb
CHANGED
@@ -15,44 +15,46 @@
|
|
15
15
|
# You should have received a copy of the GNU Affero General Public License
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
#++
|
18
|
-
require "
|
19
|
-
require "
|
20
|
-
require "
|
18
|
+
require "em_rugged/repository"
|
19
|
+
require "em_pessimistic/deferrable_child_process"
|
20
|
+
require "em/deferrable"
|
21
|
+
require "dolt/git/blame"
|
22
|
+
require "dolt/git/commit"
|
21
23
|
|
22
24
|
module Dolt
|
23
25
|
module Git
|
24
|
-
class Repository
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@name = name
|
29
|
-
@git = git
|
30
|
-
end
|
31
|
-
|
32
|
-
def blob(path, ref = "HEAD")
|
33
|
-
async_git(git.show(path, ref)) do |data, status|
|
34
|
-
Dolt::Git::Blob.new(path, data)
|
26
|
+
class Repository < EMRugged::Repository
|
27
|
+
def blame(ref, path)
|
28
|
+
deferred_method("blame -l -t -p #{ref} #{path}") do |output, s|
|
29
|
+
Dolt::Git::Blame.parse_porcelain(output)
|
35
30
|
end
|
36
31
|
end
|
37
32
|
|
38
|
-
def
|
39
|
-
|
40
|
-
Dolt::Git::
|
33
|
+
def log(ref, path, limit)
|
34
|
+
deferred_method("log -n #{limit} #{ref} #{path}") do |out, s|
|
35
|
+
Dolt::Git::Commit.parse_log(out)
|
41
36
|
end
|
42
37
|
end
|
43
38
|
|
44
39
|
private
|
45
|
-
def
|
40
|
+
def deferred_method(cmd, &block)
|
41
|
+
d = EventMachine::DefaultDeferrable.new
|
42
|
+
cmd = git(cmd)
|
43
|
+
p = EMPessimistic::DeferrableChildProcess.open(cmd)
|
46
44
|
|
47
|
-
|
48
|
-
|
45
|
+
p.callback do |output, status|
|
46
|
+
d.succeed(block.call(output, status))
|
47
|
+
end
|
49
48
|
|
50
|
-
|
51
|
-
|
49
|
+
p.errback do |err|
|
50
|
+
d.fail(err)
|
52
51
|
end
|
53
52
|
|
54
|
-
|
55
|
-
|
53
|
+
d
|
54
|
+
end
|
55
|
+
|
56
|
+
def git(cmd)
|
57
|
+
"git --git-dir #{subject.path} #{cmd}"
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
data/lib/dolt/repo_actions.rb
CHANGED
@@ -23,31 +23,44 @@ module Dolt
|
|
23
23
|
@repo_resolver = repo_resolver
|
24
24
|
end
|
25
25
|
|
26
|
-
def blob(repo,
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
26
|
+
def blob(repo, ref, path, &block)
|
27
|
+
repo_action(repo, ref, path, :blob, :rev_parse, "#{ref}:#{path}", &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def tree(repo, ref, path, &block)
|
31
|
+
repo_action(repo, ref, path, :tree, :rev_parse, "#{ref}:#{path}", &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def blame(repo, ref, path, &block)
|
35
|
+
repo_action(repo, ref, path, :blame, :blame, ref, path, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def history(repo, ref, path, count, &block)
|
39
|
+
repo_action(repo, ref, path, :commits, :log, ref, path, count, &block)
|
36
40
|
end
|
37
41
|
|
38
|
-
def
|
42
|
+
def repositories
|
43
|
+
repo_resolver.all
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def repo_resolver; @repo_resolver; end
|
48
|
+
|
49
|
+
def repo_action(repo, ref, path, data, method, *args, &block)
|
39
50
|
repository = repo_resolver.resolve(repo)
|
40
|
-
d = repository.
|
41
|
-
d.callback do |
|
42
|
-
block.call(nil, {
|
43
|
-
:tree => tree,
|
44
|
-
:repository => repository,
|
45
|
-
:ref => ref })
|
51
|
+
d = repository.send(method, *args)
|
52
|
+
d.callback do |result|
|
53
|
+
block.call(nil, tpl_data(repo, ref, path, { data => result }))
|
46
54
|
end
|
47
55
|
d.errback { |err| block.call(err, nil) }
|
48
56
|
end
|
49
57
|
|
50
|
-
|
51
|
-
|
58
|
+
def tpl_data(repo, ref, path, locals = {})
|
59
|
+
{
|
60
|
+
:repository => repo,
|
61
|
+
:path => path,
|
62
|
+
:ref => ref
|
63
|
+
}.merge(locals)
|
64
|
+
end
|
52
65
|
end
|
53
66
|
end
|
data/lib/dolt/sinatra/actions.rb
CHANGED
@@ -15,33 +15,66 @@
|
|
15
15
|
# You should have received a copy of the GNU Affero General Public License
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
#++
|
18
|
+
require "em_rugged"
|
19
|
+
|
18
20
|
module Dolt
|
19
21
|
module Sinatra
|
20
22
|
module Actions
|
21
|
-
|
23
|
+
# Built-in redirect seems to not work with Sinatra::Async, it throws
|
24
|
+
# an error.
|
25
|
+
def redirect(url)
|
26
|
+
response.status = 302
|
27
|
+
response["Location"] = url
|
28
|
+
body ""
|
29
|
+
end
|
30
|
+
|
31
|
+
def error(error)
|
22
32
|
response["Content-Type"] = "text/plain"
|
23
|
-
body("Process failed with exit code
|
33
|
+
body("Process failed with exit code #{error.exit_code}:\n#{error.message}")
|
34
|
+
end
|
35
|
+
|
36
|
+
def raw(repo, ref, path)
|
37
|
+
blob(repo, ref, path, {
|
38
|
+
:template => :raw,
|
39
|
+
:content_type => "text/plain",
|
40
|
+
:template_options => { :layout => nil }
|
41
|
+
})
|
42
|
+
end
|
43
|
+
|
44
|
+
def blob(repo, ref, path, options = { :template => :blob, :content_type => "text/html" })
|
45
|
+
actions.blob(repo, ref, path) do |err, data|
|
46
|
+
return error(err) if !err.nil?
|
47
|
+
blob = data[:blob]
|
48
|
+
return redirect(tree_url(repo, ref, path)) if !blob.is_a?(Rugged::Blob)
|
49
|
+
response["Content-Type"] = options[:content_type]
|
50
|
+
tpl_options = options[:template_options] || {}
|
51
|
+
body(renderer.render(options[:template], data, tpl_options))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def tree(repo, ref, path)
|
56
|
+
actions.tree(repo, ref, path) do |err, data|
|
57
|
+
return error(err) if !err.nil?
|
58
|
+
tree = data[:tree]
|
59
|
+
return redirect(blob_url(repo, ref, path)) if !tree.is_a?(Rugged::Tree)
|
60
|
+
response["Content-Type"] = "text/html"
|
61
|
+
body(renderer.render(:tree, data))
|
62
|
+
end
|
24
63
|
end
|
25
64
|
|
26
|
-
def
|
27
|
-
actions.
|
28
|
-
if
|
29
|
-
|
30
|
-
|
31
|
-
else
|
32
|
-
error(status)
|
33
|
-
end
|
65
|
+
def blame(repo, ref, path)
|
66
|
+
actions.blame(repo, ref, path) do |err, data|
|
67
|
+
return error(err) if !err.nil?
|
68
|
+
response["Content-Type"] = "text/html"
|
69
|
+
body(renderer.render(:blame, data))
|
34
70
|
end
|
35
71
|
end
|
36
72
|
|
37
|
-
def
|
38
|
-
actions.
|
39
|
-
if
|
40
|
-
|
41
|
-
|
42
|
-
else
|
43
|
-
error(status)
|
44
|
-
end
|
73
|
+
def history(repo, ref, path, count)
|
74
|
+
actions.history(repo, ref, path, count) do |err, data|
|
75
|
+
return error(err) if !err.nil?
|
76
|
+
response["Content-Type"] = "text/html"
|
77
|
+
body(renderer.render(:commits, data))
|
45
78
|
end
|
46
79
|
end
|
47
80
|
end
|
@@ -16,17 +16,25 @@
|
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
#++
|
18
18
|
require "dolt/sinatra/base"
|
19
|
+
require "dolt/view/single_repository"
|
20
|
+
require "dolt/view/blob"
|
21
|
+
require "dolt/view/tree"
|
19
22
|
|
20
23
|
module Dolt
|
21
24
|
module Sinatra
|
22
25
|
class MultiRepoBrowser < Dolt::Sinatra::Base
|
26
|
+
include Dolt::View::SingleRepository
|
27
|
+
include Dolt::View::Blob
|
28
|
+
include Dolt::View::Tree
|
29
|
+
|
23
30
|
aget "/" do
|
24
31
|
response["Content-Type"] = "text/html"
|
25
|
-
body(
|
32
|
+
body(renderer.render(:index, { :repositories => actions.repositories }))
|
26
33
|
end
|
27
34
|
|
28
35
|
aget "/*/tree/*:*" do
|
29
|
-
|
36
|
+
repo, ref, path = params[:splat]
|
37
|
+
tree(repo, ref, path)
|
30
38
|
end
|
31
39
|
|
32
40
|
aget "/*/tree/*" do
|
@@ -34,13 +42,32 @@ module Dolt
|
|
34
42
|
end
|
35
43
|
|
36
44
|
aget "/*/blob/*:*" do
|
37
|
-
|
45
|
+
repo, ref, path = params[:splat]
|
46
|
+
blob(repo, ref, path)
|
38
47
|
end
|
39
48
|
|
40
49
|
aget "/*/blob/*" do
|
41
50
|
force_ref(params[:splat], "blob", "master")
|
42
51
|
end
|
43
52
|
|
53
|
+
aget "/*/raw/*:*" do
|
54
|
+
repo, ref, path = params[:splat]
|
55
|
+
raw(repo, ref, path)
|
56
|
+
end
|
57
|
+
|
58
|
+
aget "/*/raw/*" do
|
59
|
+
force_ref(params[:splat], "raw", "master")
|
60
|
+
end
|
61
|
+
|
62
|
+
aget "/*/blame/*:*" do
|
63
|
+
repo, ref, path = params[:splat]
|
64
|
+
blame(repo, ref, path)
|
65
|
+
end
|
66
|
+
|
67
|
+
aget "/*/blame/*" do
|
68
|
+
force_ref(params[:splat], "blame", "master")
|
69
|
+
end
|
70
|
+
|
44
71
|
private
|
45
72
|
def force_ref(args, action, ref)
|
46
73
|
redirect(args.shift + "/#{action}/#{ref}:" + args.join)
|
@@ -16,10 +16,16 @@
|
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
#++
|
18
18
|
require "dolt/sinatra/base"
|
19
|
+
require "dolt/view/single_repository"
|
20
|
+
require "dolt/view/blob"
|
21
|
+
require "dolt/view/tree"
|
19
22
|
|
20
23
|
module Dolt
|
21
24
|
module Sinatra
|
22
25
|
class SingleRepoBrowser < Dolt::Sinatra::Base
|
26
|
+
include Dolt::View::SingleRepository
|
27
|
+
include Dolt::View::Blob
|
28
|
+
include Dolt::View::Tree
|
23
29
|
attr_reader :repo
|
24
30
|
|
25
31
|
def initialize(repo, actions, renderer)
|
@@ -32,7 +38,8 @@ module Dolt
|
|
32
38
|
end
|
33
39
|
|
34
40
|
aget "/tree/*:*" do
|
35
|
-
|
41
|
+
ref, path = params[:splat]
|
42
|
+
tree(repo, ref, path)
|
36
43
|
end
|
37
44
|
|
38
45
|
aget "/tree/*" do
|
@@ -41,13 +48,40 @@ module Dolt
|
|
41
48
|
|
42
49
|
aget "/blob/*:*" do
|
43
50
|
ref, path = params[:splat]
|
44
|
-
blob(repo,
|
51
|
+
blob(repo, ref, path)
|
45
52
|
end
|
46
53
|
|
47
54
|
aget "/blob/*" do
|
48
55
|
force_ref(params[:splat], "blob", "master")
|
49
56
|
end
|
50
57
|
|
58
|
+
aget "/raw/*:*" do
|
59
|
+
ref, path = params[:splat]
|
60
|
+
raw(repo, ref, path)
|
61
|
+
end
|
62
|
+
|
63
|
+
aget "/raw/*" do
|
64
|
+
force_ref(params[:splat], "raw", "master")
|
65
|
+
end
|
66
|
+
|
67
|
+
aget "/blame/*:*" do
|
68
|
+
ref, path = params[:splat]
|
69
|
+
blame(repo, ref, path)
|
70
|
+
end
|
71
|
+
|
72
|
+
aget "/blame/*" do
|
73
|
+
force_ref(params[:splat], "blame", "master")
|
74
|
+
end
|
75
|
+
|
76
|
+
aget "/history/*:*" do
|
77
|
+
ref, path = params[:splat]
|
78
|
+
history(repo, ref, path, (params[:commit_count] || 20).to_i)
|
79
|
+
end
|
80
|
+
|
81
|
+
aget "/history/*" do
|
82
|
+
force_ref(params[:splat], "blame", "master")
|
83
|
+
end
|
84
|
+
|
51
85
|
private
|
52
86
|
def force_ref(args, action, ref)
|
53
87
|
redirect("/#{action}/#{ref}:" + args.join)
|
@@ -25,20 +25,20 @@ module Dolt
|
|
25
25
|
@layout = opt[:layout]
|
26
26
|
@type = opt[:type] || "erb"
|
27
27
|
@context_class = Class.new
|
28
|
-
@attributes = opt[:attributes] || {}
|
29
28
|
end
|
30
29
|
|
31
|
-
def helper(
|
32
|
-
|
30
|
+
def helper(helper)
|
31
|
+
helper = [helper] unless Array === helper
|
32
|
+
helper.each { |h| @context_class.send(:include, h) }
|
33
33
|
end
|
34
34
|
|
35
|
-
def render(template, locals = {})
|
36
|
-
locals = locals.merge(attributes)
|
35
|
+
def render(template, locals = {}, options = {})
|
37
36
|
context = context_class.new
|
38
37
|
content = load(template).render(context, locals)
|
38
|
+
layout_tpl = options.key?(:layout) ? options[:layout] : layout
|
39
39
|
|
40
|
-
if !
|
41
|
-
content = load(
|
40
|
+
if !layout_tpl.nil?
|
41
|
+
content = load(layout_tpl).render(context, locals) { content }
|
42
42
|
end
|
43
43
|
|
44
44
|
content
|
@@ -58,6 +58,5 @@ module Dolt
|
|
58
58
|
def layout; @layout; end
|
59
59
|
def type; @type; end
|
60
60
|
def context_class; @context_class; end
|
61
|
-
def attributes; @attributes; end
|
62
61
|
end
|
63
62
|
end
|
data/lib/dolt/version.rb
CHANGED
data/lib/dolt/view.rb
CHANGED
@@ -15,67 +15,9 @@
|
|
15
15
|
# You should have received a copy of the GNU Affero General Public License
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
#++
|
18
|
-
require "dolt/view/breadcrumb"
|
19
|
-
require "dolt/view/highlighter"
|
20
18
|
|
21
|
-
|
22
|
-
module View
|
23
|
-
def breadcrumb(repository, path, ref, options = {})
|
24
|
-
bc = Dolt::View::Breadcrumb.new(:multi_repo_mode => options[:multi_repo_mode])
|
25
|
-
bc.render(repository, ref, path)
|
26
|
-
end
|
19
|
+
dir = File.join(File.dirname(__FILE__), "view")
|
27
20
|
|
28
|
-
|
29
|
-
|
30
|
-
class_names << "prettyprint" << "linenums"
|
31
|
-
|
32
|
-
num = 0
|
33
|
-
lines = blob.split("\n").inject("") do |html, line|
|
34
|
-
num += 1
|
35
|
-
"#{html}<li class=\"L#{num}\"><span class=\"line\">#{line}</span></li>"
|
36
|
-
end
|
37
|
-
|
38
|
-
"<pre class=\"#{class_names.join(' ')}\">" +
|
39
|
-
"<ol class=\"linenums\">#{lines}</ol></pre>"
|
40
|
-
end
|
41
|
-
|
42
|
-
def highlight(path, code, options = {})
|
43
|
-
lexer = lexer_for_file(path)
|
44
|
-
Dolt::View::Highlighter.new(options).highlight(code, lexer)
|
45
|
-
rescue RubyPython::PythonError
|
46
|
-
code
|
47
|
-
end
|
48
|
-
|
49
|
-
def highlight_lines(path, code, options = {})
|
50
|
-
lexer = lexer_for_file(path)
|
51
|
-
multiline(highlight(path, code, options), :class_names => [lexer])
|
52
|
-
end
|
53
|
-
|
54
|
-
def lexer_for_file(path)
|
55
|
-
suffix = path.split(".").pop
|
56
|
-
Dolt::View::Highlighter.lexer(suffix)
|
57
|
-
end
|
58
|
-
|
59
|
-
def tree_url(repository, entry, ref, multi_repo_mode)
|
60
|
-
action = entry.file? ? "blob" : "tree"
|
61
|
-
repo_url(repository, "/#{action}/#{ref}:#{entry.full_path}", multi_repo_mode)
|
62
|
-
end
|
63
|
-
|
64
|
-
def blame_url(repository, blob, ref, multi_repo_mode)
|
65
|
-
repo_url(repository, "/blame/#{ref}:#{blob.path}", multi_repo_mode)
|
66
|
-
end
|
67
|
-
|
68
|
-
def history_url(repository, blob, ref, multi_repo_mode)
|
69
|
-
repo_url(repository, "/history/#{ref}:#{blob.path}", multi_repo_mode)
|
70
|
-
end
|
71
|
-
|
72
|
-
def raw_url(repository, blob, ref, multi_repo_mode)
|
73
|
-
repo_url(repository, "/raw/#{ref}:#{blob.path}", multi_repo_mode)
|
74
|
-
end
|
75
|
-
|
76
|
-
def repo_url(repository, url, multi_repo_mode)
|
77
|
-
prefix = multi_repo_mode ? "/#{repository.name}" : ""
|
78
|
-
"#{prefix}#{url}"
|
79
|
-
end
|
80
|
-
end
|
21
|
+
Dir.entries(dir).select { |f| f =~ /\.rb$/ }.map do |file|
|
22
|
+
require(File.join(dir, file))
|
81
23
|
end
|