Skip to content

Commit ebfe7d2

Browse files
committed
Integrate process_executor gem for controlling the git subprocess
Signed-off-by: James Couball <jcouball@yahoo.com>
1 parent b588e66 commit ebfe7d2

20 files changed

+1057
-539
lines changed

.github/workflows/continuous_integration.yml

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,27 @@ jobs:
1313
strategy:
1414
fail-fast: false
1515
matrix:
16-
ruby: [2.7, 3.0, 3.1, 3.2]
16+
ruby: [2.7, 3.0, 3.1, 3.2, head, jruby-head, truffleruby-head]
1717
operating-system: [ubuntu-latest]
1818
include:
19-
- ruby: head
20-
operating-system: ubuntu-latest
21-
- ruby: truffleruby-head
22-
operating-system: ubuntu-latest
23-
- ruby: 2.7
19+
-
20+
# Run minimal 2.x ruby version supported on windows-latest
21+
ruby: 2.7
2422
operating-system: windows-latest
25-
- ruby: jruby-head
23+
24+
-
25+
# Run minimal 3.x ruby version supported on windows-latest
26+
ruby: 3.0
27+
operating-system: windows-latest
28+
29+
-
30+
# Run jruby-latest on windows-latest
31+
ruby: jruby-head
2632
operating-system: windows-latest
33+
# Currently jruby is not support on windows for git-2.x
34+
# There are a few bugs that need to be fixed in JRuby first.
35+
# Remove this `continue-on-error` setting when the JRuby build is successful.
36+
continuing-on-error: true
2737

2838
name: Ruby ${{ matrix.ruby }} on ${{ matrix.operating-system }}
2939

