Skip to content

Commit

Permalink
Change how the git CLI subprocess is executed (#684)
Browse files Browse the repository at this point in the history
Signed-off-by: James Couball <jcouball@yahoo.com>
  • Loading branch information
jcouball committed Jan 15, 2024
1 parent f93e042 commit 7585c39
Show file tree
Hide file tree
Showing 21 changed files with 1,062 additions and 550 deletions.
38 changes: 21 additions & 17 deletions .github/workflows/continuous_integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,39 @@ name: CI

on:
push:
branches: [master]
branches: [master,v1]
pull_request:
branches: [master]
branches: [master,v1]
workflow_dispatch:

jobs:
continuous_integration_build:
continue-on-error: true
build:
name: Ruby ${{ matrix.ruby }} on ${{ matrix.operating-system }}
runs-on: ${{ matrix.operating-system }}
continue-on-error: ${{ matrix.experimental == 'Yes' }}
env: { JAVA_OPTS: -Djdk.io.File.enableADS=true }

strategy:
fail-fast: false
matrix:
ruby: [3.0, 3.1, 3.2, 3.3]
# Only the latest versions of JRuby and TruffleRuby are tested
ruby: ["3.0", "3.1", "3.2", "3.3", "truffleruby-23.1.1", "jruby-9.4.5.0"]
operating-system: [ubuntu-latest]
experimental: [No]
include:
- ruby: head
- # Building against head version of Ruby is considered experimental
ruby: head
operating-system: ubuntu-latest
- ruby: truffleruby-23.1.1
operating-system: ubuntu-latest
- ruby: 3.0
operating-system: windows-latest
- ruby: jruby-9.4.5.0
operating-system: windows-latest
experimental: Yes

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

runs-on: ${{ matrix.operating-system }}
- # Only test with minimal Ruby version on Windows
ruby: 3.0
operating-system: windows-latest

env:
JAVA_OPTS: -Djdk.io.File.enableADS=true
- # Since JRuby on Windows is known to not work, consider this experimental
ruby: jruby-9.4.5.0
operating-system: windows-latest
experimental: Yes

steps:
- name: Checkout Code
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ The changes coming in this major release include:
* Update the required Git command line version to at least 2.28
* Update how CLI commands are called to use the [process_executer](https://github.com/main-branch/process_executer)
gem which is built on top of [Kernel.spawn](https://ruby-doc.org/3.3.0/Kernel.html#method-i-spawn).
See [PR #617](https://github.com/ruby-git/ruby-git/pull/617) for more details
See [PR #684](https://github.com/ruby-git/ruby-git/pull/684) for more details
on the motivation for this implementation.

The tentative plan is to release `2.0.0` near the end of March 2024 depending on
Expand Down
180 changes: 180 additions & 0 deletions bin/command_line_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require 'optparse'

# A script used to test calling a command line program from Ruby
#
# This script is used to test the `Git::CommandLine` class. It is called
# from the `test_command_line` unit test.
#
# --stdout: string to output to stdout
# --stderr: string to output to stderr
# --exitstatus: exit status to return (default is zero)
# --signal: uncaught signal to raise (default is not to signal)
#
# Both --stdout and --stderr can be given.
#
# If --signal is given, --exitstatus is ignored.
#
# Examples:
# Output "Hello, world!" to stdout and exit with status 0
# $ bin/command_line_test --stdout="Hello, world!" --exitstatus=0
#
# Output "ERROR: timeout" to stderr and exit with status 1
# $ bin/command_line_test --stderr="ERROR: timeout" --exitstatus=1
#
# Output "Fatal: killed by parent" to stderr and signal 9
# $ bin/command_line_test --stderr="Fatal: killed by parent" --signal=9
#
# Output to both stdout and stderr return default exitstatus 0
# $ bin/command_line_test --stdout="Hello, world!" --stderr="ERROR: timeout"
#


class CommandLineParser
def initialize
@option_parser = OptionParser.new
define_options
end

attr_reader :stdout, :stderr, :exitstatus, :signal

# Parse the command line arguements returning the options
#
# @example
# parser = CommandLineParser.new
# options = parser.parse(['major'])
#
# @param args [Array<String>] the command line arguments
#
# @return [CreateGithubRelease::Options] the options
#
def parse(*args)
begin
option_parser.parse!(remaining_args = args.dup)
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
report_errors(e.message)
end
parse_remaining_args(remaining_args)
# puts options unless options.quiet
# report_errors(*options.errors) unless options.valid?
self
end

private

# @!attribute [rw] option_parser
#
# The option parser
#
# @return [OptionParser] the option parser
#
# @api private
#
attr_reader :option_parser

def define_options
option_parser.banner = "Usage:\n#{command_template}"
option_parser.separator ''
option_parser.separator "Both --stdout and --stderr can be given."
option_parser.separator 'If --signal is given, --exitstatus is ignored.'
option_parser.separator 'If nothing is given, the script will exit with exitstatus 0.'
option_parser.separator ''
option_parser.separator 'Options:'
%i[
define_help_option define_stdout_option define_stderr_option
define_exitstatus_option define_signal_option
].each { |m| send(m) }
end

# The command line template as a string
# @return [String]
# @api private
def command_template
<<~COMMAND
#{File.basename($PROGRAM_NAME)} \
--help | \
[--stdout="string to stdout"] [--stderr="string to stderr"] [--exitstatus=1] [--signal=9]
COMMAND
end

# Define the stdout option
# @return [void]
# @api private
def define_stdout_option
option_parser.on('--stdout="string to stdout"', 'A string to send to stdout') do |string|
@stdout = string
end
end

# Define the stderr option
# @return [void]
# @api private
def define_stderr_option
option_parser.on('--stderr="string to stderr"', 'A string to send to stderr') do |string|
@stderr = string
end
end

# Define the exitstatus option
# @return [void]
# @api private
def define_exitstatus_option
option_parser.on('--exitstatus=1', 'The exitstatus to return') do |exitstatus|
@exitstatus = Integer(exitstatus)
end
end

# Define the signal option
# @return [void]
# @api private
def define_signal_option
option_parser.on('--signal=9', 'The signal to raise') do |signal|
@signal = Integer(signal)
end
end

# Define the help option
# @return [void]
# @api private
def define_help_option
option_parser.on_tail('-h', '--help', 'Show this message') do
puts option_parser
exit 0
end
end

# An error message constructed from the given errors array
# @return [String]
# @api private
def error_message(errors)
<<~MESSAGE
#{errors.map { |e| "ERROR: #{e}" }.join("\n")}
Use --help for usage
MESSAGE
end

# Output an error message and useage to stderr and exit
# @return [void]
# @api private
def report_errors(*errors)
warn error_message(errors)
exit 1
end

# Parse non-option arguments (there are none for this parser)
# @return [void]
# @api private
def parse_remaining_args(remaining_args)
report_errors('Too many args') unless remaining_args.empty?
end
end

options = CommandLineParser.new.parse(*ARGV)

STDOUT.puts options.stdout if options.stdout
STDERR.puts options.stderr if options.stderr
Process.kill(options.signal, Process.pid) if options.signal
exit(options.exitstatus) if options.exitstatus
1 change: 1 addition & 0 deletions git.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Gem::Specification.new do |s|
s.requirements = ['git 2.28.0 or greater']

s.add_runtime_dependency 'addressable', '~> 2.8'
s.add_runtime_dependency 'process_executer', '~> 0.7'
s.add_runtime_dependency 'rchardet', '~> 1.8'

s.add_development_dependency 'minitar', '~> 0.9'
Expand Down
2 changes: 2 additions & 0 deletions lib/git.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require 'git/branch'
require 'git/branches'
require 'git/command_line_result'
require 'git/command_line'
require 'git/config'
require 'git/diff'
require 'git/encoding_utils'
Expand All @@ -23,6 +24,7 @@
require 'git/repository'
require 'git/signaled_error'
require 'git/status'
require 'git/signaled_error'
require 'git/stash'
require 'git/stashes'
require 'git/url'
Expand Down

0 comments on commit 7585c39

Please sign in to comment.