git-fastclone 1.2.7 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22f5537cbc1297198ea1aa106a305ef5ad9526dc24fc9a39048c6889e6d441b4
4
- data.tar.gz: 0f1f38ba2756185c3c02b7a5ec3cf40c01e4498e743388f41991ca1d817793de
3
+ metadata.gz: d83fead53c699b625667b994e06ab9cfe0c25ed62c01239c054ec1523109f986
4
+ data.tar.gz: 9e4513fe51d1e1deb357a1781fadd1df723997df527402c12beb436103ce7b2a
5
5
  SHA512:
6
- metadata.gz: 22634dabfc0c4d91682dc7db8d9e18e6cdc4a6d6db079a66c5e498ccc6ed70c8bcb7ccd24657b91e5142d0fe8be0f34169223d1d70cb1262ed3c6d88e3ec0e83
7
- data.tar.gz: 8dd73fac0eb7eec9b8e8ead616a48549860722982b756b950ad020cd295da4dffeaf4b89b7dad3c88f2dc4b82119a40172a499441924bbcf2885e280313850eb
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 Shows more info
48
- -c, --color Pretty colors!
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__) + '/../lib'))
18
+ $LOAD_PATH.unshift(File.expand_path("#{File.dirname(__FILE__)}/../lib"))
19
19
 
20
20
  require 'git-fastclone'
21
21
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Version string for git-fastclone
4
4
  module GitFastCloneVersion
5
- VERSION = '1.2.7'.freeze
5
+ VERSION = '1.3.1'
6
6
  end
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, 'local' + reference_repo_name(url))
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'.freeze
72
+ DEFAULT_REFERENCE_REPO_DIR = '/var/tmp/git-fastclone/reference'
73
73
 
74
- DEFAULT_GIT_ALLOW_PROTOCOL = 'file:git:http:https:ssh'.freeze
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,
@@ -121,7 +121,7 @@ module GitFastClone
121
121
  puts "Cloning #{path_from_git_url(url)} to #{File.join(abs_clone_path, path)}"
122
122
  Terrapin::CommandLine.environment['GIT_ALLOW_PROTOCOL'] =
123
123
  ENV['GIT_ALLOW_PROTOCOL'] || DEFAULT_GIT_ALLOW_PROTOCOL
124
- clone(url, options[:branch], path)
124
+ clone(url, options[:branch], path, options[:config])
125
125
  end
126
126
 
127
127
  def parse_options
@@ -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(STDOUT)
140
+ self.logger = Logger.new($stdout)
141
141
  logger.formatter = proc do |_severity, _datetime, _progname, msg|
142
142
  "#{msg}\n"
143
143
  end
@@ -148,6 +148,10 @@ module GitFastClone
148
148
  self.color = true
149
149
  end
150
150
 
151
+ opts.on('--config CONFIG', 'Git config applied to the cloned repo') do |config|
152
+ options[:config] = config
153
+ end
154
+
151
155
  opts.on('--lock-timeout N', 'Timeout in seconds to acquire a lock on any reference repo.
152
156
  Default is 0 which waits indefinitely.') do |timeout_secs|
153
157
  self.flock_timeout_secs = timeout_secs
@@ -159,7 +163,7 @@ module GitFastClone
159
163
  parse_options
160
164
 
161
165
  unless ARGV[0]
162
- STDERR.puts usage
166
+ warn usage
163
167
  exit(129)
164
168
  end
165
169
 
@@ -185,16 +189,41 @@ module GitFastClone
185
189
  [url, path, options]
186
190
  end
187
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
+
188
207
  # Checkout to SOURCE_DIR. Update all submodules recursively. Use reference
189
208
  # repos everywhere for speed.
190
- def clone(url, rev, src_dir)
209
+ def clone(url, rev, src_dir, config)
210
+ clone_dest = File.join(abs_clone_path, src_dir).to_s
191
211
  initial_time = Time.now
192
212
 
193
- with_git_mirror(url) do |mirror|
194
- Terrapin::CommandLine.new('git clone', '--quiet --reference :mirror :url :path')
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
+
220
+ clone_command = '--quiet --reference :mirror :url :path'
221
+ clone_command += ' --config :config' unless config.nil?
222
+ Terrapin::CommandLine.new('git clone', clone_command)
195
223
  .run(mirror: mirror.to_s,
196
224
  url: url.to_s,
197
- path: File.join(abs_clone_path, src_dir).to_s)
225
+ path: clone_dest,
226
+ config: config.to_s)
198
227
  end
