git-fastclone 1.4.4 → 1.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7330529bf940f74fcdf782fa298d7de00d0f75b5ccbd303bb6a99d57668b6a0
4
- data.tar.gz: 4dc5b12076314094bf03638433dcbc6df5f486b6b2b5da6ff2350c77942b23ca
3
+ metadata.gz: 8b86bd9aa9bc5a377dd7d5b7b456eb0de1aee7ffd1e746642775d08042e9714f
4
+ data.tar.gz: '08dff02e06757c022c7ee0fec4890261c3d3efbee76130f2c7f4e0c2cdd91361'
5
5
  SHA512:
6
- metadata.gz: c3ce186a25e7acbc07735118a7a9d55bbca2deee8ff7ba79ea8eebdb1dd8ecff2a01beb640528af0ed8d35a9a62bf03161b8afa545ca6ceb5b7b3ea62ce510ba
7
- data.tar.gz: f6d0ec9167c8dc69ebdd7caad9c24d595bfd83c3400618d8eefaeb1e0ace4f6dc7a1eb4a752bb499f3c2dc16edf522096e4680dd69f414dcbef6dd9bc9addcd3
6
+ metadata.gz: ce36dfc95ed1d5621fc32df5721d1b796e1cdbb58c11952351dd124bf14a784bef8624e23bde74be3a3c848fff320201639b0e7737be44c8860860a0fb99a019
7
+ data.tar.gz: 77a296e5b3c6ea817fef4c0ca6df39c4f33e8f35626fd896d4f41ff9c201bf8de15c57a0543e7a8aac4cf63f7de352a00b01844c964657fb20192abbce3790a4
data/README.md CHANGED
@@ -43,17 +43,29 @@ Usage
43
43
  gem install git-fastclone
44
44
  git fastclone [options] <git-repo-url>
45
45
 
46
- -b, --branch <branch> Clone a specific branch
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.
46
+ -b, --branch BRANCH Checkout this branch rather than the default
47
+ -v, --verbose Verbose mode
48
+ --print_git_errors Print git output if a command fails
49
+ -c, --color Display colored output
50
+ --config CONFIG Git config applied to the cloned repo
51
+ --lock-timeout N Timeout in seconds to acquire a lock on any reference repo.
52
+ Default is 0 which waits indefinitely.
53
+ --pre-clone-hook command An optional command that should be invoked before cloning mirror repo
51
54
 
52
55
  Change the default `REFERENCE_REPO_DIR` environment variable if necessary.
53
56
 
54
57
  Cygwin users need to add `~/bin` to PATH.
55
58
 
56
59
 
60
+ Hooks
61
+ -----
62
+
63
+ - `pre-clone-hook` is invoked right before cloning a new mirror repo, which gives a change to prepopulate git's mirror from a different source.
64
+ The hook is invoked with given arguments:
65
+ 1. cloning repo url
66
+ 1. path to the repo mirror location
67
+ 1. attempt number, 0-indexed
68
+
57
69
  How to test?
58
70
  ------------
59
71
  Manual testing:
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Version string for git-fastclone
4
4
  module GitFastCloneVersion
5
- VERSION = '1.4.4'
5
+ VERSION = '1.5.0'
6
6
  end
data/lib/git-fastclone.rb CHANGED
@@ -47,13 +47,23 @@ module GitFastClone
47
47
  end
48
48
  module_function :reference_repo_dir
49
49
 
50
+ def reference_filename(filename)
51
+ separator = if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
52
+ '__'
53
+ else
54
+ ':'
55
+ end
56
+ "#{separator}#{filename}"
57
+ end
58
+ module_function :reference_filename
59
+
50
60
  def reference_repo_submodule_file(url, reference_dir, using_local_repo)
51
- "#{reference_repo_dir(url, reference_dir, using_local_repo)}:submodules.txt"
61
+ "#{reference_repo_dir(url, reference_dir, using_local_repo)}#{reference_filename('submodules.txt')}"
52
62
  end
53
63
  module_function :reference_repo_submodule_file
54
64
 
55
65
  def reference_repo_lock_file(url, reference_dir, using_local_repo)
56
- lock_file_name = "#{reference_repo_dir(url, reference_dir, using_local_repo)}:lock"
66
+ lock_file_name = "#{reference_repo_dir(url, reference_dir, using_local_repo)}#{reference_filename('lock')}"
57
67
  File.open(lock_file_name, File::RDWR | File::CREAT, 0o644)
58
68
  end
59
69
  module_function :reference_repo_lock_file
@@ -156,6 +166,11 @@ module GitFastClone
156
166
  Default is 0 which waits indefinitely.') do |timeout_secs|
157
167
  self.flock_timeout_secs = timeout_secs.to_i
158
168
  end
169
+
170
+ opts.on('--pre-clone-hook command',
171
+ 'An optional command that should be invoked before cloning mirror repo') do |command|
172
+ options[:pre_clone_hook] = command
173
+ end
159
174
  end.parse!
160
175
  end
161
176
 
@@ -314,7 +329,7 @@ module GitFastClone
314
329
  # overall checkout or not. When we pre-fetch based off of cached information,
315
330
  # fail_hard is false. When we fetch based off info in a repository directly,
316
331
  # fail_hard is true.
317
- def update_reference_repo(url, fail_hard)
332
+ def update_reference_repo(url, fail_hard, attempt_number)
318
333
  repo_name = reference_repo_name(url)
319
334
  mirror = reference_repo_dir(url, reference_dir, using_local_repo)
320
335
 
@@ -323,24 +338,26 @@ module GitFastClone
323
338
  submodule_file = reference_repo_submodule_file(url, reference_dir, using_local_repo)
324
339
 
325
340
  # if prefetch is on, then grab children immediately to frontload network requests
326
- prefetch(submodule_file) if File.exist?(submodule_file) && prefetch_submodules
341
+ prefetch(submodule_file, attempt_number) if File.exist?(submodule_file) && prefetch_submodules
327
342
 
328
343
  # Store the fact that our repo has been updated if necessary
329
- store_updated_repo(url, mirror, repo_name, fail_hard) unless reference_updated[repo_name]
344
+ store_updated_repo(url, mirror, repo_name, fail_hard, attempt_number) unless reference_updated[repo_name]
330
345
  end
331
346
  end
332
347
 
333
348
  # Grab the children in the event of a prefetch
334
- def prefetch(submodule_file)
349
+ def prefetch(submodule_file, attempt_number)
335
350
  File.readlines(submodule_file).each do |line|
336
351
  # We don't join these threads explicitly
337
- Thread.new { update_reference_repo(line.strip, false) }
352
+ Thread.new { update_reference_repo(line.strip, false, attempt_number) }
338
353
  end
339
354
  end
340
355
 
341
356
  # Creates or updates the mirror repo then stores an indication
342
357
  # that this repo has been updated on this run of fastclone
343
- def store_updated_repo(url, mirror, repo_name, fail_hard)
358
+ def store_updated_repo(url, mirror, repo_name, fail_hard, attempt_number)
359
+ trigger_pre_clone_hook_if_needed(url, mirror, attempt_number)
360
+ # If pre_clone_hook correctly creates a mirror directory, we don't want to clone, but just update it
344
361
  unless Dir.exist?(mirror)
345
362
  fail_on_error('git', 'clone', verbose ? '--verbose' : '--quiet', '--mirror', url.to_s, mirror.to_s,
346
363
  quiet: !verbose, print_on_failure: print_git_errors)
@@ -404,7 +421,7 @@ module GitFastClone
404
421
  retries_allowed ||= 1
405
422
  attempt_number ||= 0
406
423
 
407
- update_reference_repo(url, true)
424
+ update_reference_repo(url, true, attempt_number)
408
425
  dir = reference_repo_dir(url, reference_dir, using_local_repo)
409
426
 
410
427
  # Sometimes remote updates involve re-packing objects on a different thread
@@ -431,5 +448,11 @@ module GitFastClone
431
448
  def usage
432
449
  'Usage: git fastclone [options] <git-url> [path]'
433
450
  end
451
+
452
+ private def trigger_pre_clone_hook_if_needed(url, mirror, attempt_number)
453
+ return if Dir.exist?(mirror) || !options.include?(:pre_clone_hook)
454
+
455
+ popen2e_wrapper(options[:pre_clone_hook], url.to_s, mirror.to_s, attempt_number.to_s, quiet: !verbose)
456
+ end
434
457
  end
435
458
  end
@@ -145,6 +145,54 @@ describe GitFastClone::Runner do
145
145
  subject.clone(placeholder_arg, nil, '.', 'config')
146
146
  end
147
147
  end
148
+
149
+ context 'with pre-clone-hook errors' do
150
+ let(:pre_clone_hook) { '/some/command' }
151
+ before(:each) do
152
+ subject.options[:pre_clone_hook] = pre_clone_hook
153
+ subject.reference_dir = placeholder_arg
154
+ allow(subject).to receive(:with_git_mirror).and_call_original
155
+ allow(subject).to receive(:with_reference_repo_lock) do |_url, &block|
156
+ block.call
157
+ end
158
+ end
159
+
160
+ it 'invokes hook command' do
161
+ allow(subject).to receive(:fail_on_error)
162
+ expect(subject).to receive(:popen2e_wrapper).with(
163
+ pre_clone_hook, 'PH', 'PH/PH', '0',
164
+ { quiet: true }
165
+ ) { runner_execution_double }
166
+
167
+ subject.clone(placeholder_arg, nil, '.', 'config')
168
+ end
169
+
170
+ it 'does not call clone if hook creates mirror' do
171
+ allow(subject).to receive(:popen2e_wrapper).with(
172
+ pre_clone_hook, 'PH', 'PH/PH', '0',
173
+ { quiet: true }
174
+ ) do
175
+ # Emulate creating mirror dir
176
+ allow(Dir).to receive(:exist?).with('PH/PH').and_return(true)
177
+ end
178
+ allow(subject).to receive(:fail_on_error)
179
+
180
+ subject.clone(placeholder_arg, nil, '.', 'config')
181
+ end
182
+
183
+ it 'does not call pre-clone hook if mirror is already created' do
184
+ # Emulate already created mirror dir
185
+ allow(Dir).to receive(:exist?).and_call_original
186
+ allow(Dir).to receive(:exist?).with('PH/PH').and_return(true)
187
+ expect(subject).not_to receive(:popen2e_wrapper).with(
188
+ pre_clone_hook, 'PH', 'PH/PH', '0',
189
+ { quiet: true }
190
+ )
191
+ allow(subject).to receive(:fail_on_error)
192
+
193
+ subject.clone(placeholder_arg, nil, '.', 'config')
194
+ end
195
+ end
148
196
  end
