github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/git/repo_index.go (about) 1 // Copyright 2023 The GitBundle Inc. All rights reserved. 2 // Copyright 2017 The Gitea Authors. All rights reserved. 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file. 5 6 package git 7 8 import ( 9 "bytes" 10 "context" 11 "os" 12 "path/filepath" 13 "strings" 14 15 "github.com/gitbundle/modules/log" 16 "github.com/gitbundle/modules/util" 17 ) 18 19 // ReadTreeToIndex reads a treeish to the index 20 func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string) error { 21 if len(treeish) != 40 { 22 res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify", treeish).RunStdString(&RunOpts{Dir: repo.Path}) 23 if err != nil { 24 return err 25 } 26 if len(res) > 0 { 27 treeish = res[:len(res)-1] 28 } 29 } 30 id, err := NewIDFromString(treeish) 31 if err != nil { 32 return err 33 } 34 return repo.readTreeToIndex(id, indexFilename...) 35 } 36 37 func (repo *Repository) readTreeToIndex(id SHA1, indexFilename ...string) error { 38 var env []string 39 if len(indexFilename) > 0 { 40 env = append(os.Environ(), "GIT_INDEX_FILE="+indexFilename[0]) 41 } 42 _, _, err := NewCommand(repo.Ctx, "read-tree", id.String()).RunStdString(&RunOpts{Dir: repo.Path, Env: env}) 43 if err != nil { 44 return err 45 } 46 return nil 47 } 48 49 // ReadTreeToTemporaryIndex reads a treeish to a temporary index file 50 func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (filename, tmpDir string, cancel context.CancelFunc, err error) { 51 tmpDir, err = os.MkdirTemp("", "index") 52 if err != nil { 53 return 54 } 55 56 filename = filepath.Join(tmpDir, ".tmp-index") 57 cancel = func() { 58 err := util.RemoveAll(tmpDir) 59 if err != nil { 60 log.Error("failed to remove tmp index file: %v", err) 61 } 62 } 63 err = repo.ReadTreeToIndex(treeish, filename) 64 if err != nil { 65 defer cancel() 66 return "", "", func() {}, err 67 } 68 return 69 } 70 71 // EmptyIndex empties the index 72 func (repo *Repository) EmptyIndex() error { 73 _, _, err := NewCommand(repo.Ctx, "read-tree", "--empty").RunStdString(&RunOpts{Dir: repo.Path}) 74 return err 75 } 76 77 // LsFiles checks if the given filenames are in the index 78 func (repo *Repository) LsFiles(filenames ...string) ([]string, error) { 79 cmd := NewCommand(repo.Ctx, "ls-files", "-z", "--") 80 for _, arg := range filenames { 81 if arg != "" { 82 cmd.AddArguments(arg) 83 } 84 } 85 res, _, err := cmd.RunStdBytes(&RunOpts{Dir: repo.Path}) 86 if err != nil { 87 return nil, err 88 } 89 filelist := make([]string, 0, len(filenames)) 90 for _, line := range bytes.Split(res, []byte{'\000'}) { 91 filelist = append(filelist, string(line)) 92 } 93 94 return filelist, err 95 } 96 97 // RemoveFilesFromIndex removes given filenames from the index - it does not check whether they are present. 98 func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error { 99 cmd := NewCommand(repo.Ctx, "update-index", "--remove", "-z", "--index-info") 100 stdout := new(bytes.Buffer) 101 stderr := new(bytes.Buffer) 102 buffer := new(bytes.Buffer) 103 for _, file := range filenames { 104 if file != "" { 105 buffer.WriteString("0 0000000000000000000000000000000000000000\t") 106 buffer.WriteString(file) 107 buffer.WriteByte('\000') 108 } 109 } 110 return cmd.Run(&RunOpts{ 111 Dir: repo.Path, 112 Stdin: bytes.NewReader(buffer.Bytes()), 113 Stdout: stdout, 114 Stderr: stderr, 115 }) 116 } 117 118 // AddObjectToIndex adds the provided object hash to the index at the provided filename 119 func (repo *Repository) AddObjectToIndex(mode string, object SHA1, filename string) error { 120 cmd := NewCommand(repo.Ctx, "update-index", "--add", "--replace", "--cacheinfo", mode, object.String(), filename) 121 _, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path}) 122 return err 123 } 124 125 // WriteTree writes the current index as a tree to the object db and returns its hash 126 func (repo *Repository) WriteTree() (*Tree, error) { 127 stdout, _, runErr := NewCommand(repo.Ctx, "write-tree").RunStdString(&RunOpts{Dir: repo.Path}) 128 if runErr != nil { 129 return nil, runErr 130 } 131 id, err := NewIDFromString(strings.TrimSpace(stdout)) 132 if err != nil { 133 return nil, err 134 } 135 return NewTree(repo, id), nil 136 }