Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Distinguish LFS object errors to ignore missing objects during migration #31702

Merged
merged 4 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions modules/lfs/http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,13 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc

for _, object := range result.Objects {
if object.Error != nil {
objectError := errors.New(object.Error.Message)
log.Trace("Error on object %v: %v", object.Pointer, objectError)
log.Trace("Error on object %v: %v", object.Pointer, object.Error)
if uc != nil {
if _, err := uc(object.Pointer, objectError); err != nil {
if _, err := uc(object.Pointer, object.Error); err != nil {
return err
}
} else {
if err := dc(object.Pointer, nil, objectError); err != nil {
if err := dc(object.Pointer, nil, object.Error); err != nil {
return err
}
}
Expand Down
37 changes: 37 additions & 0 deletions modules/lfs/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
package lfs

import (
"errors"
"fmt"
"time"

"code.gitea.io/gitea/modules/util"
)

const (
Expand Down Expand Up @@ -64,6 +68,39 @@ type ObjectError struct {
Message string `json:"message"`
}

var (
// See https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md#successful-responses
// LFS object error codes should match HTTP status codes where possible:
// 404 - The object does not exist on the server.
// 409 - The specified hash algorithm disagrees with the server's acceptable options.
// 410 - The object was removed by the owner.
// 422 - Validation error.

ErrObjectNotExist = util.ErrNotExist // the object does not exist on the server
ErrObjectHashMismatch = errors.New("the specified hash algorithm disagrees with the server's acceptable options")
ErrObjectRemoved = errors.New("the object was removed by the owner")
ErrObjectValidation = errors.New("validation error")
)

func (e *ObjectError) Error() string {
return fmt.Sprintf("[%d] %s", e.Code, e.Message)
}

func (e *ObjectError) Unwrap() error {
switch e.Code {
case 404:
return ErrObjectNotExist
case 409:
return ErrObjectHashMismatch
case 410:
return ErrObjectRemoved
case 422:
return ErrObjectValidation
default:
return errors.New(e.Message)
}
}

// PointerBlob associates a Git blob with a Pointer.
type PointerBlob struct {
Hash string
Expand Down
5 changes: 5 additions & 0 deletions modules/repository/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package repository

import (
"context"
"errors"
"fmt"
"io"
"strings"
Expand Down Expand Up @@ -181,6 +182,10 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re
downloadObjects := func(pointers []lfs.Pointer) error {
err := lfsClient.Download(ctx, pointers, func(p lfs.Pointer, content io.ReadCloser, objectError error) error {
if objectError != nil {
if errors.Is(objectError, lfs.ErrObjectNotExist) {
log.Warn("Repo[%-v]: Ignore missing LFS object %-v: %v", repo, p, objectError)
return nil
}
return objectError
}

Expand Down
1 change: 1 addition & 0 deletions services/repository/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
lfsClient := lfs.NewClient(endpoint, httpTransport)
if err = repo_module.StoreMissingLfsObjectsInRepository(ctx, repo, gitRepo, lfsClient); err != nil {
log.Error("Failed to store missing LFS objects for repository: %v", err)
return repo, fmt.Errorf("StoreMissingLfsObjectsInRepository: %w", err)
}
}
}
Expand Down