libdolt 0.13.0 → 0.14.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 +6 -2
- data/lib/libdolt/git/archiver.rb +107 -0
- data/lib/libdolt/repo_actions.rb +10 -3
- data/lib/libdolt/version.rb +2 -2
- data/libdolt.gemspec +1 -0
- data/test/libdolt/git/archiver_test.rb +182 -0
- data/test/libdolt/templates/blob_test.rb +1 -0
- metadata +20 -2
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
libdolt (0.
|
4
|
+
libdolt (0.13.0)
|
5
5
|
em_pessimistic (~> 0.1)
|
6
6
|
em_rugged (~> 0.3)
|
7
7
|
eventmachine (~> 1.0)
|
@@ -25,13 +25,16 @@ GEM
|
|
25
25
|
eventmachine (1.0.0)
|
26
26
|
github-markup (0.7.4)
|
27
27
|
htmlentities (4.3.1)
|
28
|
-
json (1.7.
|
28
|
+
json (1.7.6)
|
29
29
|
makeup (0.3.0)
|
30
30
|
github-markup (~> 0.7)
|
31
31
|
htmlentities (~> 4.3)
|
32
32
|
pygments.rb (~> 0.2)
|
33
|
+
metaclass (0.0.1)
|
33
34
|
mime-types (1.19)
|
34
35
|
minitest (2.12.1)
|
36
|
+
mocha (0.13.1)
|
37
|
+
metaclass (~> 0.0.1)
|
35
38
|
posix-spawn (0.3.6)
|
36
39
|
pygments.rb (0.3.2)
|
37
40
|
posix-spawn (~> 0.3.6)
|
@@ -53,6 +56,7 @@ DEPENDENCIES
|
|
53
56
|
em-minitest-spec (~> 1.1)
|
54
57
|
libdolt!
|
55
58
|
minitest (~> 2.0)
|
59
|
+
mocha
|
56
60
|
rake (~> 0.9)
|
57
61
|
redcarpet (= 2.2.0)
|
58
62
|
tiltout (~> 1.4)
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#--
|
3
|
+
# Copyright (C) 2013 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 "when"
|
19
|
+
require "eventmachine"
|
20
|
+
require "em_pessimistic"
|
21
|
+
require "fileutils"
|
22
|
+
|
23
|
+
module Dolt
|
24
|
+
module Git
|
25
|
+
class Archiver
|
26
|
+
def initialize(work_dir, cache_dir)
|
27
|
+
# A hash of currently processing archiving jobs. It contains tuples of
|
28
|
+
# "#{repo.id}-#{oid}-#{format}" => promises representing the eventual
|
29
|
+
# completion of archiving tasks. When an archiving task is completed,
|
30
|
+
# its promise is removed from the hash. Previously generated tarballs
|
31
|
+
# can be found on disk.
|
32
|
+
@processing = {}
|
33
|
+
@work_dir = work_dir
|
34
|
+
@cache_dir = cache_dir
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns a promise that resolves with the filename of the generated
|
38
|
+
# tarball/zip file.
|
39
|
+
#
|
40
|
+
# repo - A repository object
|
41
|
+
# oid - A valid commit oid
|
42
|
+
# format - A symbol. If it is not :zip, tar.gz is assumed.
|
43
|
+
def archive(repo, oid, format = :tgz)
|
44
|
+
filename = cache_path(repo, oid, format)
|
45
|
+
return When.resolve(filename) if File.exists?(filename)
|
46
|
+
pending = pending_process(repo, oid, format)
|
47
|
+
return pending if pending
|
48
|
+
start_process(repo, oid, format)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def process_id(repo, oid, format)
|
53
|
+
"#{repo.id}-#{oid}-#{ext(format)}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def pending_process(repo, oid, format)
|
57
|
+
@processing[process_id(repo, oid, format)]
|
58
|
+
end
|
59
|
+
|
60
|
+
def start_process(repo, oid, format)
|
61
|
+
@processing[process_id(repo, oid, format)] = When.defer do |d|
|
62
|
+
p = EMPessimistic::DeferrableChildProcess.open(cmd(repo, oid, format))
|
63
|
+
|
64
|
+
p.callback do |output, status|
|
65
|
+
filename = cache_path(repo, oid, format)
|
66
|
+
FileUtils.mv(work_path(repo, oid, format), filename)
|
67
|
+
d.resolve(filename)
|
68
|
+
end
|
69
|
+
|
70
|
+
p.errback do |output, status|
|
71
|
+
d.reject(Exception.new(output))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def cmd(repository, oid, format)
|
77
|
+
path_segment = repository.path_segment.gsub(/\//, "-")
|
78
|
+
cmd = "sh -c 'git --git-dir #{repository.full_repository_path} archive "
|
79
|
+
cmd += "--prefix='#{u(path_segment)}/' --format="
|
80
|
+
wpath = u(work_path(repository, oid, format))
|
81
|
+
cmd + (format.to_s == "zip" ? "zip #{u(oid)} > #{wpath}" : "tar #{u(oid)} | gzip -m > #{wpath}") + "'"
|
82
|
+
end
|
83
|
+
|
84
|
+
def cache_path(repository, oid, format)
|
85
|
+
File.join(@cache_dir, basename(repository, oid, format))
|
86
|
+
end
|
87
|
+
|
88
|
+
def work_path(repository, oid, format)
|
89
|
+
File.join(@work_dir, basename(repository, oid, format))
|
90
|
+
end
|
91
|
+
|
92
|
+
def basename(repository, oid, format)
|
93
|
+
path_segment = repository.path_segment.gsub(/\//, "-")
|
94
|
+
"#{path_segment}-#{oid}.#{ext(format)}"
|
95
|
+
end
|
96
|
+
|
97
|
+
def ext(format)
|
98
|
+
format.to_s == "zip" ? "zip" : "tar.gz"
|
99
|
+
end
|
100
|
+
|
101
|
+
# Unquote a string by stripping off any single or double quotes
|
102
|
+
def u(string)
|
103
|
+
string.gsub("'", '').gsub('"', '')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/lib/libdolt/repo_actions.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
|
2
1
|
# encoding: utf-8
|
3
2
|
#--
|
4
|
-
# Copyright (C) 2012 Gitorious AS
|
3
|
+
# Copyright (C) 2012-2013 Gitorious AS
|
5
4
|
#
|
6
5
|
# This program is free software: you can redistribute it and/or modify
|
7
6
|
# it under the terms of the GNU Affero General Public License as published by
|
@@ -24,8 +23,9 @@ class Time; def to_json(*args); "\"#{iso8601}\""; end; end
|
|
24
23
|
|
25
24
|
module Dolt
|
26
25
|
class RepoActions
|
27
|
-
def initialize(repo_resolver)
|
26
|
+
def initialize(repo_resolver, archiver = nil)
|
28
27
|
@repo_resolver = repo_resolver
|
28
|
+
@archiver = archiver
|
29
29
|
end
|
30
30
|
|
31
31
|
def blob(repo, ref, path, &block)
|
@@ -71,6 +71,13 @@ module Dolt
|
|
71
71
|
repo_action(repo, ref, path, :tree, :tree_history, ref, path, count, &block)
|
72
72
|
end
|
73
73
|
|
74
|
+
def archive(repo, ref, format, &block)
|
75
|
+
repository = resolve_repository(repo)
|
76
|
+
d = @archiver.archive(repository, ref, format)
|
77
|
+
d.callback { |filename| block.call(nil, filename) }
|
78
|
+
d.errback { |err| block.call(err, nil) }
|
79
|
+
end
|
80
|
+
|
74
81
|
def repositories
|
75
82
|
repo_resolver.all
|
76
83
|
end
|
data/lib/libdolt/version.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
#--
|
3
|
-
# Copyright (C) 2012 Gitorious AS
|
3
|
+
# Copyright (C) 2012-2013 Gitorious AS
|
4
4
|
#
|
5
5
|
# This program is free software: you can redistribute it and/or modify
|
6
6
|
# it under the terms of the GNU Affero General Public License as published by
|
@@ -17,5 +17,5 @@
|
|
17
17
|
#++
|
18
18
|
|
19
19
|
module Dolt
|
20
|
-
VERSION = "0.
|
20
|
+
VERSION = "0.14.0"
|
21
21
|
end
|
data/libdolt.gemspec
CHANGED
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_development_dependency "rake", "~> 0.9"
|
29
29
|
s.add_development_dependency "redcarpet", "2.2.0"
|
30
30
|
s.add_development_dependency "tiltout", "~>1.4"
|
31
|
+
s.add_development_dependency "mocha"
|
31
32
|
|
32
33
|
s.files = `git ls-files`.split("\n")
|
33
34
|
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
@@ -0,0 +1,182 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#--
|
3
|
+
# Copyright (C) 2013 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 "mocha/setup"
|
20
|
+
require "libdolt/git/archiver"
|
21
|
+
|
22
|
+
class StubRepository
|
23
|
+
attr_reader :id, :full_repository_path, :path_segment
|
24
|
+
def initialize(path_segment)
|
25
|
+
@@counter ||= 0
|
26
|
+
@id = (@@counter += 1)
|
27
|
+
@full_repository_path = "/repos/#{path_segment}.git"
|
28
|
+
@path_segment = path_segment
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class StubProcessStatus
|
33
|
+
attr_reader :exitstatus
|
34
|
+
def initialize(code)
|
35
|
+
@exitstatus = code
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe Dolt::Git::Archiver do
|
40
|
+
include EM::MiniTest::Spec
|
41
|
+
|
42
|
+
describe "archive" do
|
43
|
+
before do
|
44
|
+
@archiver = Dolt::Git::Archiver.new("/work", "/cache")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "resolves with existing cached file" do
|
48
|
+
File.stubs(:exists?).with("/cache/gts-mainline-master.tar.gz").returns(true)
|
49
|
+
repo = StubRepository.new("gts/mainline")
|
50
|
+
|
51
|
+
@archiver.archive(repo, "master", :tar).then do |filename|
|
52
|
+
assert_equal "/cache/gts-mainline-master.tar.gz", filename
|
53
|
+
done!
|
54
|
+
end
|
55
|
+
wait!
|
56
|
+
end
|
57
|
+
|
58
|
+
it "generates tarball" do
|
59
|
+
repo = StubRepository.new("gts/mainline")
|
60
|
+
|
61
|
+
cmd = "sh -c 'git --git-dir /repos/gts/mainline.git archive --prefix='gts-mainline/' " +
|
62
|
+
"--format=tar master | gzip -m > /work/gts-mainline-master.tar.gz'"
|
63
|
+
d = EM::DefaultDeferrable.new
|
64
|
+
EMPessimistic::DeferrableChildProcess.expects(:open).with(cmd).returns(d)
|
65
|
+
|
66
|
+
@archiver.archive(repo, "master", :tar)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "uses gzip format from string" do
|
70
|
+
repo = StubRepository.new("gts/mainline")
|
71
|
+
|
72
|
+
cmd = "sh -c 'git --git-dir /repos/gts/mainline.git archive --prefix='gts-mainline/' " +
|
73
|
+
"--format=tar master | gzip -m > /work/gts-mainline-master.tar.gz'"
|
74
|
+
d = EM::DefaultDeferrable.new
|
75
|
+
EMPessimistic::DeferrableChildProcess.expects(:open).with(cmd).returns(d)
|
76
|
+
|
77
|
+
@archiver.archive(repo, "master", "tar")
|
78
|
+
end
|
79
|
+
|
80
|
+
it "uses zip format from string" do
|
81
|
+
repo = StubRepository.new("gts/mainline")
|
82
|
+
|
83
|
+
cmd = "sh -c 'git --git-dir /repos/gts/mainline.git archive --prefix='gts-mainline/' " +
|
84
|
+
"--format=zip master > /work/gts-mainline-master.zip'"
|
85
|
+
d = EM::DefaultDeferrable.new
|
86
|
+
EMPessimistic::DeferrableChildProcess.expects(:open).with(cmd).returns(d)
|
87
|
+
|
88
|
+
@archiver.archive(repo, "master", "zip")
|
89
|
+
end
|
90
|
+
|
91
|
+
it "moves tarball when successfully generated" do
|
92
|
+
FileUtils.expects(:mv).with("/work/gts-mainline-master.tar.gz",
|
93
|
+
"/cache/gts-mainline-master.tar.gz")
|
94
|
+
repo = StubRepository.new("gts/mainline")
|
95
|
+
d = EM::DefaultDeferrable.new
|
96
|
+
EMPessimistic::DeferrableChildProcess.expects(:open).returns(d)
|
97
|
+
d.succeed("", StubProcessStatus.new(0))
|
98
|
+
|
99
|
+
@archiver.archive(repo, "master", :tar)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "does not move tarball when raising error" do
|
103
|
+
FileUtils.expects(:mv).with("/work/gts-mainline-master.tar.gz",
|
104
|
+
"/cache/gts-mainline-master.tar.gz").never
|
105
|
+
repo = StubRepository.new("gts/mainline")
|
106
|
+
d = EM::DefaultDeferrable.new
|
107
|
+
EMPessimistic::DeferrableChildProcess.expects(:open).returns(d)
|
108
|
+
d.fail("", StubProcessStatus.new(1))
|
109
|
+
|
110
|
+
@archiver.archive(repo, "master", :tar)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "resolves promise with generated filename" do
|
114
|
+
FileUtils.stubs(:mv)
|
115
|
+
repo = StubRepository.new("gts/mainline")
|
116
|
+
d = EM::DefaultDeferrable.new
|
117
|
+
EMPessimistic::DeferrableChildProcess.expects(:open).returns(d)
|
118
|
+
d.succeed("", StubProcessStatus.new(0))
|
119
|
+
|
120
|
+
@archiver.archive(repo, "master", :tar).then do |filename|
|
121
|
+
assert_equal "/cache/gts-mainline-master.tar.gz", filename
|
122
|
+
done!
|
123
|
+
end
|
124
|
+
wait!
|
125
|
+
end
|
126
|
+
|
127
|
+
it "rejects promise when failing to archive" do
|
128
|
+
repo = StubRepository.new("gts/mainline")
|
129
|
+
d = EM::DefaultDeferrable.new
|
130
|
+
EMPessimistic::DeferrableChildProcess.expects(:open).returns(d)
|
131
|
+
d.fail("It done failed", StubProcessStatus.new(1))
|
132
|
+
|
133
|
+
@archiver.archive(repo, "master", :tar).errback do |err|
|
134
|
+
assert_match "It done failed", err.message
|
135
|
+
done!
|
136
|
+
end
|
137
|
+
wait!
|
138
|
+
end
|
139
|
+
|
140
|
+
it "does not spawn multiple identical processes" do
|
141
|
+
FileUtils.stubs(:mv)
|
142
|
+
repo = StubRepository.new("gts/mainline")
|
143
|
+
d = EM::DefaultDeferrable.new
|
144
|
+
EMPessimistic::DeferrableChildProcess.expects(:open).once.returns(d)
|
145
|
+
callbacks = 0
|
146
|
+
blk = lambda do |filename|
|
147
|
+
assert_equal "/cache/gts-mainline-master.tar.gz", filename
|
148
|
+
callbacks += 1
|
149
|
+
done! if callbacks == 2
|
150
|
+
end
|
151
|
+
|
152
|
+
@archiver.archive(repo, "master", :tar).then(&blk)
|
153
|
+
@archiver.archive(repo, "master", :tar).then(&blk)
|
154
|
+
|
155
|
+
wait!
|
156
|
+
d.succeed("", StubProcessStatus.new(0))
|
157
|
+
end
|
158
|
+
|
159
|
+
it "spawns new process when format is different" do
|
160
|
+
FileUtils.stubs(:mv)
|
161
|
+
repo = StubRepository.new("gts/mainline")
|
162
|
+
d = EM::DefaultDeferrable.new
|
163
|
+
EMPessimistic::DeferrableChildProcess.expects(:open).twice.returns(d)
|
164
|
+
callbacks = 0
|
165
|
+
|
166
|
+
@archiver.archive(repo, "master", :tar).then do |filename|
|
167
|
+
assert_equal "/cache/gts-mainline-master.tar.gz", filename
|
168
|
+
callbacks += 1
|
169
|
+
done! if callbacks == 2
|
170
|
+
end
|
171
|
+
|
172
|
+
@archiver.archive(repo, "master", :zip).then do |filename|
|
173
|
+
assert_equal "/cache/gts-mainline-master.zip", filename
|
174
|
+
callbacks += 1
|
175
|
+
done! if callbacks == 2
|
176
|
+
end
|
177
|
+
|
178
|
+
wait!
|
179
|
+
d.succeed("", StubProcessStatus.new(0))
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: libdolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
@@ -235,6 +235,22 @@ dependencies:
|
|
235
235
|
- - ~>
|
236
236
|
- !ruby/object:Gem::Version
|
237
237
|
version: '1.4'
|
238
|
+
- !ruby/object:Gem::Dependency
|
239
|
+
name: mocha
|
240
|
+
requirement: !ruby/object:Gem::Requirement
|
241
|
+
none: false
|
242
|
+
requirements:
|
243
|
+
- - ! '>='
|
244
|
+
- !ruby/object:Gem::Version
|
245
|
+
version: '0'
|
246
|
+
type: :development
|
247
|
+
prerelease: false
|
248
|
+
version_requirements: !ruby/object:Gem::Requirement
|
249
|
+
none: false
|
250
|
+
requirements:
|
251
|
+
- - ! '>='
|
252
|
+
- !ruby/object:Gem::Version
|
253
|
+
version: '0'
|
238
254
|
description: Dolt API for serving git trees and syntax highlighted blobs
|
239
255
|
email:
|
240
256
|
- christian@gitorious.org
|
@@ -249,6 +265,7 @@ files:
|
|
249
265
|
- Readme.md
|
250
266
|
- lib/libdolt.rb
|
251
267
|
- lib/libdolt/disk_repo_resolver.rb
|
268
|
+
- lib/libdolt/git/archiver.rb
|
252
269
|
- lib/libdolt/git/blame.rb
|
253
270
|
- lib/libdolt/git/commit.rb
|
254
271
|
- lib/libdolt/git/repository.rb
|
@@ -274,6 +291,7 @@ files:
|
|
274
291
|
- lib/libdolt/view/tree.rb
|
275
292
|
- lib/libdolt/view/urls.rb
|
276
293
|
- libdolt.gemspec
|
294
|
+
- test/libdolt/git/archiver_test.rb
|
277
295
|
- test/libdolt/git/blame_test.rb
|
278
296
|
- test/libdolt/git/commit_test.rb
|
279
297
|
- test/libdolt/git/repository_test.rb
|