Class: Git::CommandLine::Streaming

Inherits:
Base
  • Object
show all
Defined in:
lib/git/command_line/streaming.rb

Overview

Executes a git command in streaming mode without buffering stdout in memory

Streaming is the non-buffering strategy: it calls ProcessExecuter.run and streams stdout directly to the caller-supplied out: IO object. Stderr is always captured internally in a StringIO for error diagnostics and is available as result.stderr.

Use this class (via Lib#command_streaming) for commands such as cat-file -p <blob> whose stdout may be too large to buffer in memory.

Capturing is the complementary strategy for the common case where buffering stdout is acceptable.

Examples:

Stream a blob to a file

streaming = Git::CommandLine::Streaming.new(
  {}, '/usr/bin/git', %w[--git-dir /repo/.git], Logger.new($stdout)
)
File.open('/tmp/blob', 'wb') do |f|
  streaming.run('cat-file', 'blob', sha, out: f)
end

See Also:

Constant Summary collapse

RUN_OPTION_DEFAULTS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Default options accepted by #run

{
  in: nil,
  out: nil,
  err: nil,
  chdir: nil,
  timeout: nil,
  raise_on_failure: true,
  env: {}
}.freeze

Instance Attribute Summary

Attributes inherited from Base

#binary_path, #env, #global_opts, #logger

Instance Method Summary collapse

Methods inherited from Base

#initialize

Constructor Details

This class inherits a constructor from Git::CommandLine::Base

Instance Method Details

#run(**options_hash) ⇒ Git::CommandLineResult

Execute a git command in streaming mode and return the result

Unlike Capturing#run, this method does not buffer stdout in memory. Stdout is written only to the IO object provided via the out: option. Stderr is captured internally via a StringIO for error diagnostics.

Use this entry point for commands that stream large content (e.g. blobs) where capturing stdout in memory would be unacceptable.

Examples:

Stream a blob to a file

file = File.open('/tmp/blob', 'wb')
streaming.run('cat-file', 'blob', sha, out: file)

Parameters:

  • options_hash (Hash)

    the options to pass to the command

Options Hash (**options_hash):

  • :in (IO, nil)

    the IO object to use as stdin for the command, or nil to inherit the parent process stdin. Must be a real IO object with a file descriptor (not StringIO).

  • :out (#write, nil)

    the IO/object to stream stdout into. Stdout is NOT buffered in the returned result; this is the only way to read it.

  • :err (#write, nil)

    an optional additional destination to receive stderr output in real time (e.g. $stderr or a File). Stderr is always captured internally in a StringIO for error diagnostics. When err: is provided, writes are teed to both the internal buffer and this destination. result.stderr always reflects what was captured in the internal buffer, regardless of whether err: is supplied.

  • :chdir (String, nil)

    the directory to run the command in

  • :timeout (Numeric, nil)

    the maximum seconds to wait for the command to complete. Zero means no timeout. A timeout kills the process via SIGKILL and raises TimeoutError.

  • :raise_on_failure (Boolean) — default: true

    whether to raise FailedError on non-zero exit status. TimeoutError and SignaledError are always raised regardless.

  • :env (Hash) — default: {}

    additional environment variable overrides for this command. String keys map to String values (to set) or nil (to unset).

Returns:

  • (Git::CommandLineResult)

    the result of the command

    result.stdout will always be '' (empty) — stdout was streamed to out:. result.stderr contains any stderr output captured for diagnostics.

Raises:

  • (ArgumentError)

    if args contains an array or an unknown option is passed

  • (Git::SignaledError)

    if the command was terminated by an uncaught signal

  • (Git::FailedError)

    if the command returned a non-zero exit status

  • (Git::ProcessIOError)

    if an exception was raised while collecting subprocess output

  • (Git::TimeoutError)

    if the command times out



109
110
111
112
113
114
115
116
117
118
119
# File 'lib/git/command_line/streaming.rb', line 109

def run(*, **options_hash)
  options = merge_and_validate_options(RUN_OPTION_DEFAULTS, options_hash)

  internal_err = StringIO.new
  # Tee stderr to the caller-provided destination (if any) AND the internal
  # StringIO.  This ensures result.stderr is always available even when err:
  # is a non-StringIO IO object.
  err_dest = options[:err] ? build_stderr_tee(internal_err, options[:err]) : internal_err
  result = execute(*, err_io: err_dest, **options)
  process_result(result, internal_err, options)
end