git 2.0.0.pre1 → 2.0.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/continuous_integration.yml +2 -2
- data/CHANGELOG.md +9 -0
- data/README.md +125 -5
- data/git.gemspec +1 -1
- data/lib/git/command_line.rb +35 -9
- data/lib/git/command_line_error.rb +59 -0
- data/lib/git/config.rb +5 -1
- data/lib/git/error.rb +7 -0
- data/lib/git/failed_error.rb +4 -41
- data/lib/git/git_execute_error.rb +8 -1
- data/lib/git/lib.rb +43 -3
- data/lib/git/signaled_error.rb +3 -39
- data/lib/git/timeout_error.rb +60 -0
- data/lib/git/version.rb +1 -1
- data/lib/git.rb +3 -1
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23b5fa33a9a0cb112334c8b243abd6b388984d5f63aa2ee57f83e67d66e68f4b
|
4
|
+
data.tar.gz: 292e0d1c9aa4ce4671206abcdb1a547ab606090ecd7b8f2d182def4721347c03
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2332e16fc52d5ff5fd67cea38a1e4196bb98c06256746e81d13b0572ac78957743559eb27b8de752ba8c960e72f912cb5077fce625b6233ed6e63e1c2ef67890
|
7
|
+
data.tar.gz: bf769b8943941cec7efa01bae6152302023045d01a69c6aaddf9c04f8815eb18828a2e81b8133d0c7ab873235f08acfecce528d3e7f8659fb032baa73e44c6a1
|
@@ -18,7 +18,7 @@ jobs:
|
|
18
18
|
fail-fast: false
|
19
19
|
matrix:
|
20
20
|
# Only the latest versions of JRuby and TruffleRuby are tested
|
21
|
-
ruby: ["3.0", "3.1", "3.2", "3.3", "truffleruby-
|
21
|
+
ruby: ["3.0", "3.1", "3.2", "3.3", "truffleruby-24.0.0", "jruby-9.4.5.0"]
|
22
22
|
operating-system: [ubuntu-latest]
|
23
23
|
experimental: [No]
|
24
24
|
include:
|
@@ -38,7 +38,7 @@ jobs:
|
|
38
38
|
|
39
39
|
steps:
|
40
40
|
- name: Checkout Code
|
41
|
-
uses: actions/checkout@
|
41
|
+
uses: actions/checkout@v4
|
42
42
|
|
43
43
|
- name: Setup Ruby
|
44
44
|
uses: ruby/setup-ruby@v1
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,15 @@
|
|
5
5
|
|
6
6
|
# Change Log
|
7
7
|
|
8
|
+
## v2.0.0.pre2 (2024-02-24)
|
9
|
+
|
10
|
+
[Full Changelog](https://github.com/ruby-git/ruby-git/compare/v2.0.0.pre1..v2.0.0.pre2)
|
11
|
+
|
12
|
+
Changes since v2.0.0.pre1:
|
13
|
+
|
14
|
+
* 023017b Add a timeout for git commands (#692)
|
15
|
+
* 8286ceb Refactor the Error heriarchy (#693)
|
16
|
+
|
8
17
|
## v2.0.0.pre1 (2024-01-15)
|
9
18
|
|
10
19
|
[Full Changelog](https://github.com/ruby-git/ruby-git/compare/v1.19.1..v2.0.0.pre1)
|
data/README.md
CHANGED
@@ -11,6 +11,18 @@
|
|
11
11
|
[![Build Status](https://github.com/ruby-git/ruby-git/workflows/CI/badge.svg?branch=master)](https://github.com/ruby-git/ruby-git/actions?query=workflow%3ACI)
|
12
12
|
[![Code Climate](https://codeclimate.com/github/ruby-git/ruby-git.png)](https://codeclimate.com/github/ruby-git/ruby-git)
|
13
13
|
|
14
|
+
* [Summary](#summary)
|
15
|
+
* [v2.0.0 pre-release](#v200-pre-release)
|
16
|
+
* [Install](#install)
|
17
|
+
* [Major Objects](#major-objects)
|
18
|
+
* [Errors Raised By This Gem](#errors-raised-by-this-gem)
|
19
|
+
* [Specifying And Handling Timeouts](#specifying-and-handling-timeouts)
|
20
|
+
* [Examples](#examples)
|
21
|
+
* [Ruby version support policy](#ruby-version-support-policy)
|
22
|
+
* [License](#license)
|
23
|
+
|
24
|
+
## Summary
|
25
|
+
|
14
26
|
The [git gem](https://rubygems.org/gems/git) provides an API that can be used to
|
15
27
|
create, read, and manipulate Git repositories by wrapping system calls to the `git`
|
16
28
|
command line. The API can be used for working with Git in complex interactions
|
@@ -90,11 +102,119 @@ Pass the `--all` option to `git log` as follows:
|
|
90
102
|
|
91
103
|
**Git::Worktrees** - Enumerable object that holds `Git::Worktree objects`.
|
92
104
|
|
105
|
+
## Errors Raised By This Gem
|
106
|
+
|
107
|
+
This gem raises custom errors that derive from `Git::Error`. These errors are
|
108
|
+
arranged in the following class heirarchy:
|
109
|
+
|
110
|
+
Error heirarchy:
|
111
|
+
|
112
|
+
```text
|
113
|
+
Error
|
114
|
+
└── CommandLineError
|
115
|
+
├── FailedError
|
116
|
+
└── SignaledError
|
117
|
+
└── TimeoutError
|
118
|
+
```
|
119
|
+
|
120
|
+
Other standard errors may also be raised like `ArgumentError`. Each method should
|
121
|
+
document the errors it may raise.
|
122
|
+
|
123
|
+
Description of each Error class:
|
124
|
+
|
125
|
+
* `Error`: This catch-all error serves as the base class for other custom errors in this
|
126
|
+
gem. Errors of this class are raised when no more approriate specific error to
|
127
|
+
raise.
|
128
|
+
* `CommandLineError`: This error is raised when there's a problem executing the git
|
129
|
+
command line. This gem will raise a more specific error depending on how the
|
130
|
+
command line failed.
|
131
|
+
* `FailedError`: This error is raised when the git command line exits with a non-zero
|
132
|
+
status code that is not expected by the git gem.
|
133
|
+
* `SignaledError`: This error is raised when the git command line is terminated as a
|
134
|
+
result of receiving a signal. This could happen if the process is forcibly
|
135
|
+
terminated or if there is a serious system error.
|
136
|
+
* `TimeoutError`: This is a specific type of `SignaledError` that is raised when the
|
137
|
+
git command line operation times out and is killed via the SIGKILL signal. This
|
138
|
+
happens if the operation takes longer than the timeout duration configured in
|
139
|
+
`Git.config.timeout` or via the `:timeout` parameter given in git methods that
|
140
|
+
support this parameter.
|
141
|
+
|
142
|
+
`Git::GitExecuteError` remains as an alias for `Git::Error`. It is considered
|
143
|
+
deprecated as of git-2.0.0.
|
144
|
+
|
145
|
+
Here is an example of catching errors when using the git gem:
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
begin
|
149
|
+
timeout_duration = 0.001 # seconds
|
150
|
+
repo = Git.clone('https://github.com/ruby-git/ruby-git', 'ruby-git-temp', timeout: timeout_duration)
|
151
|
+
rescue Git::TimeoutError => e # Catch the more specific error first!
|
152
|
+
puts "Git clone took too long and timed out #{e}"
|
153
|
+
rescue Git::Error => e
|
154
|
+
puts "Received the following error: #{e}"
|
155
|
+
```
|
156
|
+
|
157
|
+
## Specifying And Handling Timeouts
|
158
|
+
|
159
|
+
The timeout feature was added in git gem version `2.0.0`.
|
160
|
+
|
161
|
+
A timeout for git operations can be set either globally or for specific method calls
|
162
|
+
that accept a `:timeout` parameter.
|
163
|
+
|
164
|
+
The timeout value must be a real, non-negative `Numeric` value that specifies a
|
165
|
+
number of seconds a `git` command will be given to complete before being sent a KILL
|
166
|
+
signal. This library may hang if the `git` command does not terminate after receiving
|
167
|
+
the KILL signal.
|
168
|
+
|
169
|
+
When a command times out, a `Git::TimeoutError` is raised.
|
170
|
+
|
171
|
+
If the timeout value is `0` or `nil`, no timeout will be enforced.
|
172
|
+
|
173
|
+
If a method accepts a `:timeout` parameter and a receives a non-nil value, it will
|
174
|
+
override the global timeout value. In this context, a value of `nil` (which is
|
175
|
+
usually the default) will use the global timeout value and a value of `0` will turn
|
176
|
+
off timeout enforcement for that method call no matter what the global value is.
|
177
|
+
|
178
|
+
To set a global timeout, use the `Git.config` object:
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
Git.config.timeout = nil # a value of nil or 0 means no timeout is enforced
|
182
|
+
Git.config.timeout = 1.5 # can be any real, non-negative Numeric interpreted as number of seconds
|
183
|
+
```
|
184
|
+
|
185
|
+
The global timeout can be overridden for a specific method if the method accepts a
|
186
|
+
`:timeout` parameter:
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
repo_url = 'https://github.com/ruby-git/ruby-git.git'
|
190
|
+
Git.clone(repo_url) # Use the global timeout value
|
191
|
+
Git.clone(repo_url, timeout: nil) # Also uses the global timeout value
|
192
|
+
Git.clone(repo_url, timeout: 0) # Do not enforce a timeout
|
193
|
+
Git.clone(repo_url, timeout: 10.5) # Timeout after 10.5 seconds raising Git::SignaledError
|
194
|
+
```
|
195
|
+
|
196
|
+
If the command takes too long, a `Git::SignaledError` will be raised:
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
begin
|
200
|
+
Git.clone(repo_url, timeout: 10)
|
201
|
+
rescue Git::TimeoutError => e
|
202
|
+
result = e.result
|
203
|
+
result.class #=> Git::CommandLineResult
|
204
|
+
result.status #=> #<Process::Status: pid 62173 SIGKILL (signal 9)>
|
205
|
+
result.status.timeout? #=> true
|
206
|
+
result.git_cmd # The git command ran as an array of strings
|
207
|
+
result.stdout # The command's output to stdout until it was terminated
|
208
|
+
result.stderr # The command's output to stderr until it was terminated
|
209
|
+
end
|
210
|
+
```
|
211
|
+
|
93
212
|
## Examples
|
94
213
|
|
95
214
|
Here are a bunch of examples of how to use the Ruby/Git package.
|
96
215
|
|
97
216
|
Require the 'git' gem.
|
217
|
+
|
98
218
|
```ruby
|
99
219
|
require 'git'
|
100
220
|
```
|
@@ -261,11 +381,11 @@ g.add(:all=>true) # git add --all -- "."
|
|
261
381
|
g.add('file_path') # git add -- "file_path"
|
262
382
|
g.add(['file_path_1', 'file_path_2']) # git add -- "file_path_1" "file_path_2"
|
263
383
|
|
264
|
-
g.remove()
|
265
|
-
g.remove('file.txt')
|
266
|
-
g.remove(['file.txt', 'file2.txt'])
|
267
|
-
g.remove('file.txt', :recursive => true)
|
268
|
-
g.remove('file.txt', :cached => true)
|
384
|
+
g.remove() # git rm -f -- "."
|
385
|
+
g.remove('file.txt') # git rm -f -- "file.txt"
|
386
|
+
g.remove(['file.txt', 'file2.txt']) # git rm -f -- "file.txt" "file2.txt"
|
387
|
+
g.remove('file.txt', :recursive => true) # git rm -f -r -- "file.txt"
|
388
|
+
g.remove('file.txt', :cached => true) # git rm -f --cached -- "file.txt"
|
269
389
|
|
270
390
|
g.commit('message')
|
271
391
|
g.commit_all('message')
|
data/git.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.requirements = ['git 2.28.0 or greater']
|
29
29
|
|
30
30
|
s.add_runtime_dependency 'addressable', '~> 2.8'
|
31
|
-
s.add_runtime_dependency 'process_executer', '~>
|
31
|
+
s.add_runtime_dependency 'process_executer', '~> 1.1'
|
32
32
|
s.add_runtime_dependency 'rchardet', '~> 1.8'
|
33
33
|
|
34
34
|
s.add_development_dependency 'minitar', '~> 0.9'
|
data/lib/git/command_line.rb
CHANGED
@@ -166,6 +166,13 @@ module Git
|
|
166
166
|
# @param merge [Boolean] whether to merge stdout and stderr in the string returned
|
167
167
|
# @param chdir [String] the directory to run the command in
|
168
168
|
#
|
169
|
+
# @param timeout [Numeric, nil] the maximum seconds to wait for the command to complete
|
170
|
+
#
|
171
|
+
# If timeout is zero or nil, the command will not time out. If the command
|
172
|
+
# times out, it is killed via a SIGKILL signal and `Git::TimeoutError` is raised.
|
173
|
+
#
|
174
|
+
# If the command does not respond to SIGKILL, it will hang this method.
|
175
|
+
#
|
169
176
|
# @return [Git::CommandLineResult] the output of the command
|
170
177
|
#
|
171
178
|
# This result of running the command.
|
@@ -173,14 +180,16 @@ module Git
|
|
173
180
|
# @raise [ArgumentError] if `args` is not an array of strings
|
174
181
|
# @raise [Git::SignaledError] if the command was terminated because of an uncaught signal
|
175
182
|
# @raise [Git::FailedError] if the command returned a non-zero exitstatus
|
183
|
+
# @raise [Git::GitExecuteError] if an exception was raised while collecting subprocess output
|
184
|
+
# @raise [Git::TimeoutError] if the command times out
|
176
185
|
#
|
177
|
-
def run(*args, out:, err:, normalize:, chomp:, merge:, chdir: nil)
|
186
|
+
def run(*args, out:, err:, normalize:, chomp:, merge:, chdir: nil, timeout: nil)
|
178
187
|
git_cmd = build_git_cmd(args)
|
179
188
|
out ||= StringIO.new
|
180
189
|
err ||= (merge ? out : StringIO.new)
|
181
|
-
status = execute(git_cmd, out, err, chdir: (chdir || :not_set))
|
190
|
+
status = execute(git_cmd, out, err, chdir: (chdir || :not_set), timeout: timeout)
|
182
191
|
|
183
|
-
process_result(git_cmd, status, out, err, normalize, chomp)
|
192
|
+
process_result(git_cmd, status, out, err, normalize, chomp, timeout)
|
184
193
|
end
|
185
194
|
|
186
195
|
private
|
@@ -258,17 +267,24 @@ module Git
|
|
258
267
|
#
|
259
268
|
# @param cmd [Array<String>] the git command to execute
|
260
269
|
# @param chdir [String] the directory to run the command in
|
270
|
+
# @param timeout [Float, Integer, nil] the maximum seconds to wait for the command to complete
|
271
|
+
#
|
272
|
+
# If timeout is zero of nil, the command will not time out. If the command
|
273
|
+
# times out, it is killed via a SIGKILL signal and `Git::TimeoutError` is raised.
|
274
|
+
#
|
275
|
+
# If the command does not respond to SIGKILL, it will hang this method.
|
261
276
|
#
|
262
277
|
# @raise [Git::GitExecuteError] if an exception was raised while collecting subprocess output
|
278
|
+
# @raise [Git::TimeoutError] if the command times out
|
263
279
|
#
|
264
|
-
# @return [
|
280
|
+
# @return [ProcessExecuter::Status] the status of the completed subprocess
|
265
281
|
#
|
266
282
|
# @api private
|
267
283
|
#
|
268
|
-
def spawn(cmd, out_writers, err_writers, chdir:)
|
284
|
+
def spawn(cmd, out_writers, err_writers, chdir:, timeout:)
|
269
285
|
out_pipe = ProcessExecuter::MonitoredPipe.new(*out_writers, chunk_size: 10_000)
|
270
286
|
err_pipe = ProcessExecuter::MonitoredPipe.new(*err_writers, chunk_size: 10_000)
|
271
|
-
ProcessExecuter.spawn(env, *cmd, out: out_pipe, err: err_pipe, chdir: chdir)
|
287
|
+
ProcessExecuter.spawn(env, *cmd, out: out_pipe, err: err_pipe, chdir: chdir, timeout: timeout)
|
272
288
|
ensure
|
273
289
|
out_pipe.close
|
274
290
|
err_pipe.close
|
@@ -313,11 +329,12 @@ module Git
|
|
313
329
|
#
|
314
330
|
# @api private
|
315
331
|
#
|
316
|
-
def process_result(git_cmd, status, out, err, normalize, chomp)
|
332
|
+
def process_result(git_cmd, status, out, err, normalize, chomp, timeout)
|
317
333
|
out_str, err_str = post_process_all([out, err], normalize, chomp)
|
318
334
|
logger.info { "#{git_cmd} exited with status #{status}" }
|
319
335
|
logger.debug { "stdout:\n#{out_str.inspect}\nstderr:\n#{err_str.inspect}" }
|
320
336
|
Git::CommandLineResult.new(git_cmd, status, out_str, err_str).tap do |result|
|
337
|
+
raise Git::TimeoutError.new(result, timeout) if status.timeout?
|
321
338
|
raise Git::SignaledError.new(result) if status.signaled?
|
322
339
|
raise Git::FailedError.new(result) unless status.success?
|
323
340
|
end
|
@@ -329,14 +346,23 @@ module Git
|
|
329
346
|
# @param out [#write] the object to write stdout to
|
330
347
|
# @param err [#write] the object to write stderr to
|
331
348
|
# @param chdir [String] the directory to run the command in
|
349
|
+
# @param timeout [Float, Integer, nil] the maximum seconds to wait for the command to complete
|
350
|
+
#
|
351
|
+
# If timeout is zero of nil, the command will not time out. If the command
|
352
|
+
# times out, it is killed via a SIGKILL signal and `Git::TimeoutError` is raised.
|
353
|
+
#
|
354
|
+
# If the command does not respond to SIGKILL, it will hang this method.
|
355
|
+
#
|
356
|
+
# @raise [Git::GitExecuteError] if an exception was raised while collecting subprocess output
|
357
|
+
# @raise [Git::TimeoutError] if the command times out
|
332
358
|
#
|
333
359
|
# @return [Git::CommandLineResult] the result of the command to return to the caller
|
334
360
|
#
|
335
361
|
# @api private
|
336
362
|
#
|
337
|
-
def execute(git_cmd, out, err, chdir:)
|
363
|
+
def execute(git_cmd, out, err, chdir:, timeout:)
|
338
364
|
out_writers, err_writers = writers(out, err)
|
339
|
-
spawn(git_cmd, out_writers, err_writers, chdir: chdir)
|
365
|
+
spawn(git_cmd, out_writers, err_writers, chdir: chdir, timeout: timeout)
|
340
366
|
end
|
341
367
|
end
|
342
368
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'error'
|
4
|
+
|
5
|
+
module Git
|
6
|
+
# Raised when a git command fails or exits because of an uncaught signal
|
7
|
+
#
|
8
|
+
# The git command executed, status, stdout, and stderr are available from this
|
9
|
+
# object.
|
10
|
+
#
|
11
|
+
# Rather than creating a CommandLineError object directly, it is recommended to use
|
12
|
+
# one of the derived classes for the appropriate type of error:
|
13
|
+
#
|
14
|
+
# * {Git::FailedError}: when the git command exits with a non-zero status
|
15
|
+
# * {Git::SignaledError}: when the git command exits because of an uncaught signal
|
16
|
+
# * {Git::TimeoutError}: when the git command times out
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
#
|
20
|
+
class CommandLineError < Git::Error
|
21
|
+
# Create a CommandLineError object
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# `exit 1` # set $? appropriately for this example
|
25
|
+
# result = Git::CommandLineResult.new(%w[git status], $?, 'stdout', 'stderr')
|
26
|
+
# error = Git::CommandLineError.new(result)
|
27
|
+
# error.to_s #=> '["git", "status"], status: pid 89784 exit 1, stderr: "stderr"'
|
28
|
+
#
|
29
|
+
# @param result [Git::CommandLineResult] the result of the git command including
|
30
|
+
# the git command, status, stdout, and stderr
|
31
|
+
#
|
32
|
+
def initialize(result)
|
33
|
+
@result = result
|
34
|
+
super()
|
35
|
+
end
|
36
|
+
|
37
|
+
# The human readable representation of this error
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# error.to_s #=> '["git", "status"], status: pid 89784 exit 1, stderr: "stderr"'
|
41
|
+
#
|
42
|
+
# @return [String]
|
43
|
+
#
|
44
|
+
def to_s = <<~MESSAGE.chomp
|
45
|
+
#{result.git_cmd}, status: #{result.status}, stderr: #{result.stderr.inspect}
|
46
|
+
MESSAGE
|
47
|
+
|
48
|
+
# @attribute [r] result
|
49
|
+
#
|
50
|
+
# The result of the git command including the git command and its status and output
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# error.result #=> #<Git::CommandLineResult:0x00000001046bd488 ...>
|
54
|
+
#
|
55
|
+
# @return [Git::CommandLineResult]
|
56
|
+
#
|
57
|
+
attr_reader :result
|
58
|
+
end
|
59
|
+
end
|
data/lib/git/config.rb
CHANGED
@@ -2,11 +2,12 @@ module Git
|
|
2
2
|
|
3
3
|
class Config
|
4
4
|
|
5
|
-
attr_writer :binary_path, :git_ssh
|
5
|
+
attr_writer :binary_path, :git_ssh, :timeout
|
6
6
|
|
7
7
|
def initialize
|
8
8
|
@binary_path = nil
|
9
9
|
@git_ssh = nil
|
10
|
+
@timeout = nil
|
10
11
|
end
|
11
12
|
|
12
13
|
def binary_path
|
@@ -17,6 +18,9 @@ module Git
|
|
17
18
|
@git_ssh || ENV['GIT_SSH']
|
18
19
|
end
|
19
20
|
|
21
|
+
def timeout
|
22
|
+
@timeout || (ENV['GIT_TIMEOUT'] && ENV['GIT_TIMEOUT'].to_i)
|
23
|
+
end
|
20
24
|
end
|
21
25
|
|
22
26
|
end
|
data/lib/git/error.rb
ADDED
data/lib/git/failed_error.rb
CHANGED
@@ -1,51 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'command_line_error'
|
4
4
|
|
5
5
|
module Git
|
6
|
-
# This error is raised when a git command
|
6
|
+
# This error is raised when a git command returns a non-zero exitstatus
|
7
7
|
#
|
8
8
|
# The git command executed, status, stdout, and stderr are available from this
|
9
|
-
# object.
|
10
|
-
# the stderr of the process.
|
9
|
+
# object.
|
11
10
|
#
|
12
11
|
# @api public
|
13
12
|
#
|
14
|
-
class FailedError < Git::
|
15
|
-
# Create a FailedError object
|
16
|
-
#
|
17
|
-
# @example
|
18
|
-
# `exit 1` # set $? appropriately for this example
|
19
|
-
# result = Git::CommandLineResult.new(%w[git status], $?, 'stdout', 'stderr')
|
20
|
-
# error = Git::FailedError.new(result)
|
21
|
-
# error.message #=>
|
22
|
-
# "[\"git\", \"status\"]\nstatus: pid 89784 exit 1\nstderr: \"stderr\""
|
23
|
-
#
|
24
|
-
# @param result [Git::CommandLineResult] the result of the git command including
|
25
|
-
# the git command, status, stdout, and stderr
|
26
|
-
#
|
27
|
-
def initialize(result)
|
28
|
-
super("#{result.git_cmd}\nstatus: #{result.status}\nstderr: #{result.stderr.inspect}")
|
29
|
-
@result = result
|
30
|
-
end
|
31
|
-
|
32
|
-
# @attribute [r] result
|
33
|
-
#
|
34
|
-
# The result of the git command including the git command and its status and output
|
35
|
-
#
|
36
|
-
# @example
|
37
|
-
# `exit 1` # set $? appropriately for this example
|
38
|
-
# result = Git::CommandLineResult.new(%w[git status], $?, 'stdout', 'stderr')
|
39
|
-
# error = Git::FailedError.new(result)
|
40
|
-
# error.result #=>
|
41
|
-
# #<Git::CommandLineResult:0x00000001046bd488
|
42
|
-
# @git_cmd=["git", "status"],
|
43
|
-
# @status=#<Process::Status: pid 89784 exit 1>,
|
44
|
-
# @stderr="stderr",
|
45
|
-
# @stdout="stdout">
|
46
|
-
#
|
47
|
-
# @return [Git::CommandLineResult]
|
48
|
-
#
|
49
|
-
attr_reader :result
|
50
|
-
end
|
13
|
+
class FailedError < Git::CommandLineError; end
|
51
14
|
end
|
@@ -1,7 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'error'
|
4
|
+
|
3
5
|
module Git
|
4
6
|
# This error is raised when a git command fails
|
5
7
|
#
|
6
|
-
class
|
8
|
+
# This error class is used as an alias for Git::Error for backwards compatibility.
|
9
|
+
# It is recommended to use Git::Error directly.
|
10
|
+
#
|
11
|
+
# @deprecated Use Git::Error instead
|
12
|
+
#
|
13
|
+
GitExecuteError = Git::Error
|
7
14
|
end
|
data/lib/git/lib.rb
CHANGED
@@ -115,7 +115,7 @@ module Git
|
|
115
115
|
arr_opts << repository_url
|
116
116
|
arr_opts << clone_dir
|
117
117
|
|
118
|
-
command('clone', *arr_opts)
|
118
|
+
command('clone', *arr_opts, timeout: opts[:timeout])
|
119
119
|
|
120
120
|
return_base_opts_from_clone(clone_dir, opts)
|
121
121
|
end
|
@@ -1191,8 +1191,48 @@ module Git
|
|
1191
1191
|
Git::CommandLine.new(env_overrides, Git::Base.config.binary_path, global_opts, @logger)
|
1192
1192
|
end
|
1193
1193
|
|
1194
|
-
|
1195
|
-
|
1194
|
+
# Runs a git command and returns the output
|
1195
|
+
#
|
1196
|
+
# @param args [Array] the git command to run and its arguments
|
1197
|
+
#
|
1198
|
+
# This should exclude the 'git' command itself and global options.
|
1199
|
+
#
|
1200
|
+
# For example, to run `git log --pretty=oneline`, you would pass `['log',
|
1201
|
+
# '--pretty=oneline']`
|
1202
|
+
#
|
1203
|
+
# @param out [String, nil] the path to a file or an IO to write the command's
|
1204
|
+
# stdout to
|
1205
|
+
#
|
1206
|
+
# @param err [String, nil] the path to a file or an IO to write the command's
|
1207
|
+
# stdout to
|
1208
|
+
#
|
1209
|
+
# @param normalize [Boolean] true to normalize the output encoding
|
1210
|
+
#
|
1211
|
+
# @param chomp [Boolean] true to remove trailing newlines from the output
|
1212
|
+
#
|
1213
|
+
# @param merge [Boolean] true to merge stdout and stderr
|
1214
|
+
#
|
1215
|
+
# @param chdir [String, nil] the directory to run the command in
|
1216
|
+
#
|
1217
|
+
# @param timeout [Numeric, nil] the maximum time to wait for the command to
|
1218
|
+
# complete
|
1219
|
+
#
|
1220
|
+
# @see Git::CommandLine#run
|
1221
|
+
#
|
1222
|
+
# @return [String] the command's stdout (or merged stdout and stderr if `merge`
|
1223
|
+
# is true)
|
1224
|
+
#
|
1225
|
+
# @raise [Git::GitExecuteError] if the command fails
|
1226
|
+
#
|
1227
|
+
# The exception's `result` attribute is a {Git::CommandLineResult} which will
|
1228
|
+
# contain the result of the command including the exit status, stdout, and
|
1229
|
+
# stderr.
|
1230
|
+
#
|
1231
|
+
# @api private
|
1232
|
+
#
|
1233
|
+
def command(*args, out: nil, err: nil, normalize: true, chomp: true, merge: false, chdir: nil, timeout: nil)
|
1234
|
+
timeout = timeout || Git.config.timeout
|
1235
|
+
result = command_line.run(*args, out: out, err: err, normalize: normalize, chomp: chomp, merge: merge, chdir: chdir, timeout: timeout)
|
1196
1236
|
result.stdout
|
1197
1237
|
end
|
1198
1238
|
|
data/lib/git/signaled_error.rb
CHANGED
@@ -1,50 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'command_line_error'
|
4
4
|
|
5
5
|
module Git
|
6
6
|
# This error is raised when a git command exits because of an uncaught signal
|
7
7
|
#
|
8
8
|
# The git command executed, status, stdout, and stderr are available from this
|
9
|
-
# object.
|
10
|
-
# the stderr of the process.
|
9
|
+
# object.
|
11
10
|
#
|
12
11
|
# @api public
|
13
12
|
#
|
14
|
-
class SignaledError < Git::
|
15
|
-
# Create a SignaledError object
|
16
|
-
#
|
17
|
-
# @example
|
18
|
-
# `kill -9 $$` # set $? appropriately for this example
|
19
|
-
# result = Git::CommandLineResult.new(%w[git status], $?, '', "killed")
|
20
|
-
# error = Git::SignaledError.new(result)
|
21
|
-
# error.message #=>
|
22
|
-
# "[\"git\", \"status\"]\nstatus: pid 88811 SIGKILL (signal 9)\nstderr: \"killed\""
|
23
|
-
#
|
24
|
-
# @param result [Git::CommandLineResult] the result of the git command including the git command, status, stdout, and stderr
|
25
|
-
#
|
26
|
-
def initialize(result)
|
27
|
-
super("#{result.git_cmd}\nstatus: #{result.status}\nstderr: #{result.stderr.inspect}")
|
28
|
-
@result = result
|
29
|
-
end
|
30
|
-
|
31
|
-
# @attribute [r] result
|
32
|
-
#
|
33
|
-
# The result of the git command including the git command, status, and output
|
34
|
-
#
|
35
|
-
# @example
|
36
|
-
# `kill -9 $$` # set $? appropriately for this example
|
37
|
-
# result = Git::CommandLineResult.new(%w[git status], $?, '', "killed")
|
38
|
-
# error = Git::SignaledError.new(result)
|
39
|
-
# error.result #=>
|
40
|
-
# #<Git::CommandLineResult:0x000000010470f6e8
|
41
|
-
# @git_cmd=["git", "status"],
|
42
|
-
# @status=#<Process::Status: pid 88811 SIGKILL (signal 9)>,
|
43
|
-
# @stderr="killed",
|
44
|
-
# @stdout="">
|
45
|
-
#
|
46
|
-
# @return [Git::CommandLineResult]
|
47
|
-
#
|
48
|
-
attr_reader :result
|
49
|
-
end
|
13
|
+
class SignaledError < Git::CommandLineError; end
|
50
14
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'signaled_error'
|
4
|
+
|
5
|
+
module Git
|
6
|
+
# This error is raised when a git command takes longer than the configured timeout
|
7
|
+
#
|
8
|
+
# The git command executed, status, stdout, and stderr, and the timeout duration
|
9
|
+
# are available from this object.
|
10
|
+
#
|
11
|
+
# result.status.timeout? will be `true`
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
#
|
15
|
+
class TimeoutError < Git::SignaledError
|
16
|
+
# Create a TimeoutError object
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# command = %w[sleep 10]
|
20
|
+
# timeout_duration = 1
|
21
|
+
# status = ProcessExecuter.spawn(*command, timeout: timeout_duration)
|
22
|
+
# result = Git::CommandLineResult.new(command, status, 'stdout', 'err output')
|
23
|
+
# error = Git::TimeoutError.new(result, timeout_duration)
|
24
|
+
# error.to_s #=> '["sleep", "10"], status: pid 70144 SIGKILL (signal 9), stderr: "err output", timed out after 1s'
|
25
|
+
#
|
26
|
+
# @param result [Git::CommandLineResult] the result of the git command including
|
27
|
+
# the git command, status, stdout, and stderr
|
28
|
+
#
|
29
|
+
# @param timeout_duration [Numeric] the amount of time the subprocess was allowed
|
30
|
+
# to run before being killed
|
31
|
+
#
|
32
|
+
def initialize(result, timeout_duration)
|
33
|
+
@timeout_duration = timeout_duration
|
34
|
+
super(result)
|
35
|
+
end
|
36
|
+
|
37
|
+
# The human readable representation of this error
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# error.to_s #=> '["sleep", "10"], status: pid 88811 SIGKILL (signal 9), stderr: "err output", timed out after 1s'
|
41
|
+
#
|
42
|
+
# @return [String]
|
43
|
+
#
|
44
|
+
def to_s = <<~MESSAGE.chomp
|
45
|
+
#{super}, timed out after #{timeout_duration}s
|
46
|
+
MESSAGE
|
47
|
+
|
48
|
+
# The amount of time the subprocess was allowed to run before being killed
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# `kill -9 $$` # set $? appropriately for this example
|
52
|
+
# result = Git::CommandLineResult.new(%w[git status], $?, '', "killed")
|
53
|
+
# error = Git::TimeoutError.new(result, 10)
|
54
|
+
# error.timeout_duration #=> 10
|
55
|
+
#
|
56
|
+
# @return [Numeric]
|
57
|
+
#
|
58
|
+
attr_reader :timeout_duration
|
59
|
+
end
|
60
|
+
end
|
data/lib/git/version.rb
CHANGED
data/lib/git.rb
CHANGED
@@ -7,11 +7,13 @@ require 'git/author'
|
|
7
7
|
require 'git/base'
|
8
8
|
require 'git/branch'
|
9
9
|
require 'git/branches'
|
10
|
+
require 'git/command_line_error'
|
10
11
|
require 'git/command_line_result'
|
11
12
|
require 'git/command_line'
|
12
13
|
require 'git/config'
|
13
14
|
require 'git/diff'
|
14
15
|
require 'git/encoding_utils'
|
16
|
+
require 'git/error'
|
15
17
|
require 'git/escaped_path'
|
16
18
|
require 'git/failed_error'
|
17
19
|
require 'git/git_execute_error'
|
@@ -24,9 +26,9 @@ require 'git/remote'
|
|
24
26
|
require 'git/repository'
|
25
27
|
require 'git/signaled_error'
|
26
28
|
require 'git/status'
|
27
|
-
require 'git/signaled_error'
|
28
29
|
require 'git/stash'
|
29
30
|
require 'git/stashes'
|
31
|
+
require 'git/timeout_error'
|
30
32
|
require 'git/url'
|
31
33
|
require 'git/version'
|
32
34
|
require 'git/working_directory'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.pre2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Chacon and others
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '1.1'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '1.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rchardet
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -190,10 +190,12 @@ files:
|
|
190
190
|
- lib/git/branch.rb
|
191
191
|
- lib/git/branches.rb
|
192
192
|
- lib/git/command_line.rb
|
193
|
+
- lib/git/command_line_error.rb
|
193
194
|
- lib/git/command_line_result.rb
|
194
195
|
- lib/git/config.rb
|
195
196
|
- lib/git/diff.rb
|
196
197
|
- lib/git/encoding_utils.rb
|
198
|
+
- lib/git/error.rb
|
197
199
|
- lib/git/escaped_path.rb
|
198
200
|
- lib/git/failed_error.rb
|
199
201
|
- lib/git/git_execute_error.rb
|
@@ -208,6 +210,7 @@ files:
|
|
208
210
|
- lib/git/stash.rb
|
209
211
|
- lib/git/stashes.rb
|
210
212
|
- lib/git/status.rb
|
213
|
+
- lib/git/timeout_error.rb
|
211
214
|
- lib/git/url.rb
|
212
215
|
- lib/git/version.rb
|
213
216
|
- lib/git/working_directory.rb
|
@@ -219,8 +222,8 @@ licenses:
|
|
219
222
|
metadata:
|
220
223
|
homepage_uri: http://github.com/ruby-git/ruby-git
|
221
224
|
source_code_uri: http://github.com/ruby-git/ruby-git
|
222
|
-
changelog_uri: https://rubydoc.info/gems/git/2.0.0.
|
223
|
-
documentation_uri: https://rubydoc.info/gems/git/2.0.0.
|
225
|
+
changelog_uri: https://rubydoc.info/gems/git/2.0.0.pre2/file/CHANGELOG.md
|
226
|
+
documentation_uri: https://rubydoc.info/gems/git/2.0.0.pre2
|
224
227
|
post_install_message:
|
225
228
|
rdoc_options: []
|
226
229
|
require_paths:
|