@@ -88,8 +88,25 @@ func (err ErrRepoFileDoesNotExist) Unwrap() error {
8888 return util .ErrNotExist
8989}
9090
91+ type LazyReader interface {
92+ io.Closer
93+ OpenLazyReader () error
94+ }
95+
9196// ChangeRepoFiles adds, updates or removes multiple files in the given repository
92- func ChangeRepoFiles (ctx context.Context , repo * repo_model.Repository , doer * user_model.User , opts * ChangeRepoFilesOptions ) (* structs.FilesResponse , error ) {
97+ func ChangeRepoFiles (ctx context.Context , repo * repo_model.Repository , doer * user_model.User , opts * ChangeRepoFilesOptions ) (_ * structs.FilesResponse , errRet error ) {
98+ var addedLfsPointers []lfs.Pointer
99+ defer func () {
100+ if errRet != nil {
101+ for _ , lfsPointer := range addedLfsPointers {
102+ _ , err := git_model .RemoveLFSMetaObjectByOid (ctx , repo .ID , lfsPointer .Oid )
103+ if err != nil {
104+ log .Error ("ChangeRepoFiles: RemoveLFSMetaObjectByOid failed: %v" , err )
105+ }
106+ }
107+ }
108+ }()
109+
93110 err := repo .MustNotBeArchived ()
94111 if err != nil {
95112 return nil , err
@@ -242,9 +259,13 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
242259 for _ , file := range opts .Files {
243260 switch file .Operation {
244261 case "create" , "update" , "rename" :
245- if err = CreateUpdateRenameFile (ctx , t , file , lfsContentStore , repo .ID , hasOldBranch ); err != nil {
262+ addedLfsPointer , err := CreateUpdateRenameFile (ctx , t , file , lfsContentStore , repo .ID )
263+ if err != nil {
246264 return nil , err
247265 }
266+ if addedLfsPointer != nil {
267+ addedLfsPointers = append (addedLfsPointers , * addedLfsPointer )
268+ }
248269 case "delete" :
249270 if err = t .RemoveFilesFromIndex (ctx , file .TreePath ); err != nil {
250271 return nil , err
@@ -454,18 +475,23 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep
454475 return nil
455476}
456477
457- func CreateUpdateRenameFile (ctx context.Context , t * TemporaryUploadRepository , file * ChangeRepoFile , contentStore * lfs.ContentStore , repoID int64 , hasOldBranch bool ) error {
478+ func CreateUpdateRenameFile (ctx context.Context , t * TemporaryUploadRepository , file * ChangeRepoFile , contentStore * lfs.ContentStore , repoID int64 ) (addedLfsPointer * lfs.Pointer , _ error ) {
479+ if rd , ok := file .ContentReader .(LazyReader ); ok {
480+ if err := rd .OpenLazyReader (); err != nil {
481+ return nil , fmt .Errorf ("OpenLazyReader: %w" , err )
482+ }
483+ defer rd .Close ()
484+ }
485+
458486 // Get the two paths (might be the same if not moving) from the index if they exist
459487 filesInIndex , err := t .LsFiles (ctx , file .TreePath , file .FromTreePath )
460488 if err != nil {
461- return fmt .Errorf ("UpdateRepoFile : %w" , err )
489+ return nil , fmt .Errorf ("LsFiles : %w" , err )
462490 }
463491 // If is a new file (not updating) then the given path shouldn't exist
464492 if file .Operation == "create" {
465493 if slices .Contains (filesInIndex , file .TreePath ) {
466- return ErrRepoFileAlreadyExists {
467- Path : file .TreePath ,
468- }
494+ return nil , ErrRepoFileAlreadyExists {Path : file .TreePath }
469495 }
470496 }
471497
@@ -474,7 +500,7 @@ func CreateUpdateRenameFile(ctx context.Context, t *TemporaryUploadRepository, f
474500 for _ , indexFile := range filesInIndex {
475501 if indexFile == file .Options .fromTreePath {
476502 if err = t .RemoveFilesFromIndex (ctx , file .FromTreePath ); err != nil {
477- return err
503+ return nil , err
478504 }
479505 }
480506 }
@@ -487,40 +513,41 @@ func CreateUpdateRenameFile(ctx context.Context, t *TemporaryUploadRepository, f
487513 case "rename" :
488514 writeObjectRet , err = writeRepoObjectForRename (ctx , t , file )
489515 default :
490- return util .NewInvalidArgumentErrorf ("unknown file modification operation: '%s'" , file .Operation )
516+ return nil , util .NewInvalidArgumentErrorf ("unknown file modification operation: '%s'" , file .Operation )
491517 }
492518 if err != nil {
493- return err
519+ return nil , err
494520 }
495521
496522 // Add the object to the index, the "file.Options.executable" is set in handleCheckErrors by the caller (legacy hacky approach)
497523 if err = t .AddObjectToIndex (ctx , util .Iif (file .Options .executable , "100755" , "100644" ), writeObjectRet .ObjectHash , file .Options .treePath ); err != nil {
498- return err
524+ return nil , err
499525 }
500526
501527 if writeObjectRet .LfsContent == nil {
502- return nil // No LFS pointer, so nothing to do
528+ return nil , nil // No LFS pointer, so nothing to do
503529 }
504530 defer writeObjectRet .LfsContent .Close ()
505531
506532 // Now we must store the content into an LFS object
507533 lfsMetaObject , err := git_model .NewLFSMetaObject (ctx , repoID , writeObjectRet .LfsPointer )
508534 if err != nil {
509- return err
510- }
511- if exist , err := contentStore .Exists (lfsMetaObject .Pointer ); err != nil {
512- return err
513- } else if exist {
514- return nil
535+ return nil , err
515536 }
516-
517- err = contentStore .Put (lfsMetaObject .Pointer , writeObjectRet .LfsContent )
537+ exist , err := contentStore .Exists (lfsMetaObject .Pointer )
518538 if err != nil {
519- if _ , errRemove := git_model .RemoveLFSMetaObjectByOid (ctx , repoID , lfsMetaObject .Oid ); errRemove != nil {
520- return fmt .Errorf ("unable to remove failed inserted LFS object %s: %v (Prev Error: %w)" , lfsMetaObject .Oid , errRemove , err )
539+ return nil , err
540+ }
541+ if ! exist {
542+ err = contentStore .Put (lfsMetaObject .Pointer , writeObjectRet .LfsContent )
543+ if err != nil {
544+ if _ , errRemove := git_model .RemoveLFSMetaObjectByOid (ctx , repoID , lfsMetaObject .Oid ); errRemove != nil {
545+ return nil , fmt .Errorf ("unable to remove failed inserted LFS object %s: %v (Prev Error: %w)" , lfsMetaObject .Oid , errRemove , err )
546+ }
547+ return nil , err
521548 }
522549 }
523- return err
550+ return & lfsMetaObject . Pointer , nil
524551}
525552
526553func checkIsLfsFileInGitAttributes (ctx context.Context , t * TemporaryUploadRepository , paths []string ) (ret []bool , err error ) {
0 commit comments