2019-05-11 16:29:17 +01:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2019-05-11 16:29:17 +01:00
package git
import (
"bytes"
2021-09-09 21:13:36 +01:00
"context"
"os"
2021-11-17 20:37:00 +00:00
"path/filepath"
2019-05-11 16:29:17 +01:00
"strings"
2021-09-09 21:13:36 +01:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
2019-05-11 16:29:17 +01:00
)
// ReadTreeToIndex reads a treeish to the index
2021-09-09 21:13:36 +01:00
func ( repo * Repository ) ReadTreeToIndex ( treeish string , indexFilename ... string ) error {
2023-12-13 21:02:00 +00:00
objectFormat , err := repo . GetObjectFormat ( )
if err != nil {
return err
}
if len ( treeish ) != objectFormat . FullLength ( ) {
2022-10-23 22:44:45 +08:00
res , _ , err := NewCommand ( repo . Ctx , "rev-parse" , "--verify" ) . AddDynamicArguments ( treeish ) . RunStdString ( & RunOpts { Dir : repo . Path } )
2019-05-11 16:29:17 +01:00
if err != nil {
return err
}
if len ( res ) > 0 {
treeish = res [ : len ( res ) - 1 ]
}
}
2023-12-19 15:20:47 +08:00
id , err := NewIDFromString ( treeish )
2019-05-11 16:29:17 +01:00
if err != nil {
return err
}
2021-09-09 21:13:36 +01:00
return repo . readTreeToIndex ( id , indexFilename ... )
2019-05-11 16:29:17 +01:00
}
2023-12-13 21:02:00 +00:00
func ( repo * Repository ) readTreeToIndex ( id ObjectID , indexFilename ... string ) error {
2021-09-09 21:13:36 +01:00
var env [ ] string
if len ( indexFilename ) > 0 {
env = append ( os . Environ ( ) , "GIT_INDEX_FILE=" + indexFilename [ 0 ] )
}
2022-10-23 22:44:45 +08:00
_ , _ , err := NewCommand ( repo . Ctx , "read-tree" ) . AddDynamicArguments ( id . String ( ) ) . RunStdString ( & RunOpts { Dir : repo . Path , Env : env } )
2019-05-11 16:29:17 +01:00
if err != nil {
return err
}
return nil
}
2021-09-09 21:13:36 +01:00
// ReadTreeToTemporaryIndex reads a treeish to a temporary index file
2024-10-29 09:27:03 -07:00
func ( repo * Repository ) ReadTreeToTemporaryIndex ( treeish string ) ( tmpIndexFilename , tmpDir string , cancel context . CancelFunc , err error ) {
defer func ( ) {
// if error happens and there is a cancel function, do clean up
if err != nil && cancel != nil {
cancel ( )
cancel = nil
}
} ( )
removeDirFn := func ( dir string ) func ( ) { // it can't use the return value "tmpDir" directly because it is empty when error occurs
return func ( ) {
if err := util . RemoveAll ( dir ) ; err != nil {
log . Error ( "failed to remove tmp index dir: %v" , err )
}
}
}
2021-11-17 20:37:00 +00:00
tmpDir , err = os . MkdirTemp ( "" , "index" )
2021-09-09 21:13:36 +01:00
if err != nil {
2024-10-29 09:27:03 -07:00
return "" , "" , nil , err
2021-09-09 21:13:36 +01:00
}
2021-11-17 20:37:00 +00:00
2024-10-29 09:27:03 -07:00
tmpIndexFilename = filepath . Join ( tmpDir , ".tmp-index" )
cancel = removeDirFn ( tmpDir )
err = repo . ReadTreeToIndex ( treeish , tmpIndexFilename )
2021-09-09 21:13:36 +01:00
if err != nil {
2024-10-29 09:27:03 -07:00
return "" , "" , cancel , err
2021-09-09 21:13:36 +01:00
}
2024-10-29 09:27:03 -07:00
return tmpIndexFilename , tmpDir , cancel , err
2021-09-09 21:13:36 +01:00
}
2019-05-11 16:29:17 +01:00
// EmptyIndex empties the index
func ( repo * Repository ) EmptyIndex ( ) error {
2022-04-01 10:55:30 +08:00
_ , _ , err := NewCommand ( repo . Ctx , "read-tree" , "--empty" ) . RunStdString ( & RunOpts { Dir : repo . Path } )
2019-05-11 16:29:17 +01:00
return err
}
// LsFiles checks if the given filenames are in the index
func ( repo * Repository ) LsFiles ( filenames ... string ) ( [ ] string , error ) {
2022-10-23 22:44:45 +08:00
cmd := NewCommand ( repo . Ctx , "ls-files" , "-z" ) . AddDashesAndList ( filenames ... )
2022-04-01 10:55:30 +08:00
res , _ , err := cmd . RunStdBytes ( & RunOpts { Dir : repo . Path } )
2019-05-11 16:29:17 +01:00
if err != nil {
return nil , err
}
filelist := make ( [ ] string , 0 , len ( filenames ) )
for _ , line := range bytes . Split ( res , [ ] byte { '\000' } ) {
filelist = append ( filelist , string ( line ) )
}
return filelist , err
}
// RemoveFilesFromIndex removes given filenames from the index - it does not check whether they are present.
func ( repo * Repository ) RemoveFilesFromIndex ( filenames ... string ) error {
2024-03-12 12:21:27 +08:00
objectFormat , err := repo . GetObjectFormat ( )
if err != nil {
return err
}
2022-02-06 20:01:47 +01:00
cmd := NewCommand ( repo . Ctx , "update-index" , "--remove" , "-z" , "--index-info" )
2019-05-11 16:29:17 +01:00
stdout := new ( bytes . Buffer )
stderr := new ( bytes . Buffer )
buffer := new ( bytes . Buffer )
for _ , file := range filenames {
if file != "" {
2024-07-04 20:57:11 +02:00
// using format: mode SP type SP sha1 TAB path
buffer . WriteString ( "0 blob " + objectFormat . EmptyObjectID ( ) . String ( ) + "\t" + file + "\000" )
2019-05-11 16:29:17 +01:00
}
}
2022-04-01 10:55:30 +08:00
return cmd . Run ( & RunOpts {
Dir : repo . Path ,
Stdin : bytes . NewReader ( buffer . Bytes ( ) ) ,
Stdout : stdout ,
Stderr : stderr ,
2022-02-11 13:47:22 +01:00
} )
2019-05-11 16:29:17 +01:00
}
2024-07-04 20:57:11 +02:00
type IndexObjectInfo struct {
Mode string
Object ObjectID
Filename string
}
// AddObjectsToIndex adds the provided object hashes to the index at the provided filenames
func ( repo * Repository ) AddObjectsToIndex ( objects ... IndexObjectInfo ) error {
cmd := NewCommand ( repo . Ctx , "update-index" , "--add" , "--replace" , "-z" , "--index-info" )
stdout := new ( bytes . Buffer )
stderr := new ( bytes . Buffer )
buffer := new ( bytes . Buffer )
for _ , object := range objects {
// using format: mode SP type SP sha1 TAB path
buffer . WriteString ( object . Mode + " blob " + object . Object . String ( ) + "\t" + object . Filename + "\000" )
}
return cmd . Run ( & RunOpts {
Dir : repo . Path ,
Stdin : bytes . NewReader ( buffer . Bytes ( ) ) ,
Stdout : stdout ,
Stderr : stderr ,
} )
}
2019-05-11 16:29:17 +01:00
// AddObjectToIndex adds the provided object hash to the index at the provided filename
2023-12-13 21:02:00 +00:00
func ( repo * Repository ) AddObjectToIndex ( mode string , object ObjectID , filename string ) error {
2024-07-04 20:57:11 +02:00
return repo . AddObjectsToIndex ( IndexObjectInfo { Mode : mode , Object : object , Filename : filename } )
2019-05-11 16:29:17 +01:00
}
// WriteTree writes the current index as a tree to the object db and returns its hash
func ( repo * Repository ) WriteTree ( ) ( * Tree , error ) {
2022-04-01 10:55:30 +08:00
stdout , _ , runErr := NewCommand ( repo . Ctx , "write-tree" ) . RunStdString ( & RunOpts { Dir : repo . Path } )
if runErr != nil {
return nil , runErr
2019-05-11 16:29:17 +01:00
}
2023-12-19 15:20:47 +08:00
id , err := NewIDFromString ( strings . TrimSpace ( stdout ) )
2019-05-11 16:29:17 +01:00
if err != nil {
return nil , err
}
return NewTree ( repo , id ) , nil
}