diff --git a/git/operations.go b/git/operations.go index 42d24faec..c93fba6a3 100644 --- a/git/operations.go +++ b/git/operations.go @@ -410,274 +410,3 @@ func (s *Service) processAction( return modifiedPath, err } - -/* -func (s *Service) prepareTree( - ctx context.Context, - shared *api.SharedRepo, - actions []CommitFileAction, - commit *api.Commit, -) error { - // execute all actions - for i := range actions { - if err := s.processAction(ctx, shared, &actions[i], commit); err != nil { - return err - } - } - - return nil -} - -func prepareTreeEmptyRepo( - ctx context.Context, - shared *api.SharedRepo, - actions []CommitFileAction, -) error { - for _, action := range actions { - if action.Action != CreateAction { - return errors.PreconditionFailed("action not allowed on empty repository") - } - - filePath := api.CleanUploadFileName(action.Path) - if filePath == "" { - return errors.InvalidArgument("invalid path") - } - - if err := createFile(ctx, shared, nil, filePath, defaultFilePermission, action.Payload); err != nil { - return errors.Internal(err, "failed to create file '%s'", action.Path) - } - } - - return nil -} - -func (s *Service) processAction( - ctx context.Context, - shared *api.SharedRepo, - action *CommitFileAction, - commit *api.Commit, -) (err error) { - filePath := api.CleanUploadFileName(action.Path) - if filePath == "" { - return errors.InvalidArgument("path cannot be empty") - } - - switch action.Action { - case CreateAction: - err = createFile(ctx, shared, commit, filePath, defaultFilePermission, action.Payload) - case UpdateAction: - err = updateFile(ctx, shared, commit, filePath, action.SHA, defaultFilePermission, action.Payload) - case MoveAction: - err = moveFile(ctx, shared, commit, filePath, action.SHA, defaultFilePermission, action.Payload) - case DeleteAction: - err = deleteFile(ctx, shared, filePath) - } - - return err -} - -func createFile(ctx context.Context, repo *api.SharedRepo, commit *api.Commit, - filePath, mode string, payload []byte) error { - // only check path availability if a source commit is available (empty repo won't have such a commit) - if commit != nil { - if err := checkPathAvailability(ctx, repo, commit, filePath, true); err != nil { - return err - } - } - - hash, err := repo.WriteGitObject(ctx, bytes.NewReader(payload)) - if err != nil { - return fmt.Errorf("createFile: error hashing object: %w", err) - } - - // Add the object to the index - if err = repo.AddObjectToIndex(ctx, mode, hash.String(), filePath); err != nil { - return fmt.Errorf("createFile: error creating object: %w", err) - } - return nil -} - -func updateFile( - ctx context.Context, - repo *api.SharedRepo, - commit *api.Commit, - filePath string, - sha string, - mode string, - payload []byte, -) error { - // get file mode from existing file (default unless executable) - entry, err := getFileEntry(ctx, repo, commit, sha, filePath) - if err != nil { - return err - } - if entry.IsExecutable() { - mode = "100755" - } - - hash, err := repo.WriteGitObject(ctx, bytes.NewReader(payload)) - if err != nil { - return fmt.Errorf("updateFile: error hashing object: %w", err) - } - - if err = repo.AddObjectToIndex(ctx, mode, hash.String(), filePath); err != nil { - return fmt.Errorf("updateFile: error updating object: %w", err) - } - return nil -} - -func moveFile( - ctx context.Context, - repo *api.SharedRepo, - commit *api.Commit, - filePath string, - sha string, - mode string, - payload []byte, -) error { - newPath, newContent, err := parseMovePayload(payload) - if err != nil { - return err - } - - // ensure file exists and matches SHA - entry, err := getFileEntry(ctx, repo, commit, sha, filePath) - if err != nil { - return err - } - - // ensure new path is available - if err = checkPathAvailability(ctx, repo, commit, newPath, false); err != nil { - return err - } - - var fileHash string - var fileMode string - if newContent != nil { - hash, err := repo.WriteGitObject(ctx, bytes.NewReader(newContent)) - if err != nil { - return fmt.Errorf("moveFile: error hashing object: %w", err) - } - - fileHash = hash.String() - fileMode = mode - if entry.IsExecutable() { - fileMode = "100755" - } - } else { - fileHash = entry.SHA.String() - fileMode = entry.Mode.String() - } - - if err = repo.AddObjectToIndex(ctx, fileMode, fileHash, newPath); err != nil { - return fmt.Errorf("moveFile: add object error: %w", err) - } - - if err = repo.RemoveFilesFromIndex(ctx, filePath); err != nil { - return fmt.Errorf("moveFile: remove object error: %w", err) - } - return nil -} - -func deleteFile(ctx context.Context, repo *api.SharedRepo, filePath string) error { - filesInIndex, err := repo.LsFiles(ctx, filePath) - if err != nil { - return fmt.Errorf("deleteFile: listing files error: %w", err) - } - if !slices.Contains(filesInIndex, filePath) { - return errors.NotFound("file path %s not found", filePath) - } - - if err = repo.RemoveFilesFromIndex(ctx, filePath); err != nil { - return fmt.Errorf("deleteFile: remove object error: %w", err) - } - return nil -} - -func getFileEntry( - ctx context.Context, - repo *api.SharedRepo, - commit *api.Commit, - sha string, - path string, -) (*api.TreeNode, error) { - entry, err := repo.GetTreeNode(ctx, commit.SHA.String(), path) - if errors.IsNotFound(err) { - return nil, errors.NotFound("path %s not found", path) - } - if err != nil { - return nil, fmt.Errorf("getFileEntry: failed to get tree for path %s: %w", path, err) - } - - // If a SHA was given and the SHA given doesn't match the SHA of the fromTreePath, throw error - if sha != "" && sha != entry.SHA.String() { - return nil, errors.InvalidArgument("sha does not match for path %s [given: %s, expected: %s]", - path, sha, entry.SHA) - } - - return entry, nil -} - -// checkPathAvailability ensures that the path is available for the requested operation. -// For the path where this file will be created/updated, we need to make -// sure no parts of the path are existing files or links except for the last -// item in the path which is the file name, and that shouldn't exist IF it is -// a new file OR is being moved to a new path. -func checkPathAvailability( - ctx context.Context, - repo *api.SharedRepo, - commit *api.Commit, - filePath string, - isNewFile bool, -) error { - parts := strings.Split(filePath, "/") - subTreePath := "" - for index, part := range parts { - subTreePath = path.Join(subTreePath, part) - entry, err := repo.GetTreeNode(ctx, commit.SHA.String(), subTreePath) - if err != nil { - if errors.IsNotFound(err) { - // Means there is no item with that name, so we're good - break - } - return fmt.Errorf("checkPathAvailability: failed to get tree entry for path %s: %w", subTreePath, err) - } - switch { - case index < len(parts)-1: - if !entry.IsDir() { - return errors.Conflict("a file already exists where you're trying to create a subdirectory [path: %s]", - subTreePath) - } - case entry.IsLink(): - return errors.Conflict("a symbolic link already exist where you're trying to create a subdirectory [path: %s]", - subTreePath) - case entry.IsDir(): - return errors.Conflict("a directory already exists where you're trying to create a subdirectory [path: %s]", - subTreePath) - case filePath != "" || isNewFile: - return errors.Conflict("file path %s already exists", filePath) - } - } - return nil -} - -func parseMovePayload(payload []byte) (string, []byte, error) { - var newContent []byte - var newPath string - filePathEnd := bytes.IndexByte(payload, 0) - if filePathEnd < 0 { - newPath = string(payload) - newContent = nil - } else { - newPath = string(payload[:filePathEnd]) - newContent = payload[filePathEnd+1:] - } - - newPath = api.CleanUploadFileName(newPath) - if newPath == "" { - return "", nil, api.ErrInvalidPath - } - - return newPath, newContent, nil -} -*/