git-fastclone 1.5.0 → 1.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b86bd9aa9bc5a377dd7d5b7b456eb0de1aee7ffd1e746642775d08042e9714f
4
- data.tar.gz: '08dff02e06757c022c7ee0fec4890261c3d3efbee76130f2c7f4e0c2cdd91361'
3
+ metadata.gz: 691025585b07db11da08c4cba7a6a6f8adbc6fa869c4d05cb4fb4abe9f29231c
4
+ data.tar.gz: 68d8a58de28932d66eb99f37630bb3bb7a9ee5e23738ed6c9c50550cc72f8a74
5
5
  SHA512:
6
- metadata.gz: ce36dfc95ed1d5621fc32df5721d1b796e1cdbb58c11952351dd124bf14a784bef8624e23bde74be3a3c848fff320201639b0e7737be44c8860860a0fb99a019
7
- data.tar.gz: 77a296e5b3c6ea817fef4c0ca6df39c4f33e8f35626fd896d4f41ff9c201bf8de15c57a0543e7a8aac4cf63f7de352a00b01844c964657fb20192abbce3790a4
6
+ metadata.gz: 7594ba7271f38731ec3522e7af1f067d606ae3dc91860ffb9d0cff6a34dee62d1dee62a8c5a77d206f9fa9ef782ea44893a9542c1ef5ef5163176269a979c8cf
7
+ data.tar.gz: 4b0b325e9ca5c756a9efce9e28f6edc7d8a9084616e60de8e33feca4a890a9319946914eece980b192aa4dcc54da362fb93954071820b4008410c6a0abfee62c
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Version string for git-fastclone
4
4
  module GitFastCloneVersion
5
- VERSION = '1.5.0'
5
+ VERSION = '1.6.0.pre1'
6
6
  end
data/lib/git-fastclone.rb CHANGED
@@ -85,7 +85,7 @@ module GitFastClone
85
85
 
86
86
  attr_accessor :reference_dir, :prefetch_submodules, :reference_updated, :reference_mutex,
87
87
  :options, :abs_clone_path, :using_local_repo, :verbose, :print_git_errors, :color,
88
- :flock_timeout_secs
88
+ :flock_timeout_secs, :sparse_paths
89
89
 
90
90
  def initialize
91
91
  # Prefetch reference repos for submodules we've seen before
@@ -115,6 +115,8 @@ module GitFastClone
115
115
  self.color = false
116
116
 
117
117
  self.flock_timeout_secs = 0
118
+
119
+ self.sparse_paths = nil
118
120
  end
119
121
 
120
122
  def run
@@ -162,14 +164,21 @@ module GitFastClone
162
164
  options[:config] = config
163
165
  end
164
166
 