199
228
 
200
229
  # Only checkout if we're changing branches to a non-default branch
@@ -238,7 +267,7 @@ module GitFastClone
238
267
 
239
268
  def thread_update_submodule(submodule_url, submodule_path, threads, pwd)
240
269
  threads << Thread.new do
241
- with_git_mirror(submodule_url) do |mirror|
270
+ with_git_mirror(submodule_url) do |mirror, _|
242
271
  Terrapin::CommandLine.new('cd', ':dir; git submodule update --quiet --reference :mirror :path')
243
272
  .run(dir: File.join(abs_clone_path, pwd).to_s,
244
273
  mirror: mirror.to_s,
@@ -263,14 +292,12 @@ module GitFastClone
263
292
  lockfile.close
264
293
  end
265
294
 
266
- def with_reference_repo_thread_lock(url)
295
+ def with_reference_repo_thread_lock(url, &block)
267
296
  # We also need thread level locking because pre-fetch means multiple threads can
268
297
  # attempt to update the same repository from a single git-fastclone process
269
298
  # file locks in posix are tracked per process, not per userland thread.
270
299
  # This gives us the equivalent of pthread_mutex around these accesses.
271
- reference_mutex[reference_repo_name(url)].synchronize do
272
- yield
273
- end
300
+ reference_mutex[reference_repo_name(url)].synchronize(&block)
274
301
  end
275
302
 
276
303
  def update_submodule_reference(url, submodule_url_list)
@@ -331,6 +358,31 @@ module GitFastClone
331
358
  raise e if fail_hard
332
359
  end
333
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
+
334
386
  # This command will create and bring the mirror up-to-date on-demand,
335
387
  # blocking any code passed in while the mirror is brought up-to-date
336
388
  #
@@ -347,27 +399,18 @@ module GitFastClone
347
399
  # This makes sure we have control and unlock when the block returns:
348
400
  with_reference_repo_lock(url) do
349
401
  dir = reference_repo_dir(url, reference_dir, using_local_repo)
350
- retries_left = 1
402
+ retries_allowed = 1
403
+ attempt_number = 0
351
404
 
352
405
  begin
353
- yield dir
406
+ yield dir, attempt_number
354
407
  rescue Terrapin::ExitStatusError => e
355
- error_strings = [
356
- 'fatal: missing blob object',
357
- 'fatal: remote did not send all necessary objects',
358
- /fatal: packed object [a-z0-9]+ \(stored in .*?\) is corrupt/,
359
- /fatal: pack has \d+ unresolved delta/,
360
- 'error: unable to read sha1 file of ',
361
- 'fatal: did not receive expected object',
362
- /^fatal: unable to read tree [a-z0-9]+\n^warning: Clone succeeded, but checkout failed/
363
- ]
364
- if e.to_s =~ /^STDERR:\n.+^#{Regexp.union(error_strings)}/m
365
- # To avoid corruption of the cache, if we failed to update or check out we remove
366
- # the cache directory entirely. This may cause the current clone to fail, but if the
367
- # underlying error from git is transient it will not affect future clones.
368
- FileUtils.remove_entry_secure(dir, force: true)
369
- if retries_left > 0
370
- 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
371
414
  retry
372
415
  end
373
416
  end
@@ -56,11 +56,22 @@ describe GitFastClone::Runner do
56
56
  let(:options) { { branch: placeholder_arg } }
57
57
 
58
58
  it 'should run with the correct args' do
59
- allow(subject).to receive(:parse_inputs) { [placeholder_arg, placeholder_arg, options] }
60
- expect(subject).to receive(:clone).with(placeholder_arg, placeholder_arg, placeholder_arg)
59
+ allow(subject).to receive(:parse_inputs) { [placeholder_arg, placeholder_arg, options, nil] }
60
+ expect(subject).to receive(:clone).with(placeholder_arg, placeholder_arg, placeholder_arg, nil)
61
61
 
62
62
  subject.run
63
63
  end
64
+
65
+ describe 'with custom configs' do
66
+ let(:options) { { branch: placeholder_arg, config: 'conf' } }
67
+
68
+ it 'should clone correctly' do
69
+ allow(subject).to receive(:parse_inputs) { [placeholder_arg, placeholder_arg, options, 'conf'] }
70
+ expect(subject).to receive(:clone).with(placeholder_arg, placeholder_arg, placeholder_arg, 'conf')
71
+
72
+ subject.run
73
+ end
74
+ end
64
75
  end
65
76
 
66
77
  describe '.parse_inputs' do
@@ -74,17 +85,69 @@ describe GitFastClone::Runner do
74
85
  end
75
86
 
76
87
  describe '.clone' do
77
- it 'should clone correctly' do
78
- terrapin_commandline_double = double('new_terrapin_commandline')
79
- allow(subject).to receive(:with_git_mirror) {}
88
+ let(:terrapin_commandline_double) { double('new_terrapin_commandline') }
89
+ before(:each) do
80
90
  allow(terrapin_commandline_double).to receive(:run) {}
81
- allow(Terrapin::CommandLine).to receive(:new) { terrapin_commandline_double }
82
-
83
91
  expect(Time).to receive(:now).twice { 0 }
84
- expect(Terrapin::CommandLine).to receive(:new)
85
- expect(terrapin_commandline_double).to receive(:run)
92
+ allow(Dir).to receive(:pwd) { '/pwd' }
93
+ allow(Dir).to receive(:chdir).and_yield
94
+ allow(subject).to receive(:with_git_mirror).and_yield('/cache', 0)
95
+ expect(subject).to receive(:clear_clone_dest_if_needed).once {}
96
+ end
97
+
98
+ it 'should clone correctly' do
99
+ expect(Terrapin::CommandLine).to receive(:new).with(
100
+ 'git clone',
101
+ '--quiet --reference :mirror :url :path'
102
+ ) { terrapin_commandline_double }
103
+ expect(Terrapin::CommandLine).to receive(:new).with(
104
+ 'git checkout',
105
+ '--quiet :rev'
106
+ ) { terrapin_commandline_double }
107
+ expect(terrapin_commandline_double).to receive(:run).with(
108
+ mirror: '/cache',
109
+ url: placeholder_arg,
110
+ path: '/pwd/.',
111
+ config: ''
112
+ )
113
+ expect(terrapin_commandline_double).to receive(:run).with(rev: placeholder_arg)
114
+
115
+ subject.clone(placeholder_arg, placeholder_arg, '.', nil)
116
+ end
117
+
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
86
146
 
87
- subject.clone(placeholder_arg, placeholder_arg, '.')
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')
88
151
  end
89
152
  end
90
153
 
@@ -268,209 +331,154 @@ describe GitFastClone::Runner do
268
331
  end
269
332
 
270
333
  describe '.with_git_mirror' do
271
- it 'should yield properly' do
334
+ before(:each) do
272
335
  allow(subject).to receive(:update_reference_repo) {}
273
- expect(subject).to receive(:reference_repo_dir)
336
+ allow(subject).to receive(:print_formatted_error) {}
337
+ expect(subject).to receive(:reference_repo_dir).and_return(test_reference_repo_dir)
274
338
  expect(subject).to receive(:reference_repo_lock_file).and_return(lockfile)
339
+ end
275
340
 
276
- subject.with_git_mirror(test_url_valid) do
277
- yielded << test_url_valid
278
- end
341
+ def retriable_error
342
+ %(
343
+ STDOUT:
279
344
 
280
- expect(yielded).to eq([test_url_valid])
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")
281
350
  end
282
351
 
283
- it 'should retry when the cache looks corrupted' do
284
- allow(subject).to receive(:update_reference_repo) {}
285
- expect(subject).to receive(:reference_repo_dir)
286
- expect(subject).to receive(:reference_repo_lock_file).and_return(lockfile)
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
287
362
 
288
- responses = [
289
- lambda { |_url|
290
- raise Terrapin::ExitStatusError, <<-ERROR.gsub(/^ {12}/, '')
291
- STDOUT:
292
-
293
- STDERR:
294
-
295
- fatal: bad object ee35b1e14e7c3a53dcc14d82606e5b872f6a05a7
296
- fatal: remote did not send all necessary objects
297
- ERROR
298
- },
299
- ->(url) { url }
300
- ]
301
- subject.with_git_mirror(test_url_valid) do
302
- 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]
303
367
  end
304
368
 
305
- expect(responses).to be_empty
306
- expect(yielded).to eq([test_url_valid])
369
+ expect(lambdas).to be_empty
370
+ expect(yielded).to eq(results)
307
371
  end
308
372
 
309
- it 'should retry when the clone succeeds but checkout fails with corrupt packed object' do
310
- allow(subject).to receive(:update_reference_repo) {}
311
- expect(subject).to receive(:reference_repo_dir)
312
- expect(subject).to receive(:reference_repo_lock_file).and_return(lockfile)
313
-
314
- responses = [
315
- lambda { |_url|
316
- raise Terrapin::ExitStatusError, <<-ERROR.gsub(/^ {12}/, '')
317
- STDOUT:
318
-
319
- STDERR:
320
-
321
- fatal: packed object 7c4d79704f8adf701f38a7bfb3e33ec5342542f1 (stored in /private/var/tmp/git-fastclone/reference/some-repo.git/objects/pack/pack-d37d7ed3e88d6e5f0ac141a7b0a2b32baf6e21a0.pack) is corrupt
322
- warning: Clone succeeded, but checkout failed.
323
- You can inspect what was checked out with 'git status' and retry with 'git restore --source=HEAD :/'
324
- ERROR
325
- },
326
- ->(url) { url }
327
- ]
328
- subject.with_git_mirror(test_url_valid) do
329
- yielded << responses.shift.call(test_url_valid)
330
- 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
331
377
 
332
- expect(responses).to be_empty
333
- expect(yielded).to eq([test_url_valid])
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]])
334
381
  end
