mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
112 lines
2.5 KiB
Go
112 lines
2.5 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package files
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
"sync"
|
|
|
|
repo_model "github.com/hanzoai/git/models/repo"
|
|
user_model "github.com/hanzoai/git/models/user"
|
|
"github.com/hanzoai/git/modules/log"
|
|
)
|
|
|
|
// UploadRepoFileOptions contains the uploaded repository file options
|
|
type UploadRepoFileOptions struct {
|
|
LastCommitID string
|
|
OldBranch string
|
|
NewBranch string
|
|
TreePath string
|
|
Message string
|
|
Files []string // In UUID format.
|
|
Signoff bool
|
|
Author *IdentityOptions
|
|
Committer *IdentityOptions
|
|
}
|
|
|
|
type lazyLocalFileReader struct {
|
|
*os.File
|
|
localFilename string
|
|
counter int
|
|
mu sync.Mutex
|
|
}
|
|
|
|
var _ LazyReadSeeker = (*lazyLocalFileReader)(nil)
|
|
|
|
func (l *lazyLocalFileReader) Close() error {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
if l.counter > 0 {
|
|
l.counter--
|
|
if l.counter == 0 {
|
|
if err := l.File.Close(); err != nil {
|
|
return fmt.Errorf("close file %s: %w", l.localFilename, err)
|
|
}
|
|
l.File = nil
|
|
}
|
|
return nil
|
|
}
|
|
return fmt.Errorf("file %s already closed", l.localFilename)
|
|
}
|
|
|
|
func (l *lazyLocalFileReader) OpenLazyReader() error {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
if l.File != nil {
|
|
l.counter++
|
|
return nil
|
|
}
|
|
|
|
file, err := os.Open(l.localFilename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
l.File = file
|
|
l.counter = 1
|
|
return nil
|
|
}
|
|
|
|
// UploadRepoFiles uploads files to the given repository
|
|
func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, opts *UploadRepoFileOptions) error {
|
|
if len(opts.Files) == 0 {
|
|
return nil
|
|
}
|
|
|
|
uploads, err := repo_model.GetUploadsByUUIDs(ctx, opts.Files)
|
|
if err != nil {
|
|
return fmt.Errorf("GetUploadsByUUIDs [uuids: %v]: %w", opts.Files, err)
|
|
}
|
|
|
|
changeOpts := &ChangeRepoFilesOptions{
|
|
LastCommitID: opts.LastCommitID,
|
|
OldBranch: opts.OldBranch,
|
|
NewBranch: opts.NewBranch,
|
|
Message: opts.Message,
|
|
Signoff: opts.Signoff,
|
|
Author: opts.Author,
|
|
Committer: opts.Committer,
|
|
}
|
|
for _, upload := range uploads {
|
|
changeOpts.Files = append(changeOpts.Files, &ChangeRepoFile{
|
|
Operation: "upload",
|
|
TreePath: path.Join(opts.TreePath, upload.Name),
|
|
ContentReader: &lazyLocalFileReader{localFilename: upload.LocalPath()},
|
|
})
|
|
}
|
|
|
|
_, err = ChangeRepoFiles(ctx, repo, doer, changeOpts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := repo_model.DeleteUploads(ctx, uploads...); err != nil {
|
|
log.Error("DeleteUploads: %v", err)
|
|
}
|
|
return nil
|
|
}
|