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 #684

Merged
merged 1 commit into from Jan 15, 2024
Merged

Conversation

jcouball
Copy link
Member

@jcouball jcouball commented Jan 14, 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

Issue #687 was opened to track that this gem does not work on JRuby for Windows when using JDK > 8. This PR will be merged without this issue being solved.

Waiting for the following issues to be addressed:

Description

Fixes the following issues:

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_subprocess2 branch 12 times, most recently from 7321c6f to 44a04c5 Compare January 15, 2024 16:57
Signed-off-by: James Couball <jcouball@yahoo.com>
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