335
382
 
336
- it 'should retry when the clone succeeds but checkout fails with unable to read tree' do
337
- allow(subject).to receive(:update_reference_repo) {}
338
- expect(subject).to receive(:reference_repo_dir)
339
- expect(subject).to receive(:reference_repo_lock_file).and_return(lockfile)
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
340
389
 
341
- responses = [
342
- lambda { |_url|
343
- raise Terrapin::ExitStatusError, <<-ERROR.gsub(/^ {12}/, '')
344
- STDOUT:
345
-
346
- STDERR:
347
-
348
- error: Could not read 92cf57b8f07df010ab5f607b109c325e30e46235
349
- fatal: unable to read tree 0c32c0521d3b0bfb4e74e4a39b97a84d1a3bb9a1
350
- warning: Clone succeeded, but checkout failed.
351
- You can inspect what was checked out with 'git status'
352
- and retry with 'git restore --source=HEAD :/'
353
- ERROR
354
- },
355
- ->(url) { url }
356
- ]
357
- subject.with_git_mirror(test_url_valid) do
358
- yielded << responses.shift.call(test_url_valid)
359
- 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
360
397
 
361
- expect(responses).to be_empty
362
- expect(yielded).to eq([test_url_valid])
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")
363
402
  end
364
403
 
365
- it 'should retry when one delta is missing' do
366
- allow(subject).to receive(:update_reference_repo) {}
367
- expect(subject).to receive(:reference_repo_dir)
368
- 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'
369
406
 
