grack 0.0.2 → 0.1.0.pre1
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.
- checksums.yaml +7 -0
- data/.travis.yml +7 -0
- data/.yardopts +1 -0
- data/LICENSE +22 -0
- data/NEWS.md +19 -0
- data/README.md +211 -0
- data/Rakefile +222 -0
- data/lib/git_adapter.rb +1 -0
- data/lib/grack.rb +1 -0
- data/lib/grack/app.rb +482 -0
- data/lib/grack/compatible_git_adapter.rb +99 -0
- data/lib/grack/file_streamer.rb +41 -0
- data/lib/grack/git_adapter.rb +142 -0
- data/lib/grack/io_streamer.rb +45 -0
- data/tests/app_test.rb +534 -0
- data/tests/compatible_git_adapter_test.rb +137 -0
- data/tests/example/_git/COMMIT_EDITMSG +1 -0
- data/tests/example/_git/HEAD +1 -0
- data/tests/example/_git/config +6 -0
- data/tests/example/_git/description +1 -0
- data/tests/example/_git/hooks/applypatch-msg.sample +15 -0
- data/tests/example/_git/hooks/commit-msg.sample +24 -0
- data/tests/example/_git/hooks/post-commit.sample +8 -0
- data/tests/example/_git/hooks/post-receive.sample +15 -0
- data/tests/example/_git/hooks/post-update.sample +8 -0
- data/tests/example/_git/hooks/pre-applypatch.sample +14 -0
- data/tests/example/_git/hooks/pre-commit.sample +50 -0
- data/tests/example/_git/hooks/pre-rebase.sample +169 -0
- data/tests/example/_git/hooks/prepare-commit-msg.sample +36 -0
- data/tests/example/_git/hooks/update.sample +128 -0
- data/tests/example/_git/index +0 -0
- data/tests/example/_git/info/exclude +6 -0
- data/tests/example/_git/info/refs +1 -0
- data/tests/example/_git/logs/HEAD +1 -0
- data/tests/example/_git/logs/refs/heads/master +1 -0
- data/tests/example/_git/objects/31/d73eb4914a8ddb6cb0e4adf250777161118f90 +0 -0
- data/tests/example/_git/objects/cb/067e06bdf6e34d4abebf6cf2de85d65a52c65e +0 -0
- data/tests/example/_git/objects/ce/013625030ba8dba906f756967f9e9ca394464a +0 -0
- data/tests/example/_git/objects/info/packs +2 -0
- data/tests/example/_git/objects/pack/pack-62c9f443d8405cd6da92dcbb4f849cc01a339c06.idx +0 -0
- data/tests/example/_git/objects/pack/pack-62c9f443d8405cd6da92dcbb4f849cc01a339c06.pack +0 -0
- data/tests/example/_git/refs/heads/master +1 -0
- data/tests/file_streamer_test.rb +37 -0
- data/tests/git_adapter_test.rb +104 -0
- data/tests/io_streamer_test.rb +36 -0
- data/tests/test_helper.rb +36 -0
- metadata +292 -19
- data/lib/git_http.rb +0 -304
data/lib/git_adapter.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'grack/git_adapter'
|
data/lib/grack.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'grack/app'
|
data/lib/grack/app.rb
ADDED
@@ -0,0 +1,482 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'rack/request'
|
3
|
+
require 'rack/response'
|
4
|
+
require 'time'
|
5
|
+
require 'zlib'
|
6
|
+
|
7
|
+
require 'grack/git_adapter'
|
8
|
+
|
9
|
+
##
|
10
|
+
# A namespace for all Grack functionality.
|
11
|
+
module Grack
|
12
|
+
##
|
13
|
+
# A Rack application for serving Git repositories over HTTP.
|
14
|
+
class App
|
15
|
+
##
|
16
|
+
# A list of supported pack service types.
|
17
|
+
VALID_SERVICE_TYPES = %w{git-upload-pack git-receive-pack}
|
18
|
+
|
19
|
+
##
|
20
|
+
# Route mappings from URIs to valid verbs and handler functions.
|
21
|
+
ROUTES = [
|
22
|
+
[%r'/(.*?)/(git-(?:upload|receive)-pack)$', 'POST', :handle_pack],
|
23
|
+
[%r'/(.*?)/info/refs$', 'GET', :info_refs],
|
24
|
+
[%r'/(.*?)/(HEAD)$', 'GET', :text_file],
|
25
|
+
[%r'/(.*?)/(objects/info/alternates)$', 'GET', :text_file],
|
26
|
+
[%r'/(.*?)/(objects/info/http-alternates)$', 'GET', :text_file],
|
27
|
+
[%r'/(.*?)/(objects/info/packs)$', 'GET', :info_packs],
|
28
|
+
[%r'/(.*?)/(objects/info/[^/]+)$', 'GET', :text_file],
|
29
|
+
[%r'/(.*?)/(objects/[0-9a-f]{2}/[0-9a-f]{38})$', 'GET', :loose_object],
|
30
|
+
[%r'/(.*?)/(objects/pack/pack-[0-9a-f]{40}\.pack)$', 'GET', :pack_file],
|
31
|
+
[%r'/(.*?)/(objects/pack/pack-[0-9a-f]{40}\.idx)$', 'GET', :idx_file],
|
32
|
+
]
|
33
|
+
|
34
|
+
##
|
35
|
+
# Creates a new instance of this application with the configuration provided
|
36
|
+
# by _opts_.
|
37
|
+
#
|
38
|
+
# @param [Hash] opts a hash of supported options.
|
39
|
+
# @option opts [String] :root (Dir.pwd) a directory path containing 1 or
|
40
|
+
# more Git repositories.
|
41
|
+
# @option opts [Boolean, nil] :allow_push (nil) determines whether or not to
|
42
|
+
# allow pushes into the repositories. +nil+ means to defer to the
|
43
|
+
# requested repository.
|
44
|
+
# @option opts [Boolean, nil] :allow_pull (nil) determines whether or not to
|
45
|
+
# allow fetches/pulls from the repositories. +nil+ means to defer to the
|
46
|
+
# requested repository.
|
47
|
+
# @option opts [#call] :git_adapter_factory (->{ GitAdapter.new }) a
|
48
|
+
# call-able object that creates Git adapter instances per request.
|
49
|
+
def initialize(opts = {})
|
50
|
+
opts = convert_old_opts(opts)
|
51
|
+
|
52
|
+
@root = Pathname.new(opts.fetch(:root, '.')).expand_path
|
53
|
+
@allow_push = opts.fetch(:allow_push, nil)
|
54
|
+
@allow_pull = opts.fetch(:allow_pull, nil)
|
55
|
+
@git_adapter_factory =
|
56
|
+
opts.fetch(:git_adapter_factory, ->{ GitAdapter.new })
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# The Rack handler entry point for this application. This duplicates the
|
61
|
+
# object and uses the duplicate to perform the work in order to enable
|
62
|
+
# thread safe request handling.
|
63
|
+
#
|
64
|
+
# @param [Hash] env a Rack request hash.
|
65
|
+
#
|
66
|
+
# @return a Rack response object.
|
67
|
+
def call(env)
|
68
|
+
dup._call(env)
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
##
|
74
|
+
# The real request handler.
|
75
|
+
#
|
76
|
+
# @param [Hash] env a Rack request hash.
|
77
|
+
#
|
78
|
+
# @return a Rack response object.
|
79
|
+
def _call(env)
|
80
|
+
@git = @git_adapter_factory.call
|
81
|
+
@env = env
|
82
|
+
@request = Rack::Request.new(env)
|
83
|
+
route
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
##
|
89
|
+
# The Rack request hash.
|
90
|
+
attr_reader :env
|
91
|
+
|
92
|
+
##
|
93
|
+
# The request object built from the request hash.
|
94
|
+
attr_reader :request
|
95
|
+
|
96
|
+
##
|
97
|
+
# The Git adapter instance for the requested repository.
|
98
|
+
attr_reader :git
|
99
|
+
|
100
|
+
##
|
101
|
+
# The path containing 1 or more Git repositories which may be requested.
|
102
|
+
attr_reader :root
|
103
|
+
|
104
|
+
##
|
105
|
+
# The path to the repository.
|
106
|
+
attr_reader :repository_uri
|
107
|
+
|
108
|
+
##
|
109
|
+
# The HTTP verb of the request.
|
110
|
+
attr_reader :request_verb
|
111
|
+
|
112
|
+
##
|
113
|
+
# The requested pack type. Will be +nil+ for requests that do no involve
|
114
|
+
# pack RPCs.
|
115
|
+
attr_reader :pack_type
|
116
|
+
|
117
|
+
##
|
118
|
+
# @return [Boolean] +true+ if the request is authorized; otherwise, +false+.
|
119
|
+
def authorized?
|
120
|
+
return allow_pull? if need_read?
|
121
|
+
return allow_push?
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# @return [Boolean] +true+ if read permissions are needed; otherwise,
|
126
|
+
# +false+.
|
127
|
+
def need_read?
|
128
|
+
(request_verb == 'GET' && pack_type != 'git-receive-pack') ||
|
129
|
+
request_verb == 'POST' && pack_type == 'git-upload-pack'
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# Determines whether or not pushes into the requested repository are
|
134
|
+
# allowed.
|
135
|
+
#
|
136
|
+
# @return [Boolean] +true+ if pushes are allowed, +false+ otherwise.
|
137
|
+
def allow_push?
|
138
|
+
@allow_push || (@allow_push.nil? && git.allow_push?)
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Determines whether or not fetches/pulls from the requested repository are
|
143
|
+
# allowed.
|
144
|
+
#
|
145
|
+
# @return [Boolean] +true+ if fetches are allowed, +false+ otherwise.
|
146
|
+
def allow_pull?
|
147
|
+
@allow_pull || (@allow_pull.nil? && git.allow_pull?)
|
148
|
+
end
|
149
|
+
|
150
|
+
##
|
151
|
+
# Routes requests to appropriate handlers. Performs request path cleanup
|
152
|
+
# and several sanity checks prior to attempting to handle the request.
|
153
|
+
#
|
154
|
+
# @return a Rack response object.
|
155
|
+
def route
|
156
|
+
# Sanitize the URI:
|
157
|
+
# * Unescape escaped characters
|
158
|
+
# * Replace runs of / with a single /
|
159
|
+
path_info = Rack::Utils.unescape(request.path_info).gsub(%r{/+}, '/')
|
160
|
+
|
161
|
+
ROUTES.each do |path_matcher, verb, handler|
|
162
|
+
path_info.match(path_matcher) do |match|
|
163
|
+
@repository_uri = match[1]
|
164
|
+
@request_verb = verb
|
165
|
+
|
166
|
+
return method_not_allowed unless verb == request.request_method
|
167
|
+
return bad_request if bad_uri?(@repository_uri)
|
168
|
+
|
169
|
+
git.repository_path = root + @repository_uri
|
170
|
+
return not_found unless git.exist?
|
171
|
+
|
172
|
+
return send(handler, *match[2..-1])
|
173
|
+
end
|
174
|
+
end
|
175
|
+
not_found
|
176
|
+
end
|
177
|
+
|
178
|
+
##
|
179
|
+
# Processes pack file exchange requests for both push and pull. Ensures
|
180
|
+
# that the request is allowed and properly formatted.
|
181
|
+
#
|
182
|
+
# @param [String] pack_type the type of pack exchange to perform per the
|
183
|
+
# request.
|
184
|
+
#
|
185
|
+
# @return a Rack response object.
|
186
|
+
def handle_pack(pack_type)
|
187
|
+
@pack_type = pack_type
|
188
|
+
unless request.content_type == "application/x-#{@pack_type}-request" &&
|
189
|
+
valid_pack_type? && authorized?
|
190
|
+
return no_access
|
191
|
+
end
|
192
|
+
|
193
|
+
headers = {'Content-Type' => "application/x-#{@pack_type}-result"}
|
194
|
+
exchange_pack(headers, request_io_in)
|
195
|
+
end
|
196
|
+
|
197
|
+
##
|
198
|
+
# Processes requests for the list of refs for the requested repository.
|
199
|
+
#
|
200
|
+
# This works for both Smart HTTP clients and basic ones. For basic clients,
|
201
|
+
# the Git adapter is used to update the +info/refs+ file which is then
|
202
|
+
# served to the clients. For Smart HTTP clients, the more efficient pack
|
203
|
+
# file exchange mechanism is used.
|
204
|
+
#
|
205
|
+
# @return a Rack response object.
|
206
|
+
def info_refs
|
207
|
+
@pack_type = request.params['service']
|
208
|
+
return no_access unless authorized?
|
209
|
+
|
210
|
+
if @pack_type.nil?
|
211
|
+
git.update_server_info
|
212
|
+
send_file(
|
213
|
+
git.file('info/refs'), 'text/plain; charset=utf-8', hdr_nocache
|
214
|
+
)
|
215
|
+
elsif valid_pack_type?
|
216
|
+
headers = hdr_nocache
|
217
|
+
headers['Content-Type'] = "application/x-#{@pack_type}-advertisement"
|
218
|
+
exchange_pack(headers, nil, {:advertise_refs => true})
|
219
|
+
else
|
220
|
+
not_found
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
##
|
225
|
+
# Processes requests for info packs for the requested repository.
|
226
|
+
#
|
227
|
+
# @param [String] path the path to an info pack file within a Git
|
228
|
+
# repository.
|
229
|
+
#
|
230
|
+
# @return a Rack response object.
|
231
|
+
def info_packs(path)
|
232
|
+
return no_access unless authorized?
|
233
|
+
send_file(git.file(path), 'text/plain; charset=utf-8', hdr_nocache)
|
234
|
+
end
|
235
|
+
|
236
|
+
##
|
237
|
+
# Processes a request for a loose object at _path_ for the selected
|
238
|
+
# repository. If the file is located, the content type is set to
|
239
|
+
# +application/x-git-loose-object+ and permanent caching is enabled.
|
240
|
+
#
|
241
|
+
# @param [String] path the path to a loose object file within a Git
|
242
|
+
# repository, such as +objects/31/d73eb4914a8ddb6cb0e4adf250777161118f90+.
|
243
|
+
#
|
244
|
+
# @return a Rack response object.
|
245
|
+
def loose_object(path)
|
246
|
+
return no_access unless authorized?
|
247
|
+
send_file(
|
248
|
+
git.file(path), 'application/x-git-loose-object', hdr_cache_forever
|
249
|
+
)
|
250
|
+
end
|
251
|
+
|
252
|
+
##
|
253
|
+
# Process a request for a pack file located at _path_ for the selected
|
254
|
+
# repository. If the file is located, the content type is set to
|
255
|
+
# +application/x-git-packed-objects+ and permanent caching is enabled.
|
256
|
+
#
|
257
|
+
# @param [String] path the path to a pack file within a Git repository such
|
258
|
+
# as +pack/pack-62c9f443d8405cd6da92dcbb4f849cc01a339c06.pack+.
|
259
|
+
#
|
260
|
+
# @return a Rack response object.
|
261
|
+
def pack_file(path)
|
262
|
+
return no_access unless authorized?
|
263
|
+
send_file(
|
264
|
+
git.file(path), 'application/x-git-packed-objects', hdr_cache_forever
|
265
|
+
)
|
266
|
+
end
|
267
|
+
|
268
|
+
##
|
269
|
+
# Process a request for a pack index file located at _path_ for the selected
|
270
|
+
# repository. If the file is located, the content type is set to
|
271
|
+
# +application/x-git-packed-objects-toc+ and permanent caching is enabled.
|
272
|
+
#
|
273
|
+
# @param [String] path the path to a pack index file within a Git
|
274
|
+
# repository, such as
|
275
|
+
# +pack/pack-62c9f443d8405cd6da92dcbb4f849cc01a339c06.idx+.
|
276
|
+
#
|
277
|
+
# @return a Rack response object.
|
278
|
+
def idx_file(path)
|
279
|
+
return no_access unless authorized?
|
280
|
+
send_file(
|
281
|
+
git.file(path),
|
282
|
+
'application/x-git-packed-objects-toc',
|
283
|
+
hdr_cache_forever
|
284
|
+
)
|
285
|
+
end
|
286
|
+
|
287
|
+
##
|
288
|
+
# Process a request for a generic file located at _path_ for the selected
|
289
|
+
# repository. If the file is located, the content type is set to
|
290
|
+
# +text/plain+ and caching is disabled.
|
291
|
+
#
|
292
|
+
# @param [String] path the path to a file within a Git repository, such as
|
293
|
+
# +HEAD+.
|
294
|
+
#
|
295
|
+
# @return a Rack response object.
|
296
|
+
def text_file(path)
|
297
|
+
return no_access unless authorized?
|
298
|
+
send_file(git.file(path), 'text/plain', hdr_nocache)
|
299
|
+
end
|
300
|
+
|
301
|
+
##
|
302
|
+
# Produces a Rack response that wraps the output from the Git adapter.
|
303
|
+
#
|
304
|
+
# A 404 response is produced if _streamer_ is +nil+. Otherwise a 200
|
305
|
+
# response is produced with _streamer_ as the response body.
|
306
|
+
#
|
307
|
+
# @param [FileStreamer,IOStreamer] streamer a provider of content for the
|
308
|
+
# response body.
|
309
|
+
# @param [String] content_type the MIME type of the content.
|
310
|
+
# @param [Hash] headers additional headers to include in the response.
|
311
|
+
#
|
312
|
+
# @return a Rack response object.
|
313
|
+
def send_file(streamer, content_type, headers = {})
|
314
|
+
return not_found if streamer.nil?
|
315
|
+
|
316
|
+
headers['Content-Type'] = content_type
|
317
|
+
headers['Last-Modified'] = streamer.mtime.httpdate
|
318
|
+
|
319
|
+
[200, headers, streamer]
|
320
|
+
end
|
321
|
+
|
322
|
+
##
|
323
|
+
# Opens a tunnel for the pack file exchange protocol between the client and
|
324
|
+
# the Git adapter.
|
325
|
+
#
|
326
|
+
# @param [Hash] headers headers to provide in the Rack response.
|
327
|
+
# @param [#read] io_in a readable, IO-like object providing client input
|
328
|
+
# data.
|
329
|
+
# @param [Hash] opts options to pass to the Git adapter's #handle_pack
|
330
|
+
# method.
|
331
|
+
#
|
332
|
+
# @return a Rack response object.
|
333
|
+
def exchange_pack(headers, io_in, opts = {})
|
334
|
+
Rack::Response.new([], 200, headers).finish do |response|
|
335
|
+
git.handle_pack(pack_type, io_in, response, opts)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
##
|
340
|
+
# Transparently ensures that the request body is not compressed.
|
341
|
+
#
|
342
|
+
# @return [#read] a +read+-able object that yields uncompressed data from
|
343
|
+
# the request body.
|
344
|
+
def request_io_in
|
345
|
+
return request.body unless env['HTTP_CONTENT_ENCODING'] =~ /gzip/
|
346
|
+
Zlib::GzipReader.new(request.body)
|
347
|
+
end
|
348
|
+
|
349
|
+
##
|
350
|
+
# Determines whether or not the requested pack type is valid.
|
351
|
+
#
|
352
|
+
# @return [Boolean] +true+ if the pack type is valid; otherwise, +false+.
|
353
|
+
def valid_pack_type?
|
354
|
+
VALID_SERVICE_TYPES.include?(pack_type)
|
355
|
+
end
|
356
|
+
|
357
|
+
##
|
358
|
+
# Determines whether or not _path_ is an acceptable URI.
|
359
|
+
#
|
360
|
+
# @param [String] path the path part of the request URI.
|
361
|
+
#
|
362
|
+
# @return [Boolean] +true+ if the requested path is considered invalid;
|
363
|
+
# otherwise, +false+.
|
364
|
+
def bad_uri?(path)
|
365
|
+
invalid_segments = %w{. ..}
|
366
|
+
path.split('/').any? { |segment| invalid_segments.include?(segment) }
|
367
|
+
end
|
368
|
+
|
369
|
+
# --------------------------------------
|
370
|
+
# HTTP error response handling functions
|
371
|
+
# --------------------------------------
|
372
|
+
|
373
|
+
##
|
374
|
+
# A shorthand for specifying a text content type for the Rack response.
|
375
|
+
PLAIN_TYPE = {'Content-Type' => 'text/plain'}
|
376
|
+
|
377
|
+
##
|
378
|
+
# Returns a Rack response appropriate for requests that use invalid verbs
|
379
|
+
# for the requested resources.
|
380
|
+
#
|
381
|
+
# For HTTP 1.1 requests, a 405 code is returned. For other versions, the
|
382
|
+
# value from #bad_request is returned.
|
383
|
+
#
|
384
|
+
# @return a Rack response appropriate for requests that use invalid verbs
|
385
|
+
# for the requested resources.
|
386
|
+
def method_not_allowed
|
387
|
+
if env['SERVER_PROTOCOL'] == 'HTTP/1.1'
|
388
|
+
[405, PLAIN_TYPE, ['Method Not Allowed']]
|
389
|
+
else
|
390
|
+
bad_request
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
##
|
395
|
+
# @return a Rack response for generally bad requests.
|
396
|
+
def bad_request
|
397
|
+
[400, PLAIN_TYPE, ['Bad Request']]
|
398
|
+
end
|
399
|
+
|
400
|
+
##
|
401
|
+
# @return a Rack response for unlocatable resources.
|
402
|
+
def not_found
|
403
|
+
[404, PLAIN_TYPE, ['Not Found']]
|
404
|
+
end
|
405
|
+
|
406
|
+
##
|
407
|
+
# @return a Rack response for forbidden resources.
|
408
|
+
def no_access
|
409
|
+
[403, PLAIN_TYPE, ['Forbidden']]
|
410
|
+
end
|
411
|
+
|
412
|
+
|
413
|
+
# ------------------------
|
414
|
+
# header writing functions
|
415
|
+
# ------------------------
|
416
|
+
|
417
|
+
##
|
418
|
+
# NOTE: This should probably be converted to a constant.
|
419
|
+
#
|
420
|
+
# @return a hash of headers that should prevent caching of a Rack response.
|
421
|
+
def hdr_nocache
|
422
|
+
{
|
423
|
+
'Expires' => 'Fri, 01 Jan 1980 00:00:00 GMT',
|
424
|
+
'Pragma' => 'no-cache',
|
425
|
+
'Cache-Control' => 'no-cache, max-age=0, must-revalidate'
|
426
|
+
}
|
427
|
+
end
|
428
|
+
|
429
|
+
##
|
430
|
+
# @return a hash of headers that should trigger caches permanent caching.
|
431
|
+
def hdr_cache_forever
|
432
|
+
now = Time.now().to_i
|
433
|
+
{
|
434
|
+
'Date' => now.to_s,
|
435
|
+
'Expires' => (now + 31536000).to_s,
|
436
|
+
'Cache-Control' => 'public, max-age=31536000'
|
437
|
+
}
|
438
|
+
end
|
439
|
+
|
440
|
+
##
|
441
|
+
# Converts old configuration settings to current ones.
|
442
|
+
#
|
443
|
+
# @param [Hash] opts an options hash to convert.
|
444
|
+
# @option opts [String] :project_root a directory path containing 1 or more
|
445
|
+
# Git repositories.
|
446
|
+
# @option opts [Boolean, nil] :receivepack determines whether or not to
|
447
|
+
# allow pushes into the repositories. +nil+ means to defer to the
|
448
|
+
# requested repository.
|
449
|
+
# @option opts [Boolean, nil] :uploadpack determines whether or not to
|
450
|
+
# allow fetches/pulls from the repositories. +nil+ means to defer to the
|
451
|
+
# requested repository.
|
452
|
+
# @option opts [#create] :adapter a class that provides an interface for
|
453
|
+
# interacting with Git repositories.
|
454
|
+
#
|
455
|
+
# @return an options hash with current options set based on old ones.
|
456
|
+
def convert_old_opts(opts)
|
457
|
+
opts = opts.dup
|
458
|
+
|
459
|
+
if opts.key?(:project_root) && ! opts.key?(:root)
|
460
|
+
opts[:root] = opts.fetch(:project_root)
|
461
|
+
end
|
462
|
+
if opts.key?(:upload_pack) && ! opts.key?(:allow_pull)
|
463
|
+
opts[:allow_pull] = opts.fetch(:upload_pack)
|
464
|
+
end
|
465
|
+
if opts.key?(:receive_pack) && ! opts.key?(:allow_push)
|
466
|
+
opts[:allow_push] = opts.fetch(:receive_pack)
|
467
|
+
end
|
468
|
+
if opts.key?(:adapter) && ! opts.key?(:git_adapter_factory)
|
469
|
+
adapter = opts.fetch(:adapter)
|
470
|
+
opts[:git_adapter_factory] =
|
471
|
+
if GitAdapter == adapter
|
472
|
+
->{ GitAdapter.new(opts.fetch(:git_path, 'git')) }
|
473
|
+
else
|
474
|
+
require 'grack/compatible_git_adapter'
|
475
|
+
->{ CompatibleGitAdapter.new(adapter.new) }
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
opts
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|