Skip to content

Commit 0e34ecc

Browse files
committed
merge duplicate code
1 parent ecff26d commit 0e34ecc

File tree

13 files changed

+130
-251
lines changed

13 files changed

+130
-251
lines changed

models/git/lfs.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ type LFSMetaObject struct {
112112
ID int64 `xorm:"pk autoincr"`
113113
lfs.Pointer `xorm:"extends"`
114114
RepositoryID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
115-
Existing bool `xorm:"-"`
116115
CreatedUnix timeutil.TimeStamp `xorm:"created"`
117116
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
118117
}
@@ -146,7 +145,6 @@ func NewLFSMetaObject(ctx context.Context, repoID int64, p lfs.Pointer) (*LFSMet
146145
if err != nil {
147146
return nil, err
148147
} else if exist {
149-
m.Existing = true
150148
return m, committer.Commit()
151149
}
152150

modules/structs/repo_file.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ func (o *UpdateFileOptions) Branch() string {
6666
return o.FileOptions.BranchName
6767
}
6868

69+
// FIXME: ChangeFileOperation.SHA is NOT required for update or delete if last commit is provided in the options.
70+
6971
// ChangeFileOperation for creating, updating or deleting a file
7072
type ChangeFileOperation struct {
7173
// indicates what to do with the file

routers/api/v1/repo/file.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,9 @@ func ChangeFiles(ctx *context.APIContext) {
470470
ctx.APIError(http.StatusUnprocessableEntity, err)
471471
return
472472
}
473+
// FIXME: actually now we support more operations like "rename", "upload"
474+
// FIXME: ChangeFileOperation.SHA is NOT required for update or delete if last commit is provided in the options.
475+
// Need to fully fix them in API
473476
changeRepoFile := &files_service.ChangeRepoFile{
474477
Operation: file.Operation,
475478
TreePath: file.Path,

routers/web/repo/editor.go

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -389,24 +389,6 @@ func UploadFilePost(ctx *context.Context) {
389389
return
390390
}
391391

392-
if !ctx.Repo.Repository.IsEmpty && form.TreePath != "" {
393-
_, treePaths := getParentTreeFields(form.TreePath)
394-
for _, parentTreePath := range treePaths {
395-
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(parentTreePath)
396-
if git.IsErrNotExist(err) {
397-
break // Means there is no item with that name, so we're good
398-
} else if err != nil {
399-
ctx.ServerError("GetTreeEntryByPath", err)
400-
return
401-
}
402-
// User can only upload files to a directory, the directory name shouldn't be an existing file.
403-
if !entry.IsDir() {
404-
ctx.JSONError(ctx.Tr("repo.editor.directory_is_a_file", parentTreePath))
405-
return
406-
}
407-
}
408-
}
409-
410392
commitMessage := buildEditorCommitMessage(ctx.Locale.TrString("repo.editor.upload_files_to_dir", util.IfZero(form.TreePath, "/")), form.CommitSummary, form.CommitMessage)
411393

412394
gitCommitter, valid := WebGitOperationGetCommitChosenEmailIdentity(ctx, form.CommitEmail)
@@ -416,7 +398,7 @@ func UploadFilePost(ctx *context.Context) {
416398
}
417399

418400
err := files_service.UploadRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, &files_service.UploadRepoFileOptions{
419-
LastCommitID: ctx.Repo.CommitID,
401+
LastCommitID: form.LastCommit,
420402
OldBranch: oldBranchName,
421403
NewBranch: branchName,
422404
TreePath: form.TreePath,

routers/web/repo/editor_error.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ func editorHandleFileOperationErrorRender(ctx *context_service.Context, message,
3838
}
3939

4040
func editorHandleFileOperationError(ctx *context_service.Context, targetBranchName string, err error) {
41-
if git.IsErrNotExist(err) {
42-
ctx.JSONError(ctx.Tr("repo.editor.file_modifying_no_longer_exists", ctx.Repo.TreePath))
41+
if errAs, ok := errorAs[git.ErrNotExist](err); ok {
42+
ctx.JSONError(ctx.Tr("repo.editor.file_modifying_no_longer_exists", errAs.RelPath))
4343
} else if git_model.IsErrLFSFileLocked(err) {
4444
ctx.JSONError(ctx.Tr("repo.editor.upload_file_is_locked", err.(git_model.ErrLFSFileLocked).Path, err.(git_model.ErrLFSFileLocked).UserName))
4545
} else if errAs, ok := errorAs[files_service.ErrFilenameInvalid](err); ok {
4646
ctx.JSONError(ctx.Tr("repo.editor.filename_is_invalid", errAs.Path))
47-
} else if errAs, ok := errorAs[files_service.ErrFilePathInvalid](errAs); ok {
47+
} else if errAs, ok := errorAs[files_service.ErrFilePathInvalid](err); ok {
4848
switch errAs.Type {
4949
case git.EntryModeSymlink:
5050
ctx.JSONError(ctx.Tr("repo.editor.file_is_a_symlink", errAs.Path))
@@ -55,13 +55,13 @@ func editorHandleFileOperationError(ctx *context_service.Context, targetBranchNa
5555
default:
5656
ctx.JSONError(ctx.Tr("repo.editor.filename_is_invalid", errAs.Path))
5757
}
58-
} else if errAs, ok := errorAs[files_service.ErrRepoFileAlreadyExists](errAs); ok {
58+
} else if errAs, ok := errorAs[files_service.ErrRepoFileAlreadyExists](err); ok {
5959
ctx.JSONError(ctx.Tr("repo.editor.file_already_exists", errAs.Path))
60-
} else if errAs, ok := errorAs[git.ErrBranchNotExist](errAs); ok {
60+
} else if errAs, ok := errorAs[git.ErrBranchNotExist](err); ok {
6161
ctx.JSONError(ctx.Tr("repo.editor.branch_does_not_exist", errAs.Name))
62-
} else if errAs, ok := errorAs[git_model.ErrBranchAlreadyExists](errAs); ok {
62+
} else if errAs, ok := errorAs[git_model.ErrBranchAlreadyExists](err); ok {
6363
ctx.JSONError(ctx.Tr("repo.editor.branch_already_exists", errAs.BranchName))
64-
} else if files_service.IsErrCommitIDDoesNotMatch(errAs) {
64+
} else if files_service.IsErrCommitIDDoesNotMatch(err) {
6565
ctx.JSONError(ctx.Tr("repo.editor.commit_id_not_matching"))
6666
} else if files_service.IsErrCommitIDDoesNotMatch(err) || git.IsErrPushOutOfDate(err) {
6767
ctx.JSONError(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(ctx.Repo.CommitID)+"..."+util.PathEscapeSegments(targetBranchName)))
@@ -71,8 +71,10 @@ func editorHandleFileOperationError(ctx *context_service.Context, targetBranchNa
7171
} else {
7272
editorHandleFileOperationErrorRender(ctx, ctx.Locale.TrString("repo.editor.push_rejected"), ctx.Locale.TrString("repo.editor.push_rejected_summary"), errAs.Message)
7373
}
74+
} else if errors.Is(err, util.ErrNotExist) {
75+
ctx.JSONError(ctx.Tr("error.not_found"))
7476
} else {
75-
setting.PanicInDevOrTesting("unclear err: %v", err)
77+
setting.PanicInDevOrTesting("unclear err %T: %v", err, err)
7678
editorHandleFileOperationErrorRender(ctx, ctx.Locale.TrString("repo.editor.failed_to_commit"), ctx.Locale.TrString("repo.editor.failed_to_commit_summary"), err.Error())
7779
}
7880
}

services/forms/repo_form.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,7 @@ type UploadRepoFileForm struct {
757757
CommitMessage string
758758
CommitChoice string `binding:"Required;MaxSize(50)"`
759759
NewBranchName string `binding:"GitRefName;MaxSize(100)"`
760+
LastCommit string
760761
Files []string
761762
Signoff bool
762763
CommitEmail string

services/repository/files/update.go

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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
@@ -241,10 +258,14 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
241258
lfsContentStore := lfs.NewContentStore()
242259
for _, file := range opts.Files {
243260
switch file.Operation {
244-
case "create", "update", "rename":
245-
if err = CreateUpdateRenameFile(ctx, t, file, lfsContentStore, repo.ID, hasOldBranch); err != nil {
261+
case "create", "update", "rename", "upload":
262+
addedLfsPointer, err := modifyFile(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
@@ -366,6 +387,7 @@ func (err ErrSHAOrCommitIDNotProvided) Error() string {
366387

367388
// handles the check for various issues for ChangeRepoFiles
368389
func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRepoFilesOptions) error {
390+
// create: old must not exist; update: old must exist; upload: old existence doesn't matter
369391
if file.Operation == "update" || file.Operation == "delete" || file.Operation == "rename" {
370392
fromEntry, err := commit.GetTreeEntryByPath(file.Options.fromTreePath)
371393
if err != nil {
@@ -403,7 +425,7 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep
403425
file.Options.executable = fromEntry.IsExecutable()
404426
}
405427

406-
if file.Operation == "create" || file.Operation == "update" || file.Operation == "rename" {
428+
if file.Operation == "create" || file.Operation == "update" || file.Operation == "upload" || file.Operation == "rename" {
407429
// For operation's target path, we need to make sure no parts of the path are existing files or links
408430
// except for the last item in the path (which is the file name).
409431
// And that shouldn't exist IF it is a new file OR is being moved to a new path.
@@ -454,18 +476,23 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep
454476
return nil
455477
}
456478

457-
func CreateUpdateRenameFile(ctx context.Context, t *TemporaryUploadRepository, file *ChangeRepoFile, contentStore *lfs.ContentStore, repoID int64, hasOldBranch bool) error {
479+
func modifyFile(ctx context.Context, t *TemporaryUploadRepository, file *ChangeRepoFile, contentStore *lfs.ContentStore, repoID int64) (addedLfsPointer *lfs.Pointer, _ error) {
480+
if rd, ok := file.ContentReader.(LazyReader); ok {
481+
if err := rd.OpenLazyReader(); err != nil {
482+
return nil, fmt.Errorf("OpenLazyReader: %w", err)
483+
}
484+
defer rd.Close()
485+
}
486+
458487
// Get the two paths (might be the same if not moving) from the index if they exist
459488
filesInIndex, err := t.LsFiles(ctx, file.TreePath, file.FromTreePath)
460489
if err != nil {
461-
return fmt.Errorf("UpdateRepoFile: %w", err)
490+
return nil, fmt.Errorf("LsFiles: %w", err)
462491
}
463492
// If is a new file (not updating) then the given path shouldn't exist
464493
if file.Operation == "create" {
465494
if slices.Contains(filesInIndex, file.TreePath) {
466-
return ErrRepoFileAlreadyExists{
467-
Path: file.TreePath,
468-
}
495+
return nil, ErrRepoFileAlreadyExists{Path: file.TreePath}
469496
}
470497
}
471498

@@ -474,53 +501,54 @@ func CreateUpdateRenameFile(ctx context.Context, t *TemporaryUploadRepository, f
474501
for _, indexFile := range filesInIndex {
475502
if indexFile == file.Options.fromTreePath {
476503
if err = t.RemoveFilesFromIndex(ctx, file.FromTreePath); err != nil {
477-
return err
504+
return nil, err
478505
}
479506
}
480507
}
481508
}
482509

483510
var writeObjectRet *writeRepoObjectRet
484511
switch file.Operation {
485-
case "create", "update":
486-
writeObjectRet, err = writeRepoObjectForCreateOrUpdate(ctx, t, file)
512+
case "create", "update", "upload":
513+
writeObjectRet, err = writeRepoObjectForModify(ctx, t, file)
487514
case "rename":
488515
writeObjectRet, err = writeRepoObjectForRename(ctx, t, file)
489516
default:
490-
return util.NewInvalidArgumentErrorf("unknown file modification operation: '%s'", file.Operation)
517+
return nil, util.NewInvalidArgumentErrorf("unknown file modification operation: '%s'", file.Operation)
491518
}
492519
if err != nil {
493-
return err
520+
return nil, err
494521
}
495522

496523
// Add the object to the index, the "file.Options.executable" is set in handleCheckErrors by the caller (legacy hacky approach)
497524
if err = t.AddObjectToIndex(ctx, util.Iif(file.Options.executable, "100755", "100644"), writeObjectRet.ObjectHash, file.Options.treePath); err != nil {
498-
return err
525+
return nil, err
499526
}
500527

501528
if writeObjectRet.LfsContent == nil {
502-
return nil // No LFS pointer, so nothing to do
529+
return nil, nil // No LFS pointer, so nothing to do
503530
}
504531
defer writeObjectRet.LfsContent.Close()
505532

506533
// Now we must store the content into an LFS object
507534
lfsMetaObject, err := git_model.NewLFSMetaObject(ctx, repoID, writeObjectRet.LfsPointer)
508535
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
536+
return nil, err
515537
}
516-
517-
err = contentStore.Put(lfsMetaObject.Pointer, writeObjectRet.LfsContent)
538+
exist, err := contentStore.Exists(lfsMetaObject.Pointer)
518539
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)
540+
return nil, err
541+
}
542+
if !exist {
543+
err = contentStore.Put(lfsMetaObject.Pointer, writeObjectRet.LfsContent)
544+
if err != nil {
545+
if _, errRemove := git_model.RemoveLFSMetaObjectByOid(ctx, repoID, lfsMetaObject.Oid); errRemove != nil {
546+
return nil, fmt.Errorf("unable to remove failed inserted LFS object %s: %v (Prev Error: %w)", lfsMetaObject.Oid, errRemove, err)
547+
}
548+
return nil, err
521549
}
522550
}
523-
return err
551+
return &lfsMetaObject.Pointer, nil
524552
}
525553

526554
func checkIsLfsFileInGitAttributes(ctx context.Context, t *TemporaryUploadRepository, paths []string) (ret []bool, err error) {
@@ -544,8 +572,8 @@ type writeRepoObjectRet struct {
544572
LfsPointer lfs.Pointer
545573
}
546574

547-
// writeRepoObjectForCreateOrUpdate hashes the git object for create or update operations
548-
func writeRepoObjectForCreateOrUpdate(ctx context.Context, t *TemporaryUploadRepository, file *ChangeRepoFile) (ret *writeRepoObjectRet, err error) {
575+
// writeRepoObjectForModify hashes the git object for create or update operations
576+
func writeRepoObjectForModify(ctx context.Context, t *TemporaryUploadRepository, file *ChangeRepoFile) (ret *writeRepoObjectRet, err error) {
549577
ret = &writeRepoObjectRet{}
550578
treeObjectContentReader := file.ContentReader
551579
if setting.LFS.StartServer {
@@ -574,7 +602,7 @@ func writeRepoObjectForCreateOrUpdate(ctx context.Context, t *TemporaryUploadRep
574602
return ret, nil
575603
}
576604

577-
// writeRepoObjectForRename the same as writeRepoObjectForCreateOrUpdate buf for "rename"
605+
// writeRepoObjectForRename the same as writeRepoObjectForModify buf for "rename"
578606
func writeRepoObjectForRename(ctx context.Context, t *TemporaryUploadRepository, file *ChangeRepoFile) (ret *writeRepoObjectRet, err error) {
579607
lastCommitID, err := t.GetLastCommit(ctx)
580608
if err != nil {

0 commit comments

Comments
 (0)