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  }