149
197
 
150
198
  describe '.clear_clone_dest_if_needed' do
@@ -249,7 +297,7 @@ describe GitFastClone::Runner do
249
297
  allow(File).to receive(:exist?) { true }
250
298
  subject.prefetch_submodules = true
251
299
  subject.reference_dir = placeholder_arg
252
- subject.update_reference_repo(test_url_valid, false)
300
+ subject.update_reference_repo(test_url_valid, false, 0)
253
301
  end
254
302
  end
255
303
 
@@ -262,7 +310,7 @@ describe GitFastClone::Runner do
262
310
  allow(File).to receive(:exist?) { true }
263
311
  subject.prefetch_submodules = false
264
312
  subject.reference_dir = placeholder_arg
265
- subject.update_reference_repo(placeholder_arg, false)
313
+ subject.update_reference_repo(placeholder_arg, false, 0)
266
314
  end
267
315
  end
268
316
 
@@ -277,7 +325,7 @@ describe GitFastClone::Runner do
277
325
  allow(subject).to receive(:reference_repo_dir) { placeholder_arg }
278
326
  subject.reference_updated = placeholder_hash
279
327
  subject.prefetch_submodules = false
280
- subject.update_reference_repo(placeholder_arg, false)
328
+ subject.update_reference_repo(placeholder_arg, false, 0)
281
329
  end
282
330
  end
283
331
 
@@ -291,7 +339,7 @@ describe GitFastClone::Runner do
291
339
  subject.reference_updated = placeholder_hash
292
340
  subject.reference_dir = placeholder_arg
293
341
  subject.prefetch_submodules = false
294
- subject.update_reference_repo(placeholder_arg, false)
342
+ subject.update_reference_repo(placeholder_arg, false, 0)
295
343
  end
296
344
  end
297
345
  end
@@ -302,7 +350,7 @@ describe GitFastClone::Runner do
302
350
 
303
351
  allow(File).to receive(:readlines) { %w[1 2 3] }
304
352
  subject.prefetch_submodules = true
305
- subject.prefetch(placeholder_arg)
353
+ subject.prefetch(placeholder_arg, 0)
306
354
  end
307
355
  end
308
356
 
@@ -315,7 +363,7 @@ describe GitFastClone::Runner do
315
363
  allow(subject).to receive(:fail_on_error) { raise ex }
316
364
  expect(FileUtils).to receive(:remove_entry_secure).with(placeholder_arg, force: true)
317
365
  expect do
318
- subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, true)
366
+ subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, true, 0)
319
367
  end.to raise_error(ex)
320
368
  end
321
369
 
@@ -327,7 +375,7 @@ describe GitFastClone::Runner do
327
375
  allow(subject).to receive(:fail_on_error) { raise ex }
328
376
  expect(FileUtils).to_not receive(:remove_entry_secure).with(placeholder_arg, force: true)
329
377
  expect do
330
- subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, true)
378
+ subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, true, 0)
331
379
  end.to raise_error(ex)
332
380
  end
333
381
  end
@@ -340,7 +388,7 @@ describe GitFastClone::Runner do
340
388
  allow(subject).to receive(:fail_on_error) { raise ex }
341
389
  expect(FileUtils).to receive(:remove_entry_secure).with(placeholder_arg, force: true)
342
390
  expect do
343
- subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, false)
391
+ subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, false, 0)
344
392
  end.to_not raise_error
345
393
  end
346
394
  end
@@ -351,7 +399,7 @@ describe GitFastClone::Runner do
351
399
  allow(subject).to receive(:fail_on_error)
352
400
 
353
401
  subject.reference_updated = placeholder_hash
354
- subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, false)
402
+ subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, false, 0)
355
403
  expect(subject.reference_updated).to eq(placeholder_arg => true)
356
404
  end
357
405
  end
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.4.4
4
+ version: 1.5.0
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: 2023-11-15 00:00:00.000000000 Z
12
+ date: 2024-02-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: colorize