diff options
| author | 2026-03-26 09:17:14 +0000 | |
|---|---|---|
| committer | 2026-03-26 09:18:30 +0000 | |
| commit | 3e884f5f3d42cbc4874a04da31dde10314b0cfad (patch) | |
| tree | f5e1e325fd1a2a0801791c054010213214475d80 /packfile/ingest/api.go | |
| parent | network/receivepack: Rename from receivepack (diff) | |
| signature | No signature | |
format: Move commitgraph and packfile here
Diffstat (limited to 'packfile/ingest/api.go')
| -rw-r--r-- | packfile/ingest/api.go | 195 |
1 files changed, 0 insertions, 195 deletions
diff --git a/packfile/ingest/api.go b/packfile/ingest/api.go deleted file mode 100644 index ce366a4f..00000000 --- a/packfile/ingest/api.go +++ /dev/null @@ -1,195 +0,0 @@ -package ingest - -import ( - "bufio" - "bytes" - "errors" - "io" - "os" - - objectid "codeberg.org/lindenii/furgit/object/id" - objectstorer "codeberg.org/lindenii/furgit/object/storer" -) - -// Options controls one pack ingest operation. -type Options struct { - // FixThin appends missing local bases for thin packs. - FixThin bool - // WriteRev writes a .rev alongside the .pack and .idx. - WriteRev bool - // Base supplies existing objects for thin-pack fixup. - Base objectstorer.Store - // Progress receives human-readable progress messages. - // - // When nil, no progress output is emitted. - Progress io.Writer - // ProgressFlush flushes transport output after progress writes. - // - // When nil, no explicit flush is attempted. - ProgressFlush func() error - // RequireTrailingEOF requires the source to hit EOF after the pack trailer. - // - // This is suitable for exact pack-file readers, but should be disabled for - // full-duplex transport streams like receive-pack where the peer keeps the - // connection open to read the server response. - RequireTrailingEOF bool -} - -// Result describes one successful ingest transaction. -type Result struct { - // PackName is the destination-relative filename of the written .pack. - PackName string - // IdxName is the destination-relative filename of the written .idx. - IdxName string - // RevName is the destination-relative filename of the written .rev. - // - // RevName is empty when writeRev is false. - RevName string - // PackHash is the final pack hash (same hash embedded in .idx/.rev trailers). - PackHash objectid.ObjectID - // ObjectCount is the final object count in the resulting pack. - // - // If thin fixup appends objects, this includes appended base objects. - ObjectCount uint32 - // ThinFixed reports whether thin fixup appended local bases. - ThinFixed bool -} - -// HeaderInfo describes the parsed PACK header. -type HeaderInfo struct { - Version uint32 - ObjectCount uint32 -} - -// DiscardResult describes one successful Discard call. -type DiscardResult struct { - PackHash objectid.ObjectID - ObjectCount uint32 -} - -// Pending is one started ingest operation awaiting Continue or Discard. -// -// Exactly one of Continue or Discard may be called. -type Pending struct { - reader *bufio.Reader - algo objectid.Algorithm - opts Options - header HeaderInfo - headerRaw [packHeaderSize]byte - - finalized bool -} - -// Ingest reads and validates one PACK header, returning one pending operation. -func Ingest( - src io.Reader, - algo objectid.Algorithm, - opts Options, -) (*Pending, error) { - if algo.Size() == 0 { - return nil, objectid.ErrInvalidAlgorithm - } - - reader := bufio.NewReader(src) - - header, headerRaw, err := readAndValidatePackHeader(reader) - if err != nil { - return nil, err - } - - return &Pending{ - reader: reader, - algo: algo, - opts: opts, - header: header, - headerRaw: headerRaw, - }, nil -} - -// Header returns parsed PACK header info. -func (pending *Pending) Header() HeaderInfo { - return pending.header -} - -// Continue ingests the pack stream into destination and writes pack artifacts. -// -// Continue is terminal. Further use of pending is undefined behavior. -// -// Artifacts are published under content-addressed final names derived from the -// resulting pack hash. If those final names already exist, Continue treats that -// as success and removes its temporary files. -func (pending *Pending) Continue(destination *os.Root) (Result, error) { - pending.finalized = true - - if pending.header.ObjectCount == 0 { - return Result{}, ErrZeroObjectContinue - } - - state, err := newIngestState( - pending.reader, - destination, - pending.algo, - pending.opts, - pending.header, - pending.headerRaw, - ) - if err != nil { - return Result{}, err - } - - return ingest(state) -} - -// Discard consumes and verifies one zero-object pack stream without writing -// files. -// -// Discard is terminal. Further use of pending is undefined behavior. -func (pending *Pending) Discard() (DiscardResult, error) { - pending.finalized = true - - if pending.header.ObjectCount != 0 { - return DiscardResult{}, ErrNonZeroDiscard - } - - hashImpl, err := pending.algo.New() - if err != nil { - return DiscardResult{}, err - } - - _, _ = hashImpl.Write(pending.headerRaw[:]) - - trailer := make([]byte, pending.algo.Size()) - - _, err = io.ReadFull(pending.reader, trailer) - if err != nil { - return DiscardResult{}, &PackTrailerMismatchError{} - } - - computed := hashImpl.Sum(nil) - if !bytes.Equal(computed, trailer) { - return DiscardResult{}, &PackTrailerMismatchError{} - } - - if pending.opts.RequireTrailingEOF { - var probe [1]byte - - n, err := pending.reader.Read(probe[:]) - if n > 0 || err == nil { - return DiscardResult{}, errors.New("packfile/ingest: pack has trailing garbage") - } - - if err != io.EOF { - return DiscardResult{}, err - } - } - - packHash, err := objectid.FromBytes(pending.algo, trailer) - if err != nil { - return DiscardResult{}, err - } - - return DiscardResult{ - PackHash: packHash, - ObjectCount: 0, - }, nil -} |
