github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libgit/diff_file.go (about) 1 // Copyright 2019 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package libgit 6 7 import ( 8 "context" 9 "io" 10 "strings" 11 "time" 12 13 "github.com/pkg/errors" 14 billy "gopkg.in/src-d/go-billy.v4" 15 "gopkg.in/src-d/go-git.v4/plumbing/object" 16 ) 17 18 const ( 19 diffFileDefaultMaxBufSize = 4 * 1024 * 1024 // 4 MB 20 ) 21 22 type diffFile struct { 23 name string 24 r *strings.Reader 25 maxBufSize int64 26 mtime time.Time 27 } 28 29 var _ billy.File = (*diffFile)(nil) 30 31 func newDiffFile( 32 ctx context.Context, from, to *object.Commit, header, name string) ( 33 *diffFile, error) { 34 s := header 35 patch, err := from.PatchContext(ctx, to) 36 if err != nil { 37 return nil, err 38 } 39 s += patch.String() 40 41 r := strings.NewReader(s) 42 return &diffFile{ 43 name: name, 44 r: r, 45 maxBufSize: diffFileDefaultMaxBufSize, 46 mtime: to.Author.When, 47 }, nil 48 } 49 50 func (df *diffFile) Len() int { 51 return df.r.Len() 52 } 53 54 func (df *diffFile) Name() string { 55 return df.name 56 } 57 58 func (df *diffFile) Write(_ []byte) (n int, err error) { 59 return 0, errors.New("diff files can't be written") 60 } 61 62 func (df *diffFile) Read(p []byte) (n int, err error) { 63 return df.r.Read(p) 64 } 65 66 func (df *diffFile) ReadAt(p []byte, off int64) (n int, err error) { 67 n, err = df.r.ReadAt(p, off) 68 if err == io.EOF { 69 if n == 0 { 70 // The billy interface only likes EOFs when no data was read. 71 return 0, err 72 } 73 } else if err != nil { 74 return 0, err 75 } 76 return n, nil 77 } 78 79 func (df *diffFile) Seek(offset int64, whence int) (int64, error) { 80 return df.r.Seek(offset, whence) 81 } 82 83 func (df *diffFile) Close() error { 84 return nil 85 } 86 87 func (df *diffFile) Lock() error { 88 return errors.New("diff files can't be locked") 89 } 90 91 func (df *diffFile) Unlock() error { 92 return errors.New("diff files can't be unlocked") 93 } 94 95 func (df *diffFile) Truncate(size int64) error { 96 return errors.New("diff files can't be truncated") 97 } 98 99 func (df *diffFile) GetInfo() *diffFileInfo { 100 return &diffFileInfo{ 101 name: df.Name(), 102 size: int64(df.Len()), 103 mtime: df.mtime, 104 } 105 } 106 107 func newCommitFile( 108 ctx context.Context, commit *object.Commit) (*diffFile, error) { 109 header := commit.String() 110 name := AutogitCommitPrefix + commit.Hash.String() 111 // We can't get the patch for the initial commit, go-git doesn't 112 // seem to support it yet. 113 parent := commit 114 if commit.NumParents() > 0 { 115 var err error 116 parent, err = commit.Parent(0) 117 if err != nil { 118 return nil, err 119 } 120 } 121 return newDiffFile(ctx, parent, commit, header, name) 122 }