bin/command_line_test

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
require 'optparse'
5+
6+
# A script used to test calling a command line program from Ruby
7+
#
8+
# This script is used to test the `Git::CommandLine` class. It is called
9+
# from the `test_command_line` unit test.
10+
#
11+
# --stdout: string to output to stdout
12+
# --stderr: string to output to stderr
13+
# --exitstatus: exit status to return (default is zero)
14+
# --signal: uncaught signal to raise (default is not to signal)
15+
#
16+
# Both --stdout and --stderr can be given.
17+
#
18+
# If --signal is given, --exitstatus is ignored.
19+
#
20+
# Examples:
21+
# Output "Hello, world!" to stdout and exit with status 0
22+
# $ bin/command_line_test --stdout="Hello, world!" --exitstatus=0
23+
#
24+
# Output "ERROR: timeout" to stderr and exit with status 1
25+
# $ bin/command_line_test --stderr="ERROR: timeout" --exitstatus=1
26+
#
27+
# Output "Fatal: killed by parent" to stderr and signal 9
28+
# $ bin/command_line_test --stderr="Fatal: killed by parent" --signal=9
29+
#
30+
# Output to both stdout and stderr return default exitstatus 0
31+
# $ bin/command_line_test --stdout="Hello, world!" --stderr="ERROR: timeout"
32+
#
33+
34+
35+
class CommandLineParser
36+
def initialize
37+
@option_parser = OptionParser.new
38+
define_options
39+
end
40+
41+
attr_reader :stdout, :stderr, :exitstatus, :signal
42+
43+
# Parse the command line arguements returning the options
44+
#
45+
# @example
46+
# parser = CommandLineParser.new
47+
# options = parser.parse(['major'])
48+
#
49+
# @param args [Array<String>] the command line arguments
50+
#
51+
# @return [CreateGithubRelease::Options] the options
52+
#
53+
def parse(*args)
54+
begin
55+
option_parser.parse!(remaining_args = args.dup)
56+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
57+
report_errors(e.message)
58+
end
59+
parse_remaining_args(remaining_args)
60+
# puts options unless options.quiet
61+
# report_errors(*options.errors) unless options.valid?
62+
self
63+
end
64+
65+
private
66+
67+
# @!attribute [rw] option_parser
68+
#
69+
# The option parser
70+
#
71+
# @return [OptionParser] the option parser
72+
#
73+
# @api private
74+
#
75+
attr_reader :option_parser
76+
77+
def define_options
78+
option_parser.banner = "Usage:\n#{command_template}"
79+
option_parser.separator ''
80+
option_parser.separator "Both --stdout and --stderr can be given."
81+
option_parser.separator 'If --signal is given, --exitstatus is ignored.'
82+
option_parser.separator 'If nothing is given, the script will exit with exitstatus 0.'
83+
option_parser.separator ''
84+
option_parser.separator 'Options:'
85+
%i[
86+
define_help_option define_stdout_option define_stderr_option
87+
define_exitstatus_option define_signal_option
88+
].each { |m| send(m) }
89+
end
90+
91+
# The command line template as a string
92+
# @return [String]
93+
# @api private
94+
def command_template
95+
<<~COMMAND
96+
#{File.basename($PROGRAM_NAME)} \
97+
--help | \
98+
[--stdout="string to stdout"] [--stderr="string to stderr"] [--exitstatus=1] [--signal=9]
99+
COMMAND
100+
end
101+
102+
# Define the stdout option
103+
# @return [void]
104+
# @api private
105+
def define_stdout_option
106+
option_parser.on('--stdout="string to stdout"', 'A string to send to stdout') do |string|
107+
@stdout = string
108+
end
109+
end
110+
111+
# Define the stderr option
112+
# @return [void]
113+
# @api private
114+
def define_stderr_option
115+
option_parser.on('--stderr="string to stderr"', 'A string to send to stderr') do |string|
116+
@stderr = string
117+
end
118+
end
119+
120+
# Define the exitstatus option
121+
# @return [void]
122+
# @api private
123+
def define_exitstatus_option
124+
option_parser.on('--exitstatus=1', 'The exitstatus to return') do |exitstatus|
125+
@exitstatus = Integer(exitstatus)
126+
end
127+
end
128+
129+
# Define the signal option
130+
# @return [void]
131+
# @api private
132+
def define_signal_option
133+
option_parser.on('--signal=9', 'The signal to raise') do |signal|
134+
@signal = Integer(signal)
135+
end
136+
end
137+
138+
# Define the help option
139+
# @return [void]
140+
# @api private
141+
def define_help_option
142+
option_parser.on_tail('-h', '--help', 'Show this message') do
143+
puts option_parser
144+
exit 0
145+
end
146+
end
147+
148+
# An error message constructed from the given errors array
149+
# @return [String]
150+
# @api private
151+
def error_message(errors)
152+
<<~MESSAGE
153+
#{errors.map { |e| "ERROR: #{e}" }.join("\n")}
154+
155+
Use --help for usage
156+
MESSAGE
157+
end
158+
159+
# Output an error message and useage to stderr and exit
160+
# @return [void]
161+
# @api private
162+
def report_errors(*errors)
163+
warn error_message(errors)
164+
exit 1
165+
end
166+
167+
# Parse non-option arguments (there are none for this parser)
168+
# @return [void]
169+
# @api private
170+
def parse_remaining_args(remaining_args)
171+
report_errors('Too many args') unless remaining_args.empty?
172+
end
173+
end
174+
175+
options = CommandLineParser.new.parse(*ARGV)
176+
177+
STDOUT.puts options.stdout if options.stdout
178+
STDERR.puts options.stderr if options.stderr
179+
Process.kill(options.signal, Process.pid) if options.signal
180+
exit(options.exitstatus) if options.exitstatus

git.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
2727
s.requirements = ['git 1.6.0.0, or greater']
2828

2929
s.add_runtime_dependency 'addressable', '~> 2.8'
30+
s.add_runtime_dependency 'process_executer', '~> 0.7'
3031
s.add_runtime_dependency 'rchardet', '~> 1.8'
3132

3233
s.add_development_dependency 'bump', '~> 0.10'

lib/git.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
require 'git/branch'
99
require 'git/branches'
1010
require 'git/command_line_result'
11+
require 'git/command_line'
1112
require 'git/config'
1213
require 'git/diff'
1314
require 'git/encoding_utils'
@@ -23,6 +24,7 @@
2324
require 'git/repository'
2425
require 'git/signaled_error'
2526
require 'git/status'
27+
require 'git/signaled_error'
2628
require 'git/stash'
2729
require 'git/stashes'
2830
require 'git/url'

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy