1// +build static,system_libgit2 2 3package commit 4 5import ( 6 "context" 7 "encoding/gob" 8 "errors" 9 "fmt" 10 "io" 11 12 git "github.com/libgit2/git2go/v31" 13 "gitlab.com/gitlab-org/gitaly/v14/internal/git2go" 14) 15 16// Run runs the commit subcommand. 17func Run(ctx context.Context, stdin io.Reader, stdout io.Writer) error { 18 var params git2go.CommitParams 19 if err := gob.NewDecoder(stdin).Decode(¶ms); err != nil { 20 return err 21 } 22 23 commitID, err := commit(ctx, params) 24 return gob.NewEncoder(stdout).Encode(git2go.Result{ 25 CommitID: commitID, 26 Error: git2go.SerializableError(err), 27 }) 28} 29 30func commit(ctx context.Context, params git2go.CommitParams) (string, error) { 31 repo, err := git.OpenRepository(params.Repository) 32 if err != nil { 33 return "", fmt.Errorf("open repository: %w", err) 34 } 35 36 index, err := git.NewIndex() 37 if err != nil { 38 return "", fmt.Errorf("new index: %w", err) 39 } 40 41 var parents []*git.Oid 42 if params.Parent != "" { 43 parentOID, err := git.NewOid(params.Parent) 44 if err != nil { 45 return "", fmt.Errorf("parse base commit oid: %w", err) 46 } 47 48 parents = []*git.Oid{parentOID} 49 50 baseCommit, err := repo.LookupCommit(parentOID) 51 if err != nil { 52 return "", fmt.Errorf("lookup commit: %w", err) 53 } 54 55 baseTree, err := baseCommit.Tree() 56 if err != nil { 57 return "", fmt.Errorf("lookup tree: %w", err) 58 } 59 60 if err := index.ReadTree(baseTree); err != nil { 61 return "", fmt.Errorf("read tree: %w", err) 62 } 63 } 64 65 for _, action := range params.Actions { 66 if err := apply(action, repo, index); err != nil { 67 if git.IsErrorClass(err, git.ErrClassIndex) { 68 err = git2go.IndexError(err.Error()) 69 } 70 71 return "", fmt.Errorf("apply action %T: %w", action, err) 72 } 73 } 74 75 treeOID, err := index.WriteTreeTo(repo) 76 if err != nil { 77 return "", fmt.Errorf("write tree: %w", err) 78 } 79 80 author := git.Signature(params.Author) 81 committer := git.Signature(params.Committer) 82 commitID, err := repo.CreateCommitFromIds("", &author, &committer, params.Message, treeOID, parents...) 83 if err != nil { 84 if git.IsErrorClass(err, git.ErrClassInvalid) { 85 return "", git2go.InvalidArgumentError(err.Error()) 86 } 87 88 return "", fmt.Errorf("create commit: %w", err) 89 } 90 91 return commitID.String(), nil 92} 93 94func apply(action git2go.Action, repo *git.Repository, index *git.Index) error { 95 switch action := action.(type) { 96 case git2go.ChangeFileMode: 97 return applyChangeFileMode(action, index) 98 case git2go.CreateDirectory: 99 return applyCreateDirectory(action, repo, index) 100 case git2go.CreateFile: 101 return applyCreateFile(action, index) 102 case git2go.DeleteFile: 103 return applyDeleteFile(action, index) 104 case git2go.MoveFile: 105 return applyMoveFile(action, index) 106 case git2go.UpdateFile: 107 return applyUpdateFile(action, index) 108 default: 109 return errors.New("unsupported action") 110 } 111} 112