git 2.0.0.pre1 → 2.0.0.pre3
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/.github/workflows/continuous_integration.yml +2 -2
- data/CHANGELOG.md +17 -0
- data/README.md +125 -5
- data/git.gemspec +1 -1
- data/lib/git/base.rb +21 -8
- 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 +45 -4
- 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: 0bd064fe363a807e4c9a77eaf61810f6fc41323ad1b60a57eb0379460f26e91c
|
4
|
+
data.tar.gz: 890bb2663ba5e3cc9b12f3dae403a019e3b7eb0ffb95ad2fdf5989073d53e807
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bbd732fb4061c1b68500860218eb14248adc48d4e4ff77d9b2c19cd13de5cb54c9c1bf313949131c91c7e3a25b24d8d105abb485571e06b25415875a67ce4f94
|
7
|
+
data.tar.gz: 6bf02024406485e4150cc76073d859446e490a659e6a17dad1f0f04c9d0084bcb063ccbc12dc839baa1b20094e2a2dcaf800c744560c49eab29264b588d154fb
|
@@ -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,23 @@
|
|
5
5
|
|
6
6
|
# Change Log
|
7
7
|
|
8
|
+
## v2.0.0.pre3 (2024-03-15)
|
9
|
+
|
10
|
+
[Full Changelog](https://github.com/ruby-git/ruby-git/compare/v2.0.0.pre2..v2.0.0.pre3)
|
11
|
+
|
12
|
+
Changes since v2.0.0.pre2:
|
13
|
+
|
14
|
+
* 5d4b34e Allow allow_unrelated_histories option for Base#pull
|
15
|
+
|
16
|
+
## v2.0.0.pre2 (2024-02-24)
|
17
|
+
|
18
|
+
[Full Changelog](https://github.com/ruby-git/ruby-git/compare/v2.0.0.pre1..v2.0.0.pre2)
|
19
|
+
|
20
|
+
Changes since v2.0.0.pre1:
|
21
|
+
|
22
|
+
* 023017b Add a timeout for git commands (#692)
|
23
|
+
* 8286ceb Refactor the Error heriarchy (#693)
|
24
|
+
|
8
25
|
## v2.0.0.pre1 (2024-01-15)
|
9
26
|
|
10
27
|
[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
|
[](https://github.com/ruby-git/ruby-git/actions?query=workflow%3ACI)
|
12
12
|
[](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/base.rb
CHANGED
@@ -409,14 +409,27 @@ module Git
|
|
409
409
|
self.lib.conflicts(&block)
|
410
410
|
end
|
411
411
|
|
412
|
-
#
|
413
|
-
#
|
414
|
-
#
|
415
|
-
#
|
416
|
-
#
|
417
|
-
#
|
418
|
-
|
419
|
-
|
412
|
+
# Pulls the given branch from the given remote into the current branch
|
413
|
+
#
|
414
|
+
# @param remote [String] the remote repository to pull from
|
415
|
+
# @param branch [String] the branch to pull from
|
416
|
+
# @param opts [Hash] options to pass to the pull command
|
417
|
+
#
|
418
|
+
# @option opts [Boolean] :allow_unrelated_histories (false) Merges histories of two projects that started their
|
419
|
+
# lives independently
|
420
|
+
# @example pulls from origin/master
|
421
|
+
# @git.pull
|
422
|
+
# @example pulls from upstream/master
|
423
|
+
# @git.pull('upstream')
|
424
|
+
# @example pulls from upstream/develop
|
425
|
+
# @git.pull('upstream', 'develop')
|
426
|
+
#
|
427
|
+
# @return [Void]
|
428
|
+
#
|
429
|
+
# @raise [Git::FailedError] if the pull fails
|
430
|
+
# @raise [ArgumentError] if a branch is given without a remote
|
431
|
+
def pull(remote = nil, branch = nil, opts = {})
|
432
|
+
self.lib.pull(remote, branch, opts)
|
420
433
|
end
|
421
434
|
|
422
435
|
# returns an array of Git:Remote objects
|
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
|
@@ -1006,10 +1006,11 @@ module Git
|
|
1006
1006
|
end
|
1007
1007
|
end
|
1008
1008
|
|
1009
|
-
def pull(remote = nil, branch = nil)
|
1009
|
+
def pull(remote = nil, branch = nil, opts = {})
|
1010
1010
|
raise ArgumentError, "You must specify a remote if a branch is specified" if remote.nil? && !branch.nil?
|
1011
1011
|
|
1012
1012
|
arr_opts = []
|
1013
|
+
arr_opts << '--allow-unrelated-histories' if opts[:allow_unrelated_histories]
|
1013
1014
|
arr_opts << remote if remote
|
1014
1015
|
arr_opts << branch if branch
|
1015
1016
|
command('pull', *arr_opts)
|
@@ -1191,8 +1192,48 @@ module Git
|
|
1191
1192
|
Git::CommandLine.new(env_overrides, Git::Base.config.binary_path, global_opts, @logger)
|
1192
1193
|
end
|
1193
1194
|
|
1194
|
-
|
1195
|
-
|
1195
|
+
# Runs a git command and returns the output
|
1196
|
+
#
|
1197
|
+
# @param args [Array] the git command to run and its arguments
|
1198
|
+
#
|
1199
|
+
# This should exclude the 'git' command itself and global options.
|
1200
|
+
#
|
1201
|
+
# For example, to run `git log --pretty=oneline`, you would pass `['log',
|
1202
|
+
# '--pretty=oneline']`
|
1203
|
+
#
|
1204
|
+
# @param out [String, nil] the path to a file or an IO to write the command's
|
1205
|
+
# stdout to
|
1206
|
+
#
|
1207
|
+
# @param err [String, nil] the path to a file or an IO to write the command's
|
1208
|
+
# stdout to
|
1209
|
+
#
|
1210
|
+
# @param normalize [Boolean] true to normalize the output encoding
|
1211
|
+
#
|
1212
|
+
# @param chomp [Boolean] true to remove trailing newlines from the output
|
1213
|
+
#
|
1214
|
+
# @param merge [Boolean] true to merge stdout and stderr
|
1215
|
+
#
|
1216
|
+
# @param chdir [String, nil] the directory to run the command in
|
1217
|
+
#
|
1218
|
+
# @param timeout [Numeric, nil] the maximum time to wait for the command to
|
1219
|
+
# complete
|
1220
|
+
#
|
1221
|
+
# @see Git::CommandLine#run
|
1222
|
+
#
|
1223
|
+
# @return [String] the command's stdout (or merged stdout and stderr if `merge`
|
1224
|
+
# is true)
|
1225
|
+
#
|
1226
|
+
# @raise [Git::GitExecuteError] if the command fails
|
1227
|
+
#
|
1228
|
+
# The exception's `result` attribute is a {Git::CommandLineResult} which will
|
1229
|
+
# contain the result of the command including the exit status, stdout, and
|
1230
|
+
# stderr.
|
1231
|
+
#
|
1232
|
+
# @api private
|
1233
|
+
#
|
1234
|
+
def command(*args, out: nil, err: nil, normalize: true, chomp: true, merge: false, chdir: nil, timeout: nil)
|
1235
|
+
timeout = timeout || Git.config.timeout
|
1236
|
+
result = command_line.run(*args, out: out, err: err, normalize: normalize, chomp: chomp, merge: merge, chdir: chdir, timeout: timeout)
|
1196
1237
|
result.stdout
|
1197
1238
|
end
|
1198
1239
|
|
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.pre3
|
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-03-15 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.pre3/file/CHANGELOG.md
|
226
|
+
documentation_uri: https://rubydoc.info/gems/git/2.0.0.pre3
|
224
227
|
post_install_message:
|
225
228
|
rdoc_options: []
|
226
229
|
require_paths:
|