git-fastclone 1.4.0 → 1.4.2
Sign up to get free protection for your applications and to get access to all the features.
- 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!
|