165
- opts.on('--lock-timeout N', 'Timeout in seconds to acquire a lock on any reference repo.
166
- Default is 0 which waits indefinitely.') do |timeout_secs|
167
+ opts.on('--lock-timeout N', 'Timeout in seconds to acquire a lock on any reference repo.',
168
+ 'Default is 0 which waits indefinitely.') do |timeout_secs|
167
169
  self.flock_timeout_secs = timeout_secs.to_i
168
170
  end
169
171
 
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
172
+ opts.on('--pre-clone-hook script_file',
173
+ 'An optional file that should be invoked before cloning mirror repo',
174
+ 'No-op when a file is missing') do |script_file|
175
+ options[:pre_clone_hook] = script_file
176
+ end
177
+
178
+ opts.on('--sparse-paths PATHS',
179
+ 'Comma-separated list of paths for sparse checkout.',
180
+ 'Enables sparse checkout mode using git sparse-checkout.') do |paths|
181
+ self.sparse_paths = paths.split(',').map(&:strip)
173
182
  end
174
183
  end.parse!
175
184
  end
@@ -198,6 +207,16 @@ module GitFastClone
198
207
  raise msg
199
208
  end
200
209
 
210
+ # Validate that --branch is specified when using --sparse-paths
211
+ if sparse_paths && !options[:branch]
212
+ msg = "Error: --branch is required when using --sparse-paths\n" \
213
+ "Sparse checkouts need an explicit branch/revision to checkout.\n" \
214
+ 'Usage: git-fastclone --sparse-paths <paths> --branch <branch> <url>'
215
+ raise msg.red if color
216
+
217
+ raise msg
218
+ end
219
+
201
220
  self.reference_dir = ENV['REFERENCE_REPO_DIR'] || DEFAULT_REFERENCE_REPO_DIR
202
221
  FileUtils.mkdir_p(reference_dir)
203
222
 
@@ -233,13 +252,23 @@ module GitFastClone
233
252
  clear_clone_dest_if_needed(attempt_number, clone_dest)
234
253
 
235
254
  clone_commands = ['git', 'clone', verbose ? '--verbose' : '--quiet']
236
- clone_commands << '--reference' << mirror.to_s << url.to_s << clone_dest
255
+ clone_commands.push('--no-checkout', '--shared') if sparse_paths
256
+ # For sparse checkouts with --shared, clone directly from the local mirror
257
+ # For normal clones, use --reference and clone from the remote URL
258
+ if sparse_paths
259
+ clone_commands << mirror.to_s << clone_dest
260
+ else
261
+ clone_commands << '--reference' << mirror.to_s << url.to_s << clone_dest
262
+ end
237
263
  clone_commands << '--config' << config.to_s unless config.nil?
238
264
  fail_on_error(*clone_commands, quiet: !verbose, print_on_failure: print_git_errors)
265
+
266
+ # Configure sparse checkout if enabled
267
+ configure_sparse_checkout(clone_dest, rev) if sparse_paths
239
268
  end
240
269
 
241
- # Only checkout if we're changing branches to a non-default branch
242
- if rev
270
+ # Only checkout if we're changing branches to a non-default branch (for non-sparse clones)
271
+ if !sparse_paths && rev
243
272
  fail_on_error('git', 'checkout', '--quiet', rev.to_s, quiet: !verbose,
244
273
  print_on_failure: print_git_errors,
245
274
  chdir: File.join(abs_clone_path, src_dir))
@@ -257,6 +286,22 @@ module GitFastClone
257
286
  end
258
287
  end
259
288
 
289
+ def configure_sparse_checkout(clone_dest, rev)
290
+ puts 'Configuring sparse checkout...' if verbose
291
+
292
+ # Initialize sparse checkout with cone mode
293
+ fail_on_error('git', 'sparse-checkout', 'init', '--cone',
294
+ quiet: !verbose, print_on_failure: print_git_errors, chdir: clone_dest)
295
+
296
+ # Set the sparse paths
297
+ fail_on_error('git', 'sparse-checkout', 'set', *sparse_paths,
298
+ quiet: !verbose, print_on_failure: print_git_errors, chdir: clone_dest)
299
+
300
+ # Checkout the specified branch/revision
301
+ fail_on_error('git', 'checkout', '--quiet', rev.to_s,
302
+ quiet: !verbose, print_on_failure: print_git_errors, chdir: clone_dest)
303
+ end
304
+
260
305
  def update_submodules(pwd, url)
261
306
  return unless File.exist?(File.join(abs_clone_path, pwd, '.gitmodules'))
262
307
 
@@ -292,13 +337,13 @@ module GitFastClone
292
337
  end
293
338
  end
294
339
 
295
- def with_reference_repo_lock(url, &block)
340
+ def with_reference_repo_lock(url, &)
296
341
  # Sane POSIX implementations remove exclusive flocks when a process is terminated or killed
297
342
  # We block here indefinitely. Waiting for other git-fastclone processes to release the lock.
298
343
  # With the default timeout of 0 we will wait forever, this can be overridden on the command line.
299
344
  lockfile = reference_repo_lock_file(url, reference_dir, using_local_repo)
300
345
  Timeout.timeout(flock_timeout_secs) { lockfile.flock(File::LOCK_EX) }
301
- with_reference_repo_thread_lock(url, &block)
346
+ with_reference_repo_thread_lock(url, &)
302
347
  ensure
303
348
  # Not strictly necessary to do this unlock as an ensure. If ever exception is caught outside this
304
349
  # primitive, ensure protection may come in handy.
@@ -306,12 +351,12 @@ module GitFastClone
306
351
  lockfile.close
307
352
  end
308
353
 
309
- def with_reference_repo_thread_lock(url, &block)
354
+ def with_reference_repo_thread_lock(url, &)
310
355
  # We also need thread level locking because pre-fetch means multiple threads can
311
356
  # attempt to update the same repository from a single git-fastclone process
312
357
  # file locks in posix are tracked per process, not per userland thread.
313
358
  # This gives us the equivalent of pthread_mutex around these accesses.
314
- reference_mutex[reference_repo_name(url)].synchronize(&block)
359
+ reference_mutex[reference_repo_name(url)].synchronize(&)
315
360
  end
316
361
 
317
362
  def update_submodule_reference(url, submodule_url_list)
@@ -452,7 +497,13 @@ module GitFastClone
452
497
  private def trigger_pre_clone_hook_if_needed(url, mirror, attempt_number)
453
498
  return if Dir.exist?(mirror) || !options.include?(:pre_clone_hook)
454
499
 
455
- popen2e_wrapper(options[:pre_clone_hook], url.to_s, mirror.to_s, attempt_number.to_s, quiet: !verbose)
500
+ hook_command = options[:pre_clone_hook]
501
+ unless File.exist?(File.expand_path(hook_command))
502
+ puts 'pre_clone_hook script is missing' if verbose
503
+ return
504
+ end
505
+
506
+ popen2e_wrapper(hook_command, url.to_s, mirror.to_s, attempt_number.to_s, quiet: !verbose)
456
507
  end
457
508
  end
458
509
  end
@@ -45,7 +45,6 @@ describe GitFastClone::Runner do
45
45
  it 'should initialize properly' do
46
46
  stub_const('GitFastClone::DEFAULT_REFERENCE_REPO_DIR', 'new_dir')
47
47
 
48
- expect(Hash).to respond_to(:new).with(2).arguments
49
48
  expect(GitFastClone::DEFAULT_REFERENCE_REPO_DIR).to eq('new_dir')
50
49
  expect(subject.prefetch_submodules).to eq(true)
51
50
  expect(subject.reference_mutex).to eq({})
@@ -146,11 +145,13 @@ describe GitFastClone::Runner do
146
145
  end
147
146
  end
148
147
 
149
- context 'with pre-clone-hook errors' do
148
+ context 'with pre-clone-hook' do
150
149
  let(:pre_clone_hook) { '/some/command' }
151
150
  before(:each) do
152
151
  subject.options[:pre_clone_hook] = pre_clone_hook
153
152
  subject.reference_dir = placeholder_arg
153
+ allow(File).to receive(:exist?).and_call_original
154
+ allow(File).to receive(:exist?).with(pre_clone_hook).and_return(true)
154
155
  allow(subject).to receive(:with_git_mirror).and_call_original
155
156
  allow(subject).to receive(:with_reference_repo_lock) do |_url, &block|
156
157
  block.call
@@ -192,6 +193,22 @@ describe GitFastClone::Runner do
192
193
 
193
194
  subject.clone(placeholder_arg, nil, '.', 'config')
194
195
  end
196
+
197
+ context 'non-existing script' do
198
+ before(:each) do
199
+ allow(File).to receive(:exist?).with(pre_clone_hook).and_return(false)
200
+ end
201
+
202
+ it 'does not invoke hook command' do
203
+ allow(subject).to receive(:fail_on_error)
204
+ expect(subject).not_to receive(:popen2e_wrapper).with(
205
+ pre_clone_hook, 'PH', 'PH/PH', '0',
206
+ { quiet: true }
207
+ )
208
+
209
+ subject.clone(placeholder_arg, nil, '.', 'config')
210
+ end
211
+ end
195
212
  end
196
213
  end
197
214
 
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.5.0
4
+ version: 1.6.0.pre1
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: 2024-02-23 00:00:00.000000000 Z
12
+ date: 2025-11-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: colorize
@@ -59,14 +59,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
59
59
  requirements:
60
60
  - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: '2.7'
62
+ version: '3.2'
63
63
  required_rubygems_version: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0'
68
68
  requirements: []
69
- rubygems_version: 3.4.10
69
+ rubygems_version: 3.5.22
70
70
  signing_key:
71
71
  specification_version: 4
72
72
  summary: git-clone --recursive on steroids!