dolt 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/lib/dolt/async/when.rb +47 -6
- data/lib/dolt/git/commit.rb +1 -1
- data/lib/dolt/git/repository.rb +39 -4
- data/lib/dolt/repo_actions.rb +5 -0
- data/lib/dolt/sinatra/actions.rb +11 -0
- data/lib/dolt/sinatra/multi_repo_browser.rb +14 -0
- data/lib/dolt/sinatra/single_repo_browser.rb +5 -0
- data/lib/dolt/version.rb +1 -1
- data/lib/dolt/view/blob.rb +4 -0
- data/test/dolt/async/when_test.rb +112 -0
- data/test/dolt/git/repository_test.rb +90 -0
- data/test/dolt/repo_actions_test.rb +49 -0
- data/test/dolt/sinatra/actions_test.rb +14 -0
- data/test/dolt/templates/tree_history_test.rb +93 -0
- data/test/dolt/templates/tree_test.rb +2 -1
- data/vendor/ui/.gitignore +2 -0
- data/vendor/ui/.gitmodules +15 -0
- data/vendor/ui/build +28 -0
- data/vendor/ui/buster.js +5 -2
- data/vendor/ui/css/gitorious.css +11 -0
- data/vendor/ui/dist/gts-ui-deps.js +27 -0
- data/vendor/ui/js/components/ref-selector.js +32 -55
- data/vendor/ui/js/components/tree-history.js +62 -0
- data/vendor/ui/js/gitorious.js +6 -0
- data/vendor/ui/js/libs/cullquery.js +6 -0
- data/vendor/ui/js/libs/ext-libs.js +28 -0
- data/vendor/ui/{bootstrap → lib/bootstrap}/css/bootstrap-responsive.min.css +0 -0
- data/vendor/ui/{bootstrap → lib/bootstrap}/css/bootstrap.min.css +0 -0
- data/vendor/ui/{bootstrap → lib/bootstrap}/img/glyphicons-halflings-white.png +0 -0
- data/vendor/ui/{bootstrap → lib/bootstrap}/img/glyphicons-halflings.png +0 -0
- data/vendor/ui/{bootstrap → lib/bootstrap}/js/bootstrap.min.js +0 -0
- data/vendor/ui/package.json +20 -0
- data/vendor/ui/test/tree-history-test.js +260 -0
- data/views/500.erb +1 -1
- data/views/layout.erb +4 -4
- data/views/tree.erb +3 -3
- data/views/tree_history.erb +19 -0
- metadata +22 -10
data/Gemfile.lock
CHANGED
data/lib/dolt/async/when.rb
CHANGED
@@ -33,6 +33,10 @@ module When
|
|
33
33
|
@deferred.fail(*args)
|
34
34
|
end
|
35
35
|
|
36
|
+
def resolved?
|
37
|
+
@resolved
|
38
|
+
end
|
39
|
+
|
36
40
|
private
|
37
41
|
def mark_resolved
|
38
42
|
raise StandardError.new("Already resolved") if @resolved
|
@@ -65,23 +69,60 @@ module When
|
|
65
69
|
@promise.errback(&block)
|
66
70
|
end
|
67
71
|
|
72
|
+
def resolved?
|
73
|
+
@resolver.resolved?
|
74
|
+
end
|
75
|
+
|
68
76
|
def self.resolved(value)
|
69
77
|
d = self.new
|
70
|
-
d.resolve(
|
78
|
+
d.resolve(value)
|
71
79
|
d
|
72
80
|
end
|
73
81
|
|
74
82
|
def self.rejected(value)
|
75
83
|
d = self.new
|
76
|
-
d.reject(
|
84
|
+
d.reject(value)
|
77
85
|
d
|
78
86
|
end
|
79
87
|
end
|
80
88
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
89
|
+
def self.deferred(val)
|
90
|
+
return val if val.respond_to?(:callback) && val.respond_to?(:errback)
|
91
|
+
Deferred.resolved(val).promise
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.all(promises)
|
95
|
+
raise(ArgumentError, "expected enumerable promises") if !promises.is_a?(Enumerable)
|
96
|
+
resolved = 0
|
97
|
+
results = []
|
98
|
+
d = Deferred.new
|
99
|
+
|
100
|
+
attempt_resolution = lambda do |err, res|
|
101
|
+
break if d.resolved?
|
102
|
+
if err.nil?
|
103
|
+
d.resolve(res) if promises.length == resolved
|
104
|
+
else
|
105
|
+
d.reject(err)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
wait_for_all(promises) do |err, result, index|
|
110
|
+
resolved += 1
|
111
|
+
results[index] = result
|
112
|
+
attempt_resolution.call(err, results)
|
113
|
+
end
|
114
|
+
|
115
|
+
attempt_resolution.call(nil, results) if promises.length == 0
|
116
|
+
d.promise
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
def self.wait_for_all(promises, &block)
|
121
|
+
promises.each_with_index do |p, i|
|
122
|
+
p.callback do |result|
|
123
|
+
block.call(nil, result, i)
|
124
|
+
end
|
125
|
+
p.errback { |e| block.call(e, nil, i) }
|
85
126
|
end
|
86
127
|
end
|
87
128
|
end
|
data/lib/dolt/git/commit.rb
CHANGED
data/lib/dolt/git/repository.rb
CHANGED
@@ -20,6 +20,7 @@ require "em_pessimistic/deferrable_child_process"
|
|
20
20
|
require "em/deferrable"
|
21
21
|
require "dolt/git/blame"
|
22
22
|
require "dolt/git/commit"
|
23
|
+
require "dolt/async/when"
|
23
24
|
|
24
25
|
module Dolt
|
25
26
|
module Git
|
@@ -31,12 +32,46 @@ module Dolt
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def log(ref, path, limit)
|
34
|
-
|
35
|
-
|
35
|
+
entry_history(ref, path, limit)
|
36
|
+
end
|
37
|
+
|
38
|
+
def tree_history(ref, path, limit = 1)
|
39
|
+
d = EventMachine::DefaultDeferrable.new
|
40
|
+
rp = rev_parse("#{ref}:#{path}")
|
41
|
+
rp.errback { |err| d.fail(err) }
|
42
|
+
rp.callback do |tree|
|
43
|
+
if tree.class != Rugged::Tree
|
44
|
+
message = "#{ref}:#{path} is not a tree (#{tree.class.to_s})"
|
45
|
+
break d.fail(Exception.new(message))
|
46
|
+
end
|
47
|
+
|
48
|
+
building = build_history(path || "./", ref, tree, limit)
|
49
|
+
building.callback { |history| d.succeed(history) }
|
50
|
+
building.errback { |err| d.fail(err) }
|
36
51
|
end
|
52
|
+
d
|
37
53
|
end
|
38
54
|
|
39
55
|
private
|
56
|
+
def entry_history(ref, entry, limit)
|
57
|
+
deferred_method("log -n #{limit} #{ref} #{entry}") do |out, s|
|
58
|
+
Dolt::Git::Commit.parse_log(out)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def build_history(path, ref, entries, limit)
|
63
|
+
d = EventMachine::DefaultDeferrable.new
|
64
|
+
resolve = lambda { |p| path == "" ? p : File.join(path, p) }
|
65
|
+
progress = When.all(entries.map do |e|
|
66
|
+
entry_history(ref, resolve.call(e[:name]), limit)
|
67
|
+
end)
|
68
|
+
progress.errback { |e| d.fail(e) }
|
69
|
+
progress.callback do |history|
|
70
|
+
d.succeed(entries.map { |e| e.merge({ :history => history.shift }) })
|
71
|
+
end
|
72
|
+
d
|
73
|
+
end
|
74
|
+
|
40
75
|
def deferred_method(cmd, &block)
|
41
76
|
d = EventMachine::DefaultDeferrable.new
|
42
77
|
cmd = git(cmd)
|
@@ -46,8 +81,8 @@ module Dolt
|
|
46
81
|
d.succeed(block.call(output, status))
|
47
82
|
end
|
48
83
|
|
49
|
-
p.errback do |
|
50
|
-
d.fail(
|
84
|
+
p.errback do |stderr, status|
|
85
|
+
d.fail(stderr)
|
51
86
|
end
|
52
87
|
|
53
88
|
d
|
data/lib/dolt/repo_actions.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
# encoding: utf-8
|
2
3
|
#--
|
3
4
|
# Copyright (C) 2012 Gitorious AS
|
@@ -53,6 +54,10 @@ module Dolt
|
|
53
54
|
d.errback { |err| block.call(err, nil) }
|
54
55
|
end
|
55
56
|
|
57
|
+
def tree_history(repo, ref, path, count, &block)
|
58
|
+
repo_action(repo, ref, path, :tree, :tree_history, ref, path, count, &block)
|
59
|
+
end
|
60
|
+
|
56
61
|
def repositories
|
57
62
|
repo_resolver.all
|
58
63
|
end
|
data/lib/dolt/sinatra/actions.rb
CHANGED
@@ -89,6 +89,17 @@ module Dolt
|
|
89
89
|
body(renderer.render(:refs, data, :layout => nil))
|
90
90
|
end
|
91
91
|
end
|
92
|
+
|
93
|
+
def tree_history(repo, ref, path, count = 1)
|
94
|
+
actions.tree_history(repo, ref, path, count) do |err, data|
|
95
|
+
if !err.nil?
|
96
|
+
error(err, repo, ref)
|
97
|
+
else
|
98
|
+
response["Content-Type"] = "application/json"
|
99
|
+
body(renderer.render(:tree_history, data, :layout => nil))
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
92
103
|
end
|
93
104
|
end
|
94
105
|
end
|
@@ -68,10 +68,24 @@ module Dolt
|
|
68
68
|
force_ref(params[:splat], "blame", "master")
|
69
69
|
end
|
70
70
|
|
71
|
+
aget "/*/history/*:*" do
|
72
|
+
repo, ref, path = params[:splat]
|
73
|
+
history(repo, ref, path, (params[:commit_count] || 20).to_i)
|
74
|
+
end
|
75
|
+
|
76
|
+
aget "/*/history/*" do
|
77
|
+
force_ref(params[:splat], "history", "master")
|
78
|
+
end
|
79
|
+
|
71
80
|
aget "/*/refs" do
|
72
81
|
refs(params[:splat].first)
|
73
82
|
end
|
74
83
|
|
84
|
+
aget "/*/tree_history/*:*" do
|
85
|
+
repo, ref, path = params[:splat]
|
86
|
+
tree_history(repo, ref, path)
|
87
|
+
end
|
88
|
+
|
75
89
|
private
|
76
90
|
def force_ref(args, action, ref)
|
77
91
|
redirect(args.shift + "/#{action}/#{ref}:" + args.join)
|
data/lib/dolt/version.rb
CHANGED
data/lib/dolt/view/blob.rb
CHANGED
@@ -67,6 +67,10 @@ The content you're attempting to browse appears to be binary.
|
|
67
67
|
repo_url(repository, "/raw/#{ref}:#{path}")
|
68
68
|
end
|
69
69
|
|
70
|
+
def tree_history_url(repository, ref, path)
|
71
|
+
repo_url(repository, "/tree_history/#{ref}:#{path}")
|
72
|
+
end
|
73
|
+
|
70
74
|
def format_whitespace(text)
|
71
75
|
text
|
72
76
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#--
|
3
|
+
# Copyright (C) 2012 Gitorious AS
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#++
|
18
|
+
require "test_helper"
|
19
|
+
require "dolt/async/when"
|
20
|
+
|
21
|
+
describe When do
|
22
|
+
include EM::MiniTest::Spec
|
23
|
+
|
24
|
+
describe ".all" do
|
25
|
+
it "returns deferrable" do
|
26
|
+
d = When.all([When.deferred(42)])
|
27
|
+
assert d.respond_to?(:callback)
|
28
|
+
assert d.respond_to?(:errback)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "resolves immediately if no promises" do
|
32
|
+
d = When.all([])
|
33
|
+
d.callback do |results|
|
34
|
+
assert_equal [], results
|
35
|
+
done!
|
36
|
+
end
|
37
|
+
wait!
|
38
|
+
end
|
39
|
+
|
40
|
+
it "resolves when single deferrable resolves" do
|
41
|
+
deferred = When::Deferred.new
|
42
|
+
d = When.all([deferred.promise])
|
43
|
+
resolved = false
|
44
|
+
d.callback { |results| resolved = true }
|
45
|
+
|
46
|
+
assert !resolved
|
47
|
+
deferred.resolve(42)
|
48
|
+
assert resolved
|
49
|
+
end
|
50
|
+
|
51
|
+
it "resolves when all deferrables are resolved" do
|
52
|
+
deferreds = [When::Deferred.new, When::Deferred.new, When::Deferred.new]
|
53
|
+
d = When.all(deferreds.map(&:promise))
|
54
|
+
resolved = false
|
55
|
+
d.callback { |results| resolved = true }
|
56
|
+
|
57
|
+
assert !resolved
|
58
|
+
deferreds[0].resolve(42)
|
59
|
+
assert !resolved
|
60
|
+
deferreds[1].resolve(13)
|
61
|
+
assert !resolved
|
62
|
+
deferreds[2].resolve(3)
|
63
|
+
assert resolved
|
64
|
+
end
|
65
|
+
|
66
|
+
it "rejects when single deferrable rejects" do
|
67
|
+
deferred = When::Deferred.new
|
68
|
+
d = When.all([deferred.promise])
|
69
|
+
rejected = false
|
70
|
+
d.errback { |results| rejected = true }
|
71
|
+
|
72
|
+
assert !rejected
|
73
|
+
deferred.reject(StandardError.new)
|
74
|
+
assert rejected
|
75
|
+
end
|
76
|
+
|
77
|
+
it "rejects on first rejection" do
|
78
|
+
deferreds = [When::Deferred.new, When::Deferred.new, When::Deferred.new]
|
79
|
+
d = When.all(deferreds.map(&:promise))
|
80
|
+
rejected = false
|
81
|
+
d.errback { |results| rejected = true }
|
82
|
+
|
83
|
+
deferreds[0].resolve(42)
|
84
|
+
deferreds[2].reject(StandardError.new)
|
85
|
+
deferreds[1].resolve(13)
|
86
|
+
|
87
|
+
assert rejected
|
88
|
+
end
|
89
|
+
|
90
|
+
it "proxies resolution vaule in array" do
|
91
|
+
deferred = When::Deferred.new
|
92
|
+
d = When.all([deferred.promise])
|
93
|
+
results = nil
|
94
|
+
d.callback { |res| results = res }
|
95
|
+
|
96
|
+
deferred.resolve(42)
|
97
|
+
assert_equal [42], results
|
98
|
+
end
|
99
|
+
|
100
|
+
it "orders results like input" do
|
101
|
+
deferred1 = When::Deferred.new
|
102
|
+
deferred2 = When::Deferred.new
|
103
|
+
d = When.all([deferred1.promise, deferred2.promise])
|
104
|
+
results = nil
|
105
|
+
d.callback { |res| results = res }
|
106
|
+
|
107
|
+
deferred2.resolve(42)
|
108
|
+
deferred1.resolve(13)
|
109
|
+
assert_equal [13, 42], results
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -17,6 +17,7 @@
|
|
17
17
|
#++
|
18
18
|
require "test_helper"
|
19
19
|
require "dolt/git/repository"
|
20
|
+
require "time"
|
20
21
|
|
21
22
|
describe Dolt::Git::Repository do
|
22
23
|
include EM::MiniTest::Spec
|
@@ -57,4 +58,93 @@ describe Dolt::Git::Repository do
|
|
57
58
|
wait!
|
58
59
|
end
|
59
60
|
end
|
61
|
+
|
62
|
+
describe "#tree_history" do
|
63
|
+
before { @repository = Dolt::Git::Repository.new(".") }
|
64
|
+
|
65
|
+
it "returns deferrable" do
|
66
|
+
deferrable = @repository.tree_history("master", "")
|
67
|
+
assert deferrable.respond_to?(:callback)
|
68
|
+
assert deferrable.respond_to?(:errback)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "fails if path is not a tree" do
|
72
|
+
deferrable = @repository.tree_history("master", "Gemfile")
|
73
|
+
deferrable.errback do |err|
|
74
|
+
assert_match /not a tree/, err.message
|
75
|
+
done!
|
76
|
+
end
|
77
|
+
wait!
|
78
|
+
end
|
79
|
+
|
80
|
+
it "fails if path does not exist in ref" do
|
81
|
+
deferrable = @repository.tree_history("26139a3", "test")
|
82
|
+
deferrable.errback do |err|
|
83
|
+
assert_match /does not exist/, err.message
|
84
|
+
done!
|
85
|
+
end
|
86
|
+
wait!
|
87
|
+
end
|
88
|
+
|
89
|
+
it "yields tree with history" do
|
90
|
+
promise = @repository.tree_history("48ffbf7", "")
|
91
|
+
|
92
|
+
promise.callback do |log|
|
93
|
+
assert_equal 11, log.length
|
94
|
+
expected = {
|
95
|
+
:type => :blob,
|
96
|
+
:oid => "e90021f89616ddf86855d05337c188408d3b417e",
|
97
|
+
:filemode => 33188,
|
98
|
+
:name => ".gitmodules",
|
99
|
+
:history => [{
|
100
|
+
:oid => "906d67b4f3e5de7364ba9b57d174d8998d53ced6",
|
101
|
+
:author => { :name => "Christian Johansen",
|
102
|
+
:email => "christian@cjohansen.no" },
|
103
|
+
:summary => "Working Moron server for viewing blobs",
|
104
|
+
:date => Time.parse("Mon Sep 10 15:07:39 +0200 2012"),
|
105
|
+
:message => ""
|
106
|
+
}]
|
107
|
+
}
|
108
|
+
|
109
|
+
assert_equal expected, log[0]
|
110
|
+
done!
|
111
|
+
end
|
112
|
+
|
113
|
+
promise.errback do |err|
|
114
|
+
puts "FAILED! #{err.inspect}"
|
115
|
+
end
|
116
|
+
|
117
|
+
wait!
|
118
|
+
end
|
119
|
+
|
120
|
+
it "yields nested tree with history" do
|
121
|
+
promise = @repository.tree_history("48ffbf7", "lib")
|
122
|
+
|
123
|
+
promise.callback do |log|
|
124
|
+
expected = [{
|
125
|
+
:type => :tree,
|
126
|
+
:oid => "58f84405b588699b24c619aa4cd83669c5623f88",
|
127
|
+
:filemode => 16384,
|
128
|
+
:name => "dolt",
|
129
|
+
:history => [{
|
130
|
+
:oid => "8ab4f8c42511f727244a02aeee04824891610bbd",
|
131
|
+
:author => { :name => "Christian Johansen",
|
132
|
+
:email => "christian@gitorious.com" },
|
133
|
+
:summary => "New version",
|
134
|
+
:date => Time.parse("Mon Oct 1 16:34:00 +0200 2012"),
|
135
|
+
:message => ""
|
136
|
+
}]
|
137
|
+
}]
|
138
|
+
|
139
|
+
assert_equal expected, log
|
140
|
+
done!
|
141
|
+
end
|
142
|
+
|
143
|
+
promise.errback do |err|
|
144
|
+
puts "FAILED! #{err.inspect}"
|
145
|
+
end
|
146
|
+
|
147
|
+
wait!
|
148
|
+
end
|
149
|
+
end
|
60
150
|
end
|