Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change how the git CLI subprocess is executed #681

Closed
wants to merge 1 commit into from

Conversation

jcouball
Copy link
Member

@jcouball jcouball commented Jan 3, 2024

Your checklist for this pull request

馃毃Please review the guidelines for contributing to this repository.

  • Ensure all commits include DCO sign-off.
  • Ensure that your contributions pass unit testing.
  • Ensure that your contributions contain documentation if applicable.

TODO

Waiting for the following issues to be addressed:

Description

Fixes #355, Fixes #363, Fixes #441, Fixes #495, Fixes #516, Fixes #574

In the current implementation, all calls to git are done using backticks which has several disadvantages:

  • STDOUT and STDERR are commingled (via redirection added to the command line using 2>&1) which can cause processing errors.
  • Changes to the environment's subprocess have to be global which could impact users of this gem
  • Arguments passed on the command line go through the system shell making it difficult to escape args correctly for all platforms AND leaving this gem open to security vulnerabilities

Requirements

Implement a cross platform (Windows, Linux, and Mac) and cross Ruby (MRI, JRuby, and TruffleRuby) solution that meets the following requirements:

  1. Independently capture STDOUT and STDERR
  2. Be able to both capture STDOUT and STDIN as well as stream them to the terminal and a file at the same time if desired (e.g. for debugging)
  3. Provide a isolated environment and current working directory for the git command subprocess that does not change these global variables in the process that this gem is running in
  4. Pass command line args to the git command without being interpreted by the system shell
  5. Be able to implement a timeout on git subprocesses so they do not hang forever if input is asked for

Alternative Implementations Examined

# Option Pros Cons
1 Kernel.` (aka backtick) Very simple Does not implement any of the desired reqs
2 IO.popen Simple Does not implement desired reqs 1, 2, 5
3 Open3.popen3 Simple Does not implement desired reqs 2 and 5
4 Open3.capture3 Simple Does not implement desired reqs 2 and 5
5 Process.spawn Can be made to implement all reqs Very complex implementation
6 ProcessExecuter.spawn Much less complex than Process.spawn. Implements all reqs. Bespoke wrapper around Process.spawn. Less used in the field than other options.

Option 6 was chosen because it is the least complex implementation that implements all the requirements.

Changes Made in this PR

This PR re-implements Git::Lib#command. In order to get the desired results, some changes were needed to the signature of this method which caused some changes in code and tests.

The implementation of Git::Lib#command is handled by the new class Git::CommandLine. This class has a small interface: #initialize which accepts attribute values that do not change between git command invocations (env, binary_path, global_opts, and logger) and #run which takes the git command args, redirection, and flags for normalization, chomping, and merging stderr with stdout.

@jcouball jcouball force-pushed the refactor_subprocess branch 3 times, most recently from f54a167 to 477e2d3 Compare January 3, 2024 21:09
Signed-off-by: James Couball <jcouball@yahoo.com>
@jcouball jcouball closed this Jan 14, 2024
@jcouball jcouball deleted the refactor_subprocess branch March 20, 2024 00:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant