git-fastclone 1.3.0 → 1.3.1
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 +4 -4
- data/README.md +4 -2
- data/bin/git-fastclone +1 -1
- data/lib/git-fastclone/version.rb +1 -1
- data/lib/git-fastclone.rb +66 -30
- data/spec/git_fastclone_runner_spec.rb +152 -188
- data/spec/git_fastclone_url_helper_spec.rb +1 -1
- metadata +7 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d83fead53c699b625667b994e06ab9cfe0c25ed62c01239c054ec1523109f986
|
|
4
|
+
data.tar.gz: 9e4513fe51d1e1deb357a1781fadd1df723997df527402c12beb436103ce7b2a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ecc286e3180698eab52e06e61d3bf62c27af6524a3ab398d86cf1bbbe336dd9c547609ec6744264be506ea9f41920cf68210b08d6fad752f5d8fc589b069e2be
|
|
7
|
+
data.tar.gz: 653a21b17f4a033ee23bd77f1953a72df9176006ebb320a33ed179e4f7f2a957133a4569f1d91722c65d2d638ee727eae15d41b6b73f5b133d138823365e6937
|
data/README.md
CHANGED
|
@@ -44,8 +44,10 @@ Usage
|
|
|
44
44
|
git fastclone [options] <git-repo-url>
|
|
45
45
|
|
|
46
46
|
-b, --branch <branch> Clone a specific branch
|
|
47
|
-
-v, --verbose
|
|
48
|
-
-c, --color
|
|
47
|
+
-v, --verbose Verbose mode
|
|
48
|
+
-c, --color Display colored output
|
|
49
|
+
--config CONFIG Git config applied to the cloned repo
|
|
50
|
+
--lock-timeout N Timeout in seconds to acquire a lock on any reference repo.
|
|
49
51
|
|
|
50
52
|
Change the default `REFERENCE_REPO_DIR` environment variable if necessary.
|
|
51
53
|
|
data/bin/git-fastclone
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
# See the License for the specific language governing permissions and
|
|
16
16
|
# limitations under the License.
|
|
17
17
|
|
|
18
|
-
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)
|
|
18
|
+
$LOAD_PATH.unshift(File.expand_path("#{File.dirname(__FILE__)}/../lib"))
|
|
19
19
|
|
|
20
20
|
require 'git-fastclone'
|
|
21
21
|
|
data/lib/git-fastclone.rb
CHANGED
|
@@ -41,7 +41,7 @@ module GitFastClone
|
|
|
41
41
|
|
|
42
42
|
def reference_repo_dir(url, reference_dir, using_local_repo)
|
|
43
43
|
if using_local_repo
|
|
44
|
-
File.join(reference_dir,
|
|
44
|
+
File.join(reference_dir, "local#{reference_repo_name(url)}")
|
|
45
45
|
else
|
|
46
46
|
File.join(reference_dir, reference_repo_name(url))
|
|
47
47
|
end
|
|
@@ -69,9 +69,9 @@ module GitFastClone
|
|
|
69
69
|
|
|
70
70
|
include GitFastClone::UrlHelper
|
|
71
71
|
|
|
72
|
-
DEFAULT_REFERENCE_REPO_DIR = '/var/tmp/git-fastclone/reference'
|
|
72
|
+
DEFAULT_REFERENCE_REPO_DIR = '/var/tmp/git-fastclone/reference'
|
|
73
73
|
|
|
74
|
-
DEFAULT_GIT_ALLOW_PROTOCOL = 'file:git:http:https:ssh'
|
|
74
|
+
DEFAULT_GIT_ALLOW_PROTOCOL = 'file:git:http:https:ssh'
|
|
75
75
|
|
|
76
76
|
attr_accessor :reference_dir, :prefetch_submodules, :reference_updated, :reference_mutex,
|
|
77
77
|
:options, :logger, :abs_clone_path, :using_local_repo, :verbose, :color,
|
|
@@ -137,7 +137,7 @@ module GitFastClone
|
|
|
137
137
|
|
|
138
138
|
opts.on('-v', '--verbose', 'Verbose mode') do
|
|
139
139
|
self.verbose = true
|
|
140
|
-
self.logger = Logger.new(
|
|
140
|
+
self.logger = Logger.new($stdout)
|
|
141
141
|
logger.formatter = proc do |_severity, _datetime, _progname, msg|
|
|
142
142
|
"#{msg}\n"
|
|
143
143
|
end
|
|
@@ -163,7 +163,7 @@ module GitFastClone
|
|
|
163
163
|
parse_options
|
|
164
164
|
|
|
165
165
|
unless ARGV[0]
|
|
166
|
-
|
|
166
|
+
warn usage
|
|
167
167
|
exit(129)
|
|
168
168
|
end
|
|
169
169
|
|
|
@@ -189,18 +189,40 @@ module GitFastClone
|
|
|
189
189
|
[url, path, options]
|
|
190
190
|
end
|
|
191
191
|
|
|
192
|
+
def clear_clone_dest_if_needed(attempt_number, clone_dest)
|
|
193
|
+
return unless attempt_number.positive?
|
|
194
|
+
|
|
195
|
+
dest_with_dotfiles = Dir.glob("#{clone_dest}/*", File::FNM_DOTMATCH)
|
|
196
|
+
dest_files = dest_with_dotfiles.reject { |f| %w[. ..].include?(File.basename(f)) }
|
|
197
|
+
return if dest_files.empty?
|
|
198
|
+
|
|
199
|
+
clear_clone_dest(dest_files)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def clear_clone_dest(dest_files)
|
|
203
|
+
puts 'Non-empty clone directory found, clearing its content now.'
|
|
204
|
+
FileUtils.rm_rf(dest_files)
|
|
205
|
+
end
|
|
206
|
+
|
|
192
207
|
# Checkout to SOURCE_DIR. Update all submodules recursively. Use reference
|
|
193
208
|
# repos everywhere for speed.
|
|
194
209
|
def clone(url, rev, src_dir, config)
|
|
210
|
+
clone_dest = File.join(abs_clone_path, src_dir).to_s
|
|
195
211
|
initial_time = Time.now
|
|
196
212
|
|
|
197
|
-
|
|
213
|
+
if Dir.exist?(clone_dest) && !Dir.empty?(clone_dest)
|
|
214
|
+
raise "Can't clone into an existing non-empty path: #{clone_dest}"
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
with_git_mirror(url) do |mirror, attempt_number|
|
|
218
|
+
clear_clone_dest_if_needed(attempt_number, clone_dest)
|
|
219
|
+
|
|
198
220
|
clone_command = '--quiet --reference :mirror :url :path'
|
|
199
221
|
clone_command += ' --config :config' unless config.nil?
|
|
200
222
|
Terrapin::CommandLine.new('git clone', clone_command)
|
|
201
223
|
.run(mirror: mirror.to_s,
|
|
202
224
|
url: url.to_s,
|
|
203
|
-
path:
|
|
225
|
+
path: clone_dest,
|
|
204
226
|
config: config.to_s)
|
|
205
227
|
end
|
|
206
228
|
|
|
@@ -245,7 +267,7 @@ module GitFastClone
|
|
|
245
267
|
|
|
246
268
|
def thread_update_submodule(submodule_url, submodule_path, threads, pwd)
|
|
247
269
|
threads << Thread.new do
|
|
248
|
-
with_git_mirror(submodule_url) do |mirror|
|
|
270
|
+
with_git_mirror(submodule_url) do |mirror, _|
|
|
249
271
|
Terrapin::CommandLine.new('cd', ':dir; git submodule update --quiet --reference :mirror :path')
|
|
250
272
|
.run(dir: File.join(abs_clone_path, pwd).to_s,
|
|
251
273
|
mirror: mirror.to_s,
|
|
@@ -270,14 +292,12 @@ module GitFastClone
|
|
|
270
292
|
lockfile.close
|
|
271
293
|
end
|
|
272
294
|
|
|
273
|
-
def with_reference_repo_thread_lock(url)
|
|
295
|
+
def with_reference_repo_thread_lock(url, &block)
|
|
274
296
|
# We also need thread level locking because pre-fetch means multiple threads can
|
|
275
297
|
# attempt to update the same repository from a single git-fastclone process
|
|
276
298
|
# file locks in posix are tracked per process, not per userland thread.
|
|
277
299
|
# This gives us the equivalent of pthread_mutex around these accesses.
|
|
278
|
-
reference_mutex[reference_repo_name(url)].synchronize
|
|
279
|
-
yield
|
|
280
|
-
end
|
|
300
|
+
reference_mutex[reference_repo_name(url)].synchronize(&block)
|
|
281
301
|
end
|
|
282
302
|
|
|
283
303
|
def update_submodule_reference(url, submodule_url_list)
|
|
@@ -338,6 +358,31 @@ module GitFastClone
|
|
|
338
358
|
raise e if fail_hard
|
|
339
359
|
end
|
|
340
360
|
|
|
361
|
+
def retriable_error?(error)
|
|
362
|
+
error_strings = [
|
|
363
|
+
'fatal: missing blob object',
|
|
364
|
+
'fatal: remote did not send all necessary objects',
|
|
365
|
+
/fatal: packed object [a-z0-9]+ \(stored in .*?\) is corrupt/,
|
|
366
|
+
/fatal: pack has \d+ unresolved delta/,
|
|
367
|
+
'error: unable to read sha1 file of ',
|
|
368
|
+
'fatal: did not receive expected object',
|
|
369
|
+
/^fatal: unable to read tree [a-z0-9]+\n^warning: Clone succeeded, but checkout failed/
|
|
370
|
+
]
|
|
371
|
+
error.to_s =~ /^STDERR:\n.*^#{Regexp.union(error_strings)}/m
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def print_formatted_error(error)
|
|
375
|
+
indented_error = error.to_s.split("\n").map { |s| "> #{s}\n" }.join
|
|
376
|
+
puts "Encountered a retriable error:\n#{indented_error}\n\nRemoving the fastclone cache."
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# To avoid corruption of the cache, if we failed to update or check out we remove
|
|
380
|
+
# the cache directory entirely. This may cause the current clone to fail, but if the
|
|
381
|
+
# underlying error from git is transient it will not affect future clones.
|
|
382
|
+
def clear_cache(dir)
|
|
383
|
+
FileUtils.remove_entry_secure(dir, force: true)
|
|
384
|
+
end
|
|
385
|
+
|
|
341
386
|
# This command will create and bring the mirror up-to-date on-demand,
|
|
342
387
|
# blocking any code passed in while the mirror is brought up-to-date
|
|
343
388
|
#
|
|
@@ -354,27 +399,18 @@ module GitFastClone
|
|
|
354
399
|
# This makes sure we have control and unlock when the block returns:
|
|
355
400
|
with_reference_repo_lock(url) do
|
|
356
401
|
dir = reference_repo_dir(url, reference_dir, using_local_repo)
|
|
357
|
-
|
|
402
|
+
retries_allowed = 1
|
|
403
|
+
attempt_number = 0
|
|
358
404
|
|
|
359
405
|
begin
|
|
360
|
-
yield dir
|
|
406
|
+
yield dir, attempt_number
|
|
361
407
|
rescue Terrapin::ExitStatusError => e
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
'fatal: did not receive expected object',
|
|
369
|
-
/^fatal: unable to read tree [a-z0-9]+\n^warning: Clone succeeded, but checkout failed/
|
|
370
|
-
]
|
|
371
|
-
if e.to_s =~ /^STDERR:\n.+^#{Regexp.union(error_strings)}/m
|
|
372
|
-
# To avoid corruption of the cache, if we failed to update or check out we remove
|
|
373
|
-
# the cache directory entirely. This may cause the current clone to fail, but if the
|
|
374
|
-
# underlying error from git is transient it will not affect future clones.
|
|
375
|
-
FileUtils.remove_entry_secure(dir, force: true)
|
|
376
|
-
if retries_left > 0
|
|
377
|
-
retries_left -= 1
|
|
408
|
+
if retriable_error?(e)
|
|
409
|
+
print_formatted_error(e)
|
|
410
|
+
clear_cache(dir)
|
|
411
|
+
|
|
412
|
+
if attempt_number < retries_allowed
|
|
413
|
+
attempt_number += 1
|
|
378
414
|
retry
|
|
379
415
|
end
|
|
380
416
|
end
|
|
@@ -91,7 +91,8 @@ describe GitFastClone::Runner do
|
|
|
91
91
|
expect(Time).to receive(:now).twice { 0 }
|
|
92
92
|
allow(Dir).to receive(:pwd) { '/pwd' }
|
|
93
93
|
allow(Dir).to receive(:chdir).and_yield
|
|
94
|
-
allow(subject).to receive(:with_git_mirror).and_yield('/cache')
|
|
94
|
+
allow(subject).to receive(:with_git_mirror).and_yield('/cache', 0)
|
|
95
|
+
expect(subject).to receive(:clear_clone_dest_if_needed).once {}
|
|
95
96
|
end
|
|
96
97
|
|
|
97
98
|
it 'should clone correctly' do
|
|
@@ -114,21 +115,39 @@ describe GitFastClone::Runner do
|
|
|
114
115
|
subject.clone(placeholder_arg, placeholder_arg, '.', nil)
|
|
115
116
|
end
|
|
116
117
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
it 'should clone correctly with custom configs' do
|
|
119
|
+
expect(Terrapin::CommandLine).to receive(:new).with(
|
|
120
|
+
'git clone',
|
|
121
|
+
'--quiet --reference :mirror :url :path --config :config'
|
|
122
|
+
) { terrapin_commandline_double }
|
|
123
|
+
expect(terrapin_commandline_double).to receive(:run).with(
|
|
124
|
+
mirror: '/cache',
|
|
125
|
+
url: placeholder_arg,
|
|
126
|
+
path: '/pwd/.',
|
|
127
|
+
config: 'config'
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
subject.clone(placeholder_arg, nil, '.', 'config')
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe '.clear_clone_dest_if_needed' do
|
|
135
|
+
it 'does not clear on first attempt' do
|
|
136
|
+
expect(Dir).not_to receive(:glob)
|
|
137
|
+
expect(subject).not_to receive(:clear_clone_dest)
|
|
138
|
+
subject.clear_clone_dest_if_needed(0, '/some/path')
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it 'does not clear if the directory is only FNM_DOTMATCH self and parent refs' do
|
|
142
|
+
expect(Dir).to receive(:glob).and_return(%w[. ..])
|
|
143
|
+
expect(subject).not_to receive(:clear_clone_dest)
|
|
144
|
+
subject.clear_clone_dest_if_needed(1, '/some/path')
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it 'does clear if the directory is not empty' do
|
|
148
|
+
expect(Dir).to receive(:glob).and_return(%w[. .. /some/path/file.txt])
|
|
149
|
+
expect(subject).to receive(:clear_clone_dest) {}
|
|
150
|
+
subject.clear_clone_dest_if_needed(1, '/some/path')
|
|
132
151
|
end
|
|
133
152
|
end
|
|
134
153
|
|
|
@@ -312,209 +331,154 @@ describe GitFastClone::Runner do
|
|
|
312
331
|
end
|
|
313
332
|
|
|
314
333
|
describe '.with_git_mirror' do
|
|
315
|
-
|
|
334
|
+
before(:each) do
|
|
316
335
|
allow(subject).to receive(:update_reference_repo) {}
|
|
317
|
-
|
|
336
|
+
allow(subject).to receive(:print_formatted_error) {}
|
|
337
|
+
expect(subject).to receive(:reference_repo_dir).and_return(test_reference_repo_dir)
|
|
318
338
|
expect(subject).to receive(:reference_repo_lock_file).and_return(lockfile)
|
|
339
|
+
end
|
|
319
340
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
341
|
+
def retriable_error
|
|
342
|
+
%(
|
|
343
|
+
STDOUT:
|
|
323
344
|
|
|
324
|
-
|
|
345
|
+
STDERR:
|
|
346
|
+
|
|
347
|
+
fatal: bad object ee35b1e14e7c3a53dcc14d82606e5b872f6a05a7
|
|
348
|
+
fatal: remote did not send all necessary objects
|
|
349
|
+
).strip.split("\n").map(&:strip).join("\n")
|
|
325
350
|
end
|
|
326
351
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
352
|
+
def try_with_git_mirror(responses, results)
|
|
353
|
+
lambdas = responses.map do |response|
|
|
354
|
+
if response == true
|
|
355
|
+
# Simulate successful response
|
|
356
|
+
->(url) { url }
|
|
357
|
+
else
|
|
358
|
+
# Simulate failed error response
|
|
359
|
+
->(_url) { raise Terrapin::ExitStatusError, response }
|
|
360
|
+
end
|
|
361
|
+
end
|
|
331
362
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
STDERR:
|
|
338
|
-
|
|
339
|
-
fatal: bad object ee35b1e14e7c3a53dcc14d82606e5b872f6a05a7
|
|
340
|
-
fatal: remote did not send all necessary objects
|
|
341
|
-
ERROR
|
|
342
|
-
},
|
|
343
|
-
->(url) { url }
|
|
344
|
-
]
|
|
345
|
-
subject.with_git_mirror(test_url_valid) do
|
|
346
|
-
yielded << responses.shift.call(test_url_valid)
|
|
363
|
+
subject.with_git_mirror(test_url_valid) do |url, attempt|
|
|
364
|
+
raise 'Not enough responses were provided!' if lambdas.empty?
|
|
365
|
+
|
|
366
|
+
yielded << [lambdas.shift.call(url), attempt]
|
|
347
367
|
end
|
|
348
368
|
|
|
349
|
-
expect(
|
|
350
|
-
expect(yielded).to eq(
|
|
369
|
+
expect(lambdas).to be_empty
|
|
370
|
+
expect(yielded).to eq(results)
|
|
351
371
|
end
|
|
352
372
|
|
|
353
|
-
it 'should
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
responses = [
|
|
359
|
-
lambda { |_url|
|
|
360
|
-
raise Terrapin::ExitStatusError, <<-ERROR.gsub(/^ {12}/, '')
|
|
361
|
-
STDOUT:
|
|
362
|
-
|
|
363
|
-
STDERR:
|
|
364
|
-
|
|
365
|
-
fatal: packed object 7c4d79704f8adf701f38a7bfb3e33ec5342542f1 (stored in /private/var/tmp/git-fastclone/reference/some-repo.git/objects/pack/pack-d37d7ed3e88d6e5f0ac141a7b0a2b32baf6e21a0.pack) is corrupt
|
|
366
|
-
warning: Clone succeeded, but checkout failed.
|
|
367
|
-
You can inspect what was checked out with 'git status' and retry with 'git restore --source=HEAD :/'
|
|
368
|
-
ERROR
|
|
369
|
-
},
|
|
370
|
-
->(url) { url }
|
|
371
|
-
]
|
|
372
|
-
subject.with_git_mirror(test_url_valid) do
|
|
373
|
-
yielded << responses.shift.call(test_url_valid)
|
|
374
|
-
end
|
|
373
|
+
it 'should yield properly' do
|
|
374
|
+
expect(subject).not_to receive(:clear_cache)
|
|
375
|
+
try_with_git_mirror([true], [[test_reference_repo_dir, 0]])
|
|
376
|
+
end
|
|
375
377
|
|
|
376
|
-
|
|
377
|
-
expect(
|
|
378
|
+
it 'should retry once for retriable errors' do
|
|
379
|
+
expect(subject).to receive(:clear_cache).once {}
|
|
380
|
+
try_with_git_mirror([retriable_error, true], [[test_reference_repo_dir, 1]])
|
|
378
381
|
end
|
|
379
382
|
|
|
380
|
-
it 'should retry
|
|
381
|
-
|
|
382
|
-
expect
|
|
383
|
-
|
|
383
|
+
it 'should only retry twice at most' do
|
|
384
|
+
expect(subject).to receive(:clear_cache).twice {}
|
|
385
|
+
expect do
|
|
386
|
+
try_with_git_mirror([retriable_error, retriable_error], [])
|
|
387
|
+
end.to raise_error(Terrapin::ExitStatusError)
|
|
388
|
+
end
|
|
384
389
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
error: Could not read 92cf57b8f07df010ab5f607b109c325e30e46235
|
|
393
|
-
fatal: unable to read tree 0c32c0521d3b0bfb4e74e4a39b97a84d1a3bb9a1
|
|
394
|
-
warning: Clone succeeded, but checkout failed.
|
|
395
|
-
You can inspect what was checked out with 'git status'
|
|
396
|
-
and retry with 'git restore --source=HEAD :/'
|
|
397
|
-
ERROR
|
|
398
|
-
},
|
|
399
|
-
->(url) { url }
|
|
400
|
-
]
|
|
401
|
-
subject.with_git_mirror(test_url_valid) do
|
|
402
|
-
yielded << responses.shift.call(test_url_valid)
|
|
403
|
-
end
|
|
390
|
+
it 'should not retry for non-retriable errors' do
|
|
391
|
+
expect(subject).not_to receive(:clear_cache)
|
|
392
|
+
expect do
|
|
393
|
+
try_with_git_mirror(['Some unexpected error message'], [])
|
|
394
|
+
end.to raise_error(Terrapin::ExitStatusError)
|
|
395
|
+
end
|
|
396
|
+
end
|
|
404
397
|
|
|
405
|
-
|
|
406
|
-
|
|
398
|
+
describe '.retriable_error?' do
|
|
399
|
+
def format_error(error)
|
|
400
|
+
error_wrapper = "STDOUT:\n\nSTDERR:\n#{error}"
|
|
401
|
+
error_wrapper.strip.lines.map(&:strip).join("\n")
|
|
407
402
|
end
|
|
408
403
|
|
|
409
|
-
it '
|
|
410
|
-
|
|
411
|
-
expect(subject).to receive(:reference_repo_dir)
|
|
412
|
-
expect(subject).to receive(:reference_repo_lock_file).and_return(lockfile)
|
|
404
|
+
it 'not for a random error message' do
|
|
405
|
+
error = format_error 'random error message'
|
|
413
406
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
raise Terrapin::ExitStatusError, <<-ERROR.gsub(/^ {12}/, '')
|
|
417
|
-
STDOUT:
|
|
418
|
-
|
|
419
|
-
STDERR:
|
|
420
|
-
|
|
421
|
-
error: Could not read f7fad86d06fee0678f9af7203b6031feabb40c3e
|
|
422
|
-
fatal: pack has 1 unresolved delta
|
|
423
|
-
fatal: index-pack failed
|
|
424
|
-
ERROR
|
|
425
|
-
},
|
|
426
|
-
->(url) { url }
|
|
427
|
-
]
|
|
428
|
-
subject.with_git_mirror(test_url_valid) do
|
|
429
|
-
yielded << responses.shift.call(test_url_valid)
|
|
430
|
-
end
|
|
407
|
+
expect(subject.retriable_error?(error)).to be_falsey
|
|
408
|
+
end
|
|
431
409
|
|
|
432
|
-
|
|
433
|
-
|
|
410
|
+
it 'when the cache looks corrupted' do
|
|
411
|
+
error = format_error <<-ERROR
|
|
412
|
+
fatal: bad object ee35b1e14e7c3a53dcc14d82606e5b872f6a05a7
|
|
413
|
+
fatal: remote did not send all necessary objects
|
|
414
|
+
ERROR
|
|
415
|
+
|
|
416
|
+
expect(subject.retriable_error?(error)).to be_truthy
|
|
434
417
|
end
|
|
435
418
|
|
|
436
|
-
it '
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
419
|
+
it 'when the clone succeeds but checkout fails with corrupt packed object' do
|
|
420
|
+
error = format_error <<-ERROR
|
|
421
|
+
fatal: packed object 7c4d79704f8adf701f38a7bfb3e33ec5342542f1 (stored in /private/var/tmp/git-fastclone/reference/some-repo.git/objects/pack/pack-d37d7ed3e88d6e5f0ac141a7b0a2b32baf6e21a0.pack) is corrupt
|
|
422
|
+
warning: Clone succeeded, but checkout failed.
|
|
423
|
+
You can inspect what was checked out with 'git status' and retry with 'git restore --source=HEAD :/'
|
|
424
|
+
ERROR
|
|
440
425
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
raise Terrapin::ExitStatusError, <<-ERROR.gsub(/^ {12}/, '')
|
|
444
|
-
STDOUT:
|
|
445
|
-
|
|
446
|
-
STDERR:
|
|
447
|
-
|
|
448
|
-
error: Could not read f7fad86d06fee0678f9af7203b6031feabb40c3e
|
|
449
|
-
fatal: pack has 138063 unresolved deltas
|
|
450
|
-
fatal: index-pack failed
|
|
451
|
-
ERROR
|
|
452
|
-
},
|
|
453
|
-
->(url) { url }
|
|
454
|
-
]
|
|
455
|
-
subject.with_git_mirror(test_url_valid) do
|
|
456
|
-
yielded << responses.shift.call(test_url_valid)
|
|
457
|
-
end
|
|
426
|
+
expect(subject.retriable_error?(error)).to be_truthy
|
|
427
|
+
end
|
|
458
428
|
|
|
459
|
-
|
|
460
|
-
|
|
429
|
+
it 'when the clone succeeds but checkout fails with unable to read tree' do
|
|
430
|
+
error = format_error <<-ERROR
|
|
431
|
+
error: Could not read 92cf57b8f07df010ab5f607b109c325e30e46235
|
|
432
|
+
fatal: unable to read tree 0c32c0521d3b0bfb4e74e4a39b97a84d1a3bb9a1
|
|
433
|
+
warning: Clone succeeded, but checkout failed.
|
|
434
|
+
You can inspect what was checked out with 'git status'
|
|
435
|
+
and retry with 'git restore --source=HEAD :/'
|
|
436
|
+
ERROR
|
|
437
|
+
|
|
438
|
+
expect(subject.retriable_error?(error)).to be_truthy
|
|
461
439
|
end
|
|
462
|
-
end
|
|
463
440
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
STDERR:
|
|
475
|
-
|
|
476
|
-
error: unable to read sha1 file of sqiosbuild/lib/action/action.rb (6113b739af82d8b07731de8a58d6e233301f80ab)
|
|
477
|
-
fatal: unable to checkout working tree
|
|
478
|
-
warning: Clone succeeded, but checkout failed.
|
|
479
|
-
You can inspect what was checked out with 'git status'
|
|
480
|
-
and retry with 'git restore --source=HEAD :/'
|
|
481
|
-
ERROR
|
|
482
|
-
},
|
|
483
|
-
->(url) { url }
|
|
484
|
-
]
|
|
485
|
-
subject.with_git_mirror(test_url_valid) do
|
|
486
|
-
yielded << responses.shift.call(test_url_valid)
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
expect(responses).to be_empty
|
|
490
|
-
expect(yielded).to eq([test_url_valid])
|
|
491
|
-
end
|
|
441
|
+
it 'when one delta is missing' do
|
|
442
|
+
error = format_error <<-ERROR
|
|
443
|
+
error: Could not read f7fad86d06fee0678f9af7203b6031feabb40c3e
|
|
444
|
+
fatal: pack has 1 unresolved delta
|
|
445
|
+
fatal: index-pack failed
|
|
446
|
+
ERROR
|
|
447
|
+
|
|
448
|
+
expect(subject.retriable_error?(error)).to be_truthy
|
|
449
|
+
end
|
|
492
450
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
451
|
+
it 'when deltas are missing' do
|
|
452
|
+
error = format_error <<-ERROR
|
|
453
|
+
error: Could not read f7fad86d06fee0678f9af7203b6031feabb40c3e
|
|
454
|
+
fatal: pack has 138063 unresolved deltas
|
|
455
|
+
fatal: index-pack failed
|
|
456
|
+
ERROR
|
|
497
457
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
raise Terrapin::ExitStatusError, <<-ERROR.gsub(/^ {12}/, '')
|
|
501
|
-
STDOUT:
|
|
458
|
+
expect(subject.retriable_error?(error)).to be_truthy
|
|
459
|
+
end
|
|
502
460
|
|
|
503
|
-
|
|
461
|
+
it 'when the cache errors with unable to read sha1 file' do
|
|
462
|
+
error = format_error <<-ERROR
|
|
463
|
+
error: unable to read sha1 file of sqiosbuild/lib/action/action.rb (6113b739af82d8b07731de8a58d6e233301f80ab)
|
|
464
|
+
fatal: unable to checkout working tree
|
|
465
|
+
warning: Clone succeeded, but checkout failed.
|
|
466
|
+
You can inspect what was checked out with 'git status'
|
|
467
|
+
and retry with 'git restore --source=HEAD :/'
|
|
468
|
+
ERROR
|
|
504
469
|
|
|
505
|
-
|
|
506
|
-
error: Could not read 0cd3703c23fa44c0043d97fbc26356a23939f31b
|
|
507
|
-
fatal: did not receive expected object 3c64c9dd49c79bd09aa13d4b05ac18263ca29ccd
|
|
508
|
-
fatal: index-pack failed
|
|
509
|
-
ERROR
|
|
510
|
-
},
|
|
511
|
-
->(url) { url }
|
|
512
|
-
]
|
|
513
|
-
subject.with_git_mirror(test_url_valid) do
|
|
514
|
-
yielded << responses.shift.call(test_url_valid)
|
|
470
|
+
expect(subject.retriable_error?(error)).to be_truthy
|
|
515
471
|
end
|
|
516
472
|
|
|
517
|
-
|
|
518
|
-
|
|
473
|
+
it 'when the cache errors with did not receive expected object' do
|
|
474
|
+
error = format_error <<-ERROR
|
|
475
|
+
error: Could not read 6682dfe81f66656436e60883dd795e7ec6735153
|
|
476
|
+
error: Could not read 0cd3703c23fa44c0043d97fbc26356a23939f31b
|
|
477
|
+
fatal: did not receive expected object 3c64c9dd49c79bd09aa13d4b05ac18263ca29ccd
|
|
478
|
+
fatal: index-pack failed
|
|
479
|
+
ERROR
|
|
480
|
+
|
|
481
|
+
expect(subject.retriable_error?(error)).to be_truthy
|
|
482
|
+
end
|
|
519
483
|
end
|
|
520
484
|
end
|
|
@@ -62,7 +62,7 @@ describe GitFastClone::UrlHelper do
|
|
|
62
62
|
allow(subject).to receive(:reference_repo_name) { test_reference_dir }
|
|
63
63
|
|
|
64
64
|
expect(subject.reference_repo_dir(test_url_valid, test_reference_dir, false))
|
|
65
|
-
.to eq(test_reference_dir
|
|
65
|
+
.to eq("#{test_reference_dir}/#{test_reference_dir}")
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: git-fastclone
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.3.
|
|
4
|
+
version: 1.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Tauraso
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2022-12-
|
|
12
|
+
date: 2022-12-08 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: colorize
|
|
@@ -61,7 +61,8 @@ files:
|
|
|
61
61
|
homepage: http://square.github.io/git-fastclone/
|
|
62
62
|
licenses:
|
|
63
63
|
- Apache
|
|
64
|
-
metadata:
|
|
64
|
+
metadata:
|
|
65
|
+
rubygems_mfa_required: 'true'
|
|
65
66
|
post_install_message:
|
|
66
67
|
rdoc_options: []
|
|
67
68
|
require_paths:
|
|
@@ -70,18 +71,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
70
71
|
requirements:
|
|
71
72
|
- - ">="
|
|
72
73
|
- !ruby/object:Gem::Version
|
|
73
|
-
version: '
|
|
74
|
+
version: '2.7'
|
|
74
75
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
76
|
requirements:
|
|
76
77
|
- - ">="
|
|
77
78
|
- !ruby/object:Gem::Version
|
|
78
79
|
version: '0'
|
|
79
80
|
requirements: []
|
|
80
|
-
rubygems_version: 3.
|
|
81
|
+
rubygems_version: 3.3.7
|
|
81
82
|
signing_key:
|
|
82
83
|
specification_version: 4
|
|
83
84
|
summary: git-clone --recursive on steroids!
|
|
84
|
-
test_files:
|
|
85
|
-
- spec/git_fastclone_runner_spec.rb
|
|
86
|
-
- spec/git_fastclone_url_helper_spec.rb
|
|
87
|
-
- spec/spec_helper.rb
|
|
85
|
+
test_files: []
|