git-fastclone 1.4.0 → 1.4.2
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/lib/git-fastclone/version.rb +1 -1
- data/lib/git-fastclone.rb +20 -19
- data/lib/runner_execution.rb +8 -33
- data/spec/git_fastclone_runner_spec.rb +34 -25
- data/spec/runner_execution_spec.rb +58 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da2eb17be407c42dbabdb002d8cee1fb56820f6543df47758b0376e84ed2344e
|
4
|
+
data.tar.gz: 0c1ca35bca06f608f8087670eba49cb5cc7d6c1af7c308e38159477455bd33c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a3d27522c916ac8883ad8abceb5d19529bb406409b3f7904652a54640b2edc91184420baad3118d8379b7c26ce2331018367c994375843c9130ae9511f1108f
|
7
|
+
data.tar.gz: 413c42026762c4bf1a80d693d2920c0a519969a7d5c4f215fb810b88f6dabb5e449a15d331214c0751e0daa92c4cbc706915e7ca4d9691ec2aaefb292b8cbef6
|
data/lib/git-fastclone.rb
CHANGED
@@ -74,7 +74,7 @@ module GitFastClone
|
|
74
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
|
-
:options, :abs_clone_path, :using_local_repo, :verbose, :color,
|
77
|
+
:options, :abs_clone_path, :using_local_repo, :verbose, :print_git_errors, :color,
|
78
78
|
:flock_timeout_secs
|
79
79
|
|
80
80
|
def initialize
|
@@ -100,6 +100,8 @@ module GitFastClone
|
|
100
100
|
|
101
101
|
self.verbose = false
|
102
102
|
|
103
|
+
self.print_git_errors = false
|
104
|
+
|
103
105
|
self.color = false
|
104
106
|
|
105
107
|
self.flock_timeout_secs = 0
|
@@ -133,9 +135,15 @@ module GitFastClone
|
|
133
135
|
end
|
134
136
|
|
135
137
|
opts.on('-v', '--verbose', 'Verbose mode') do
|
138
|
+
puts '--print_git_errors is redundant when using --verbose' if print_git_errors
|
136
139
|
self.verbose = true
|
137
140
|
end
|
138
141
|
|
142
|
+
opts.on('--print_git_errors', 'Print git output if a command fails') do
|
143
|
+
puts '--print_git_errors is redundant when using --verbose' if verbose
|
144
|
+
self.print_git_errors = true
|
145
|
+
end
|
146
|
+
|
139
147
|
opts.on('-c', '--color', 'Display colored output') do
|
140
148
|
self.color = true
|
141
149
|
end
|
@@ -212,13 +220,14 @@ module GitFastClone
|
|
212
220
|
clone_commands = ['git', 'clone', verbose ? '--verbose' : '--quiet']
|
213
221
|
clone_commands << '--reference' << mirror.to_s << url.to_s << clone_dest
|
214
222
|
clone_commands << '--config' << config.to_s unless config.nil?
|
215
|
-
|
223
|
+
fail_on_error(*clone_commands, quiet: !verbose, print_on_failure: print_git_errors)
|
216
224
|
end
|
217
225
|
|
218
226
|
# Only checkout if we're changing branches to a non-default branch
|
219
227
|
if rev
|
220
228
|
Dir.chdir(File.join(abs_clone_path, src_dir)) do
|
221
|
-
|
229
|
+
fail_on_error('git', 'checkout', '--quiet', rev.to_s, quiet: !verbose,
|
230
|
+
print_on_failure: print_git_errors)
|
222
231
|
end
|
223
232
|
end
|
224
233
|
|
@@ -243,7 +252,8 @@ module GitFastClone
|
|
243
252
|
submodule_url_list = []
|
244
253
|
output = ''
|
245
254
|
Dir.chdir(File.join(abs_clone_path, pwd).to_s) do
|
246
|
-
output = fail_on_error('git', 'submodule', 'init', quiet: !verbose
|
255
|
+
output = fail_on_error('git', 'submodule', 'init', quiet: !verbose,
|
256
|
+
print_on_failure: print_git_errors)
|
247
257
|
end
|
248
258
|
|
249
259
|
output.split("\n").each do |line|
|
@@ -261,10 +271,9 @@ module GitFastClone
|
|
261
271
|
threads << Thread.new do
|
262
272
|
with_git_mirror(submodule_url) do |mirror, _|
|
263
273
|
Dir.chdir(File.join(abs_clone_path, pwd).to_s) do
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
)
|
274
|
+
cmd = ['git', 'submodule', verbose ? nil : '--quiet', 'update', '--reference', mirror.to_s,
|
275
|
+
submodule_path.to_s].compact
|
276
|
+
fail_on_error(*cmd, quiet: !verbose, print_on_failure: print_git_errors)
|
268
277
|
end
|
269
278
|
end
|
270
279
|
|
@@ -337,21 +346,13 @@ module GitFastClone
|
|
337
346
|
# that this repo has been updated on this run of fastclone
|
338
347
|
def store_updated_repo(url, mirror, repo_name, fail_hard)
|
339
348
|
unless Dir.exist?(mirror)
|
340
|
-
|
341
|
-
|
342
|
-
mirror.to_s], quiet: !verbose
|
343
|
-
)
|
349
|
+
fail_on_error('git', 'clone', verbose ? '--verbose' : '--quiet', '--mirror', url.to_s, mirror.to_s,
|
350
|
+
quiet: !verbose, print_on_failure: print_git_errors)
|
344
351
|
end
|
345
352
|
|
346
353
|
Dir.chdir(mirror) do
|
347
354
|
cmd = ['git', 'remote', verbose ? '--verbose' : nil, 'update', '--prune'].compact
|
348
|
-
|
349
|
-
fail_pipe_on_error(cmd, quiet: !verbose)
|
350
|
-
else
|
351
|
-
# Because above operation might spit out a lot to stderr, we use this to swallow them
|
352
|
-
# and only display if the operation return non 0 exit code
|
353
|
-
fail_on_error(*cmd, quiet: !verbose)
|
354
|
-
end
|
355
|
+
fail_on_error(*cmd, quiet: !verbose, print_on_failure: print_git_errors)
|
355
356
|
end
|
356
357
|
reference_updated[repo_name] = true
|
357
358
|
rescue RunnerExecutionRuntimeError => e
|
data/lib/runner_execution.rb
CHANGED
@@ -20,37 +20,9 @@ module RunnerExecution
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
# Wrapper around open3.pipeline_r which fails on error.
|
24
|
-
# and stops users from invoking the shell by accident.
|
25
|
-
def fail_pipe_on_error(*cmd_list, quiet: false, **opts)
|
26
|
-
print_command('Running Pipeline:', cmd_list) unless quiet
|
27
|
-
|
28
|
-
env = opts.delete(:env) { {} }
|
29
|
-
raise ArgumentError, "The :env option must be a hash, not #{env.inspect}" unless env.is_a?(Hash)
|
30
|
-
|
31
|
-
cmd_list.map! { |cmd| shell_safe(cmd).unshift(env) }
|
32
|
-
|
33
|
-
output, *status_list = Open3.pipeline_r(*cmd_list, opts) do |out, wait_threads|
|
34
|
-
out_reader = Thread.new do
|
35
|
-
if quiet
|
36
|
-
output = out.read
|
37
|
-
else
|
38
|
-
# Output from pipeline should go to stdout and also get returned for
|
39
|
-
# processing if necessary.
|
40
|
-
output = tee(out, STDOUT)
|
41
|
-
end
|
42
|
-
out.close
|
43
|
-
output
|
44
|
-
end
|
45
|
-
[out_reader.value] + wait_threads.map(&:value)
|
46
|
-
end
|
47
|
-
exit_on_status(output, cmd_list, status_list, quiet: quiet)
|
48
|
-
end
|
49
|
-
module_function :fail_pipe_on_error
|
50
|
-
|
51
23
|
# Runs a command that fails on error.
|
52
24
|
# Uses popen2e wrapper. Handles bad statuses with potential for retries.
|
53
|
-
def fail_on_error(*cmd, stdin_data: nil, binmode: false, quiet: false, **opts)
|
25
|
+
def fail_on_error(*cmd, stdin_data: nil, binmode: false, quiet: false, print_on_failure: false, **opts)
|
54
26
|
print_command('Running Shell Safe Command:', [cmd]) unless quiet
|
55
27
|
shell_safe_cmd = shell_safe(cmd)
|
56
28
|
retry_times = opts[:retry] || 0
|
@@ -67,7 +39,9 @@ module RunnerExecution
|
|
67
39
|
end
|
68
40
|
|
69
41
|
# Get out with the status, good or bad.
|
70
|
-
|
42
|
+
# When quiet, we don't need to print the output, as it is already streamed from popen2e_wrapper
|
43
|
+
needs_print_on_failure = quiet && print_on_failure
|
44
|
+
exit_on_status(output, [shell_safe_cmd], [status], quiet: quiet, print_on_failure: needs_print_on_failure)
|
71
45
|
end
|
72
46
|
module_function :fail_on_error
|
73
47
|
|
@@ -183,20 +157,21 @@ module RunnerExecution
|
|
183
157
|
# return code of the first one.
|
184
158
|
#
|
185
159
|
# Otherwise returns first argument (output)
|
186
|
-
def exit_on_status(output, cmd_list, status_list, quiet: false)
|
160
|
+
def exit_on_status(output, cmd_list, status_list, quiet: false, print_on_failure: false)
|
187
161
|
status_list.each_index do |index|
|
188
162
|
status = status_list[index]
|
189
163
|
cmd = cmd_list[index]
|
190
|
-
check_status(cmd, status, output: output, quiet: quiet)
|
164
|
+
check_status(cmd, status, output: output, quiet: quiet, print_on_failure: print_on_failure)
|
191
165
|
end
|
192
166
|
|
193
167
|
output
|
194
168
|
end
|
195
169
|
module_function :exit_on_status
|
196
170
|
|
197
|
-
def check_status(cmd, status, output: nil, quiet: false)
|
171
|
+
def check_status(cmd, status, output: nil, quiet: false, print_on_failure: false)
|
198
172
|
return if status.exited? && status.exitstatus == 0
|
199
173
|
|
174
|
+
logger.info(output) if print_on_failure
|
200
175
|
# If we exited nonzero or abnormally, print debugging info and explode.
|
201
176
|
if status.exited?
|
202
177
|
logger.debug("Process Exited normally. Exit status:#{status.exitstatus}") unless quiet
|
@@ -89,7 +89,7 @@ describe GitFastClone::Runner do
|
|
89
89
|
describe '.clone' do
|
90
90
|
let(:runner_execution_double) { double('runner_execution') }
|
91
91
|
before(:each) do
|
92
|
-
allow(runner_execution_double).to receive(:
|
92
|
+
allow(runner_execution_double).to receive(:fail_on_error) {}
|
93
93
|
allow(Dir).to receive(:pwd) { '/pwd' }
|
94
94
|
allow(Dir).to receive(:chdir).and_yield
|
95
95
|
allow(subject).to receive(:with_git_mirror).and_yield('/cache', 0)
|
@@ -97,13 +97,13 @@ describe GitFastClone::Runner do
|
|
97
97
|
end
|
98
98
|
|
99
99
|
it 'should clone correctly' do
|
100
|
-
expect(subject).to receive(:
|
101
|
-
|
102
|
-
{ quiet: true }
|
100
|
+
expect(subject).to receive(:fail_on_error).with(
|
101
|
+
'git', 'checkout', '--quiet', 'PH',
|
102
|
+
{ quiet: true, print_on_failure: false }
|
103
103
|
) { runner_execution_double }
|
104
|
-
expect(subject).to receive(:
|
105
|
-
|
106
|
-
{ quiet: true }
|
104
|
+
expect(subject).to receive(:fail_on_error).with(
|
105
|
+
'git', 'clone', '--quiet', '--reference', '/cache', 'PH', '/pwd/.',
|
106
|
+
{ quiet: true, print_on_failure: false }
|
107
107
|
) { runner_execution_double }
|
108
108
|
|
109
109
|
subject.clone(placeholder_arg, placeholder_arg, '.', nil)
|
@@ -111,26 +111,41 @@ describe GitFastClone::Runner do
|
|
111
111
|
|
112
112
|
it 'should clone correctly with verbose mode on' do
|
113
113
|
subject.verbose = true
|
114
|
-
expect(subject).to receive(:
|
115
|
-
|
116
|
-
{ quiet: false }
|
114
|
+
expect(subject).to receive(:fail_on_error).with(
|
115
|
+
'git', 'checkout', '--quiet', 'PH',
|
116
|
+
{ quiet: false, print_on_failure: false }
|
117
117
|
) { runner_execution_double }
|
118
|
-
expect(subject).to receive(:
|
119
|
-
|
120
|
-
{ quiet: false }
|
118
|
+
expect(subject).to receive(:fail_on_error).with(
|
119
|
+
'git', 'clone', '--verbose', '--reference', '/cache', 'PH', '/pwd/.',
|
120
|
+
{ quiet: false, print_on_failure: false }
|
121
121
|
) { runner_execution_double }
|
122
122
|
|
123
123
|
subject.clone(placeholder_arg, placeholder_arg, '.', nil)
|
124
124
|
end
|
125
125
|
|
126
126
|
it 'should clone correctly with custom configs' do
|
127
|
-
expect(subject).to receive(:
|
128
|
-
|
129
|
-
{ quiet: true }
|
127
|
+
expect(subject).to receive(:fail_on_error).with(
|
128
|
+
'git', 'clone', '--quiet', '--reference', '/cache', 'PH', '/pwd/.', '--config', 'config',
|
129
|
+
{ quiet: true, print_on_failure: false }
|
130
130
|
) { runner_execution_double }
|
131
131
|
|
132
132
|
subject.clone(placeholder_arg, nil, '.', 'config')
|
133
133
|
end
|
134
|
+
|
135
|
+
context 'with printing errors' do
|
136
|
+
before(:each) do
|
137
|
+
subject.print_git_errors = true
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'prints failures' do
|
141
|
+
expect(subject).to receive(:fail_on_error).with(
|
142
|
+
'git', 'clone', '--quiet', '--reference', '/cache', 'PH', '/pwd/.', '--config', 'config',
|
143
|
+
{ quiet: true, print_on_failure: true }
|
144
|
+
) { runner_execution_double }
|
145
|
+
|
146
|
+
subject.clone(placeholder_arg, nil, '.', 'config')
|
147
|
+
end
|
148
|
+
end
|
134
149
|
end
|
135
150
|
|
136
151
|
describe '.clear_clone_dest_if_needed' do
|
@@ -298,7 +313,7 @@ describe GitFastClone::Runner do
|
|
298
313
|
status = double('status')
|
299
314
|
allow(status).to receive(:exitstatus).and_return(1)
|
300
315
|
ex = RunnerExecution::RunnerExecutionRuntimeError.new(status, 'cmd')
|
301
|
-
allow(subject).to receive(:
|
316
|
+
allow(subject).to receive(:fail_on_error) { raise ex }
|
302
317
|
expect(FileUtils).to receive(:remove_entry_secure).with(placeholder_arg, force: true)
|
303
318
|
expect do
|
304
319
|
subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, true)
|
@@ -311,7 +326,7 @@ describe GitFastClone::Runner do
|
|
311
326
|
status = double('status')
|
312
327
|
allow(status).to receive(:exitstatus).and_return(1)
|
313
328
|
ex = RunnerExecution::RunnerExecutionRuntimeError.new(status, 'cmd')
|
314
|
-
allow(subject).to receive(:
|
329
|
+
allow(subject).to receive(:fail_on_error) { raise ex }
|
315
330
|
expect(FileUtils).to receive(:remove_entry_secure).with(placeholder_arg, force: true)
|
316
331
|
expect do
|
317
332
|
subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, false)
|
@@ -322,7 +337,7 @@ describe GitFastClone::Runner do
|
|
322
337
|
let(:placeholder_hash) { {} }
|
323
338
|
|
324
339
|
it 'should correctly update the hash' do
|
325
|
-
allow(subject).to receive(:
|
340
|
+
allow(subject).to receive(:fail_on_error)
|
326
341
|
allow(Dir).to receive(:chdir) {}
|
327
342
|
|
328
343
|
subject.reference_updated = placeholder_hash
|
@@ -367,12 +382,6 @@ describe GitFastClone::Runner do
|
|
367
382
|
let(:expected_commands) { [] }
|
368
383
|
|
369
384
|
before(:each) do
|
370
|
-
allow(subject).to receive(:fail_pipe_on_error) { |*params|
|
371
|
-
command = params[0]
|
372
|
-
expect(expected_commands.length).to be > 0
|
373
|
-
expected_command = expected_commands.shift
|
374
|
-
expect(command).to eq(expected_command)
|
375
|
-
}
|
376
385
|
allow(subject).to receive(:fail_on_error) { |*params|
|
377
386
|
# last one is an argument `quiet:`
|
378
387
|
command = params.first(params.size - 1)
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2023 Square Inc.
|
4
|
+
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'spec_helper'
|
18
|
+
require 'git-fastclone'
|
19
|
+
|
20
|
+
# Integration tests use real demo_tool.sh to inspect the E2E behavior
|
21
|
+
describe RunnerExecution do
|
22
|
+
subject { described_class }
|
23
|
+
let(:external_tool) { "#{__dir__}/../script/spec_demo_tool.sh" }
|
24
|
+
let(:logger) { double('logger') }
|
25
|
+
|
26
|
+
before do
|
27
|
+
allow($stdout).to receive(:puts)
|
28
|
+
allow(logger).to receive(:info)
|
29
|
+
allow(logger).to receive(:debug)
|
30
|
+
allow(logger).to receive(:warn)
|
31
|
+
allow(RunnerExecution).to receive(:logger).and_return(logger)
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.fail_on_error' do
|
35
|
+
it 'should log failure info on command error' do
|
36
|
+
expect(logger).to receive(:info).with("My error output\n")
|
37
|
+
|
38
|
+
expect do
|
39
|
+
described_class.fail_on_error(external_tool, '1', 'My error output', quiet: true,
|
40
|
+
print_on_failure: true)
|
41
|
+
end.to raise_error(RunnerExecution::RunnerExecutionRuntimeError)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should not log failure output on command success' do
|
45
|
+
expect($stdout).not_to receive(:info)
|
46
|
+
|
47
|
+
described_class.fail_on_error(external_tool, '0', 'My success output', quiet: true,
|
48
|
+
print_on_failure: true)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should not log failure output when not in the quiet mode' do
|
52
|
+
expect($stdout).not_to receive(:info)
|
53
|
+
|
54
|
+
described_class.fail_on_error(external_tool, '0', 'My success output', quiet: false,
|
55
|
+
print_on_failure: true)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
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
|
+
version: 1.4.2
|
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-
|
12
|
+
date: 2023-06-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: colorize
|
@@ -44,6 +44,7 @@ files:
|
|
44
44
|
- lib/runner_execution.rb
|
45
45
|
- spec/git_fastclone_runner_spec.rb
|
46
46
|
- spec/git_fastclone_url_helper_spec.rb
|
47
|
+
- spec/runner_execution_spec.rb
|
47
48
|
- spec/spec_helper.rb
|
48
49
|
homepage: http://square.github.io/git-fastclone/
|
49
50
|
licenses:
|
@@ -65,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
66
|
- !ruby/object:Gem::Version
|
66
67
|
version: '0'
|
67
68
|
requirements: []
|
68
|
-
rubygems_version: 3.
|
69
|
+
rubygems_version: 3.4.13
|
69
70
|
signing_key:
|
70
71
|
specification_version: 4
|
71
72
|
summary: git-clone --recursive on steroids!
|