app/services/backup_repository/pipe_io.rb
Rama develop · réplica de lectura del repositorio original.
class BackupRepository
# Wrapper around a non-rewindable IO (e.g. an Open3.popen stdout pipe) that
# satisfies the contract Gem::Package::TarReader expects from its source —
# `pos`, `read`, `eof?`, `getc`, `readpartial`. Without it, TarReader's
# constructor calls `io.pos` (which raises Errno::ESPIPE on a pipe) and the
# Entry#close routines call `io.seek` to skip over file bodies the consumer
# did not read.
#
# The wrapper exposes a virtual byte counter that advances on every read,
# and answers every `seek` with Errno::EINVAL — the documented escape
# hatch that triggers TarReader's read-and-discard fallback (see
# rubygems/package/tar_reader/entry.rb).
class PipeIo
def initialize(io)
@io = io
@pos = 0
end
attr_reader :pos
delegate :eof?, to: :@io
def read(length = nil, outbuf = nil)
data = outbuf ? @io.read(length, outbuf) : @io.read(length)
@pos += data.bytesize if data
data
end
def readpartial(maxlen, outbuf = +'')
@io.readpartial(maxlen, outbuf)
@pos += outbuf.bytesize
outbuf
end
def getc
char = @io.getc
@pos += char.bytesize if char
char
end
# Documented contract with TarReader: raising Errno::EINVAL signals
# "stream is not seekable" and triggers its read-fallback.
def seek(*)
raise Errno::EINVAL
end
def rewind
raise Errno::EINVAL
end
end
end