370
- responses = [
371
- lambda { |_url|
372
- raise Terrapin::ExitStatusError, <<-ERROR.gsub(/^ {12}/, '')
373
- STDOUT:
374
-
375
- STDERR:
376
-
377
- error: Could not read f7fad86d06fee0678f9af7203b6031feabb40c3e
378
- fatal: pack has 1 unresolved delta
379
- fatal: index-pack failed
380
- ERROR
381
- },
382
- ->(url) { url }
383
- ]
384
- subject.with_git_mirror(test_url_valid) do
385
- yielded << responses.shift.call(test_url_valid)
386
- end
407
+ expect(subject.retriable_error?(error)).to be_falsey
408
+ end
387
409
 
388
- expect(responses).to be_empty
389
- expect(yielded).to eq([test_url_valid])
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
390
417
  end
391
418
 
392
- it 'should retry when deltas are missing' do
393
- allow(subject).to receive(:update_reference_repo) {}
394
- expect(subject).to receive(:reference_repo_dir)
395
- expect(subject).to receive(:reference_repo_lock_file).and_return(lockfile)
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
396
425
 
397
- responses = [
398
- lambda { |_url|
399
- raise Terrapin::ExitStatusError, <<-ERROR.gsub(/^ {12}/, '')
400
- STDOUT:
401
-
402
- STDERR:
403
-
404
- error: Could not read f7fad86d06fee0678f9af7203b6031feabb40c3e
405
- fatal: pack has 138063 unresolved deltas
406
- fatal: index-pack failed
407
- ERROR
408
- },
409
- ->(url) { url }
410
- ]
411
- subject.with_git_mirror(test_url_valid) do
412
- yielded << responses.shift.call(test_url_valid)
413
- end
426
+ expect(subject.retriable_error?(error)).to be_truthy
427
+ end
414
428
 
415
- expect(responses).to be_empty
416
- expect(yielded).to eq([test_url_valid])
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
417
439
  end
418
- end
419
440
 
420
- it 'should retry when the cache errors with unable to read sha1 file' do
421
- allow(subject).to receive(:update_reference_repo) {}
422
- expect(subject).to receive(:reference_repo_dir)
423
- expect(subject).to receive(:reference_repo_lock_file).and_return(lockfile)
424
-
425
- responses = [
426
- lambda { |_url|
427
- raise Terrapin::ExitStatusError, <<-ERROR.gsub(/^ {12}/, '')
428
- STDOUT:
429
-
430
- STDERR:
431
-
432
- error: unable to read sha1 file of sqiosbuild/lib/action/action.rb (6113b739af82d8b07731de8a58d6e233301f80ab)
433
- fatal: unable to checkout working tree
434
- warning: Clone succeeded, but checkout failed.
435
- You can inspect what was checked out with 'git status'
436
- and retry with 'git restore --source=HEAD :/'
437
- ERROR
438
- },
439
- ->(url) { url }
440
- ]
441
- subject.with_git_mirror(test_url_valid) do
442
- yielded << responses.shift.call(test_url_valid)
443
- end
444
-
445
- expect(responses).to be_empty
446
- expect(yielded).to eq([test_url_valid])
447
- 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
448
450
 
449
- it 'should retry when the cache errors with did not receive expected object' do
450
- allow(subject).to receive(:update_reference_repo) {}
451
- expect(subject).to receive(:reference_repo_dir)
452
- expect(subject).to receive(:reference_repo_lock_file).and_return(lockfile)
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
453
457
 
454
- responses = [
455
- lambda { |_url|
456
- raise Terrapin::ExitStatusError, <<-ERROR.gsub(/^ {12}/, '')
457
- STDOUT:
458
+ expect(subject.retriable_error?(error)).to be_truthy
459
+ end
458
460
 
459
- STDERR:
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
460
469
 
461
- error: Could not read 6682dfe81f66656436e60883dd795e7ec6735153
462
- error: Could not read 0cd3703c23fa44c0043d97fbc26356a23939f31b
463
- fatal: did not receive expected object 3c64c9dd49c79bd09aa13d4b05ac18263ca29ccd
464
- fatal: index-pack failed
465
- ERROR
466
- },
467
- ->(url) { url }
468
- ]
469
- subject.with_git_mirror(test_url_valid) do
470
- yielded << responses.shift.call(test_url_valid)
470
+ expect(subject.retriable_error?(error)).to be_truthy
471
471
  end
472
472
 
473
- expect(responses).to be_empty
474
- expect(yielded).to eq([test_url_valid])
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
475
483
  end
476
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 + '/' + 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.2.7
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: 2021-02-26 00:00:00.000000000 Z
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: '0'
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.0.1
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: []