Squashed commit of the following:
commit 0afcb843d7ffd596991c4885cab768273a6eb42c Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 17:13:29 2016 -0600 Removed Upload stats as the upload table is just a temporary table commit 7ecd73ff5535612d79d471409173ee7f1fcfa157 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 08:42:41 2016 -0600 Fix for CodeMirror mode commit c29b9ab531e2e7af0fb5db24dc17e51027dd1174 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 08:03:33 2016 -0600 Made tabbing in editor use spaces commit 23af384c53206a8a40e11e45bf49d7a149c4adcd Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 07:56:46 2016 -0600 Fix for data-url commit cfb8a97591cb6fc0a92e49563b7b764c524db0e9 Merge: 7fc8a89991ce42
Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 07:42:53 2016 -0600 Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file Conflicts: modules/bindata/bindata.go public/js/gogs.js commit 7fc8a89cb495478225b02d613e647f99a1489634 Merge: fd3d86c c03d040 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 07:40:00 2016 -0600 Merge branch 'feature-create-and-edit-repo-file' of github.com:richmahn/gogs into feature-create-and-edit-repo-file commit fd3d86ca6bbc02cfda566a504ffd6b03db4f75ef Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 07:39:44 2016 -0600 Code cleanup commit c03d0401c1049eeeccc32ab1f9c3303c130be5ee Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Fri Jul 29 15:38:23 2016 -0600 Code cleanup commit 98e1206ccf9f9a4503c020e3a7830cf9f861dfae Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Thu Jul 28 18:36:01 2016 -0600 Code cleanup and fixes commit c2895dc742f25f8412879c9fa15e18f27f42f194 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Thu Jul 28 18:24:04 2016 -0600 Fixes per Unknwon's requests commit 6aa7e46b21ad4c96e562daa2eac26a8fb408f8ef Merge: 889e9faad7ea88
Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Thu Jul 28 17:13:43 2016 -0600 Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file Conflicts: modules/bindata/bindata.go modules/setting/setting.go commit 889e9faf1bd8559a4979c8f46005d488c1a234d4 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Fri Jul 22 14:09:18 2016 -0600 Fix in gogs.js commit 47603edf223f147b114be65f3bd27bc1e88827a5 Merge: bb57912cf85e9e
Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Fri Jul 22 14:07:36 2016 -0600 Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file Conflicts: modules/bindata/bindata.go public/js/gogs.js commit bb5791255867a71c11a77b639db050ad09c597a4 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Fri Jul 22 14:02:18 2016 -0600 Update for using CodeMirror mode addon commit d10d128c51039be19e2af9c66c63db66a9f2ec6d Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Tue Jul 19 16:12:57 2016 -0600 Update for Edit commit 34a34982025144e3225e389f7849eb6273c1d576 Merge: fa1b7521c7dcdd
Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Tue Jul 19 11:52:02 2016 -0600 Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file Conflicts: modules/bindata/bindata.go commit fa1b752be29cd455c5184ddac2ffe80b3489763e Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Fri Jul 15 18:35:42 2016 -0600 Feature for editing, creating, uploading and deleting files
This commit is contained in:
parent
7e7613cdec
commit
d0a0239bac
34 changed files with 2509 additions and 208 deletions
|
@ -417,6 +417,19 @@ func (err ErrInvalidTagName) Error() string {
|
|||
return fmt.Sprintf("release tag name is not valid [tag_name: %s]", err.TagName)
|
||||
}
|
||||
|
||||
type ErrRepoFileAlreadyExist struct {
|
||||
FileName string
|
||||
}
|
||||
|
||||
func IsErrRepoFileAlreadyExist(err error) bool {
|
||||
_, ok := err.(ErrRepoFileAlreadyExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrRepoFileAlreadyExist) Error() string {
|
||||
return fmt.Sprintf("repository file already exists [file name: %s]", err.FileName)
|
||||
}
|
||||
|
||||
// __________ .__
|
||||
// \______ \____________ ____ ____ | |__
|
||||
// | | _/\_ __ \__ \ / \_/ ___\| | \
|
||||
|
@ -628,3 +641,27 @@ func IsErrTeamAlreadyExist(err error) bool {
|
|||
func (err ErrTeamAlreadyExist) Error() string {
|
||||
return fmt.Sprintf("team already exists [org_id: %d, name: %s]", err.OrgID, err.Name)
|
||||
}
|
||||
|
||||
// ____ ___ .__ .___
|
||||
// | | \______ | | _________ __| _/
|
||||
// | | /\____ \| | / _ \__ \ / __ |
|
||||
// | | / | |_> > |_( <_> ) __ \_/ /_/ |
|
||||
// |______/ | __/|____/\____(____ /\____ |
|
||||
// |__| \/ \/
|
||||
//
|
||||
|
||||
type ErrUploadNotExist struct {
|
||||
ID int64
|
||||
UUID string
|
||||
UserID int64
|
||||
RepoID int64
|
||||
}
|
||||
|
||||
func IsErrUploadNotExist(err error) bool {
|
||||
_, ok := err.(ErrAttachmentNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrUploadNotExist) Error() string {
|
||||
return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
|
||||
}
|
||||
|
|
|
@ -639,23 +639,18 @@ func newIssue(e *xorm.Session, repo *Repository, issue *Issue, labelIDs []int64,
|
|||
}
|
||||
|
||||
// Check attachments.
|
||||
attachments := make([]*Attachment, 0, len(uuids))
|
||||
for _, uuid := range uuids {
|
||||
attach, err := getAttachmentByUUID(e, uuid)
|
||||
attachment, err := getAttachmentByUUID(e, uuid)
|
||||
if err != nil {
|
||||
if IsErrAttachmentNotExist(err) {
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("getAttachmentByUUID[%s]: %v", uuid, err)
|
||||
}
|
||||
attachments = append(attachments, attach)
|
||||
}
|
||||
|
||||
for i := range attachments {
|
||||
attachments[i].IssueID = issue.ID
|
||||
attachment.IssueID = issue.ID
|
||||
// No assign value could be 0, so ignore AllCols().
|
||||
if _, err = e.Id(attachments[i].ID).Update(attachments[i]); err != nil {
|
||||
return fmt.Errorf("update attachment[%d]: %v", attachments[i].ID, err)
|
||||
if _, err = e.Id(attachment.ID).Update(attachment); err != nil {
|
||||
return fmt.Errorf("update attachment[%d]: %v", attachment.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1728,7 +1723,7 @@ func DeleteAttachments(attachments []*Attachment, remove bool) (int, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if _, err := x.Delete(a.ID); err != nil {
|
||||
if _, err := x.Delete(a); err != nil {
|
||||
return i, err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -354,7 +354,7 @@ func (pr *PullRequest) testPatch() (err error) {
|
|||
|
||||
log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)
|
||||
|
||||
if err := pr.BaseRepo.UpdateLocalCopy(); err != nil {
|
||||
if err := pr.BaseRepo.UpdateLocalCopy(pr.BaseRepo.DefaultBranch); err != nil {
|
||||
return fmt.Errorf("UpdateLocalCopy: %v", err)
|
||||
}
|
||||
|
||||
|
|
443
models/repo.go
443
models/repo.go
|
@ -9,7 +9,9 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
|
@ -28,6 +30,7 @@ import (
|
|||
|
||||
git "github.com/gogits/git-module"
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
|
||||
"github.com/gogits/gogs/modules/bindata"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
|
@ -435,16 +438,25 @@ func (repo *Repository) LocalCopyPath() string {
|
|||
return path.Join(setting.AppDataPath, "tmp/local", com.ToStr(repo.ID))
|
||||
}
|
||||
|
||||
func updateLocalCopy(repoPath, localPath string) error {
|
||||
func updateLocalCopy(repoPath, localPath, branch string) error {
|
||||
if !com.IsExist(localPath) {
|
||||
if err := git.Clone(repoPath, localPath, git.CloneRepoOptions{
|
||||
Timeout: time.Duration(setting.Git.Timeout.Clone) * time.Second,
|
||||
Branch: branch,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Clone: %v", err)
|
||||
}
|
||||
} else {
|
||||
if err := git.Checkout(localPath, git.CheckoutOptions{
|
||||
Branch: branch,
|
||||
Timeout: time.Duration(setting.Git.Timeout.Pull) * time.Second,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Checkout: %v", err)
|
||||
}
|
||||
if err := git.Pull(localPath, git.PullRemoteOptions{
|
||||
All: true,
|
||||
All: false,
|
||||
Remote: "origin",
|
||||
Branch: branch,
|
||||
Timeout: time.Duration(setting.Git.Timeout.Pull) * time.Second,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Pull: %v", err)
|
||||
|
@ -454,8 +466,8 @@ func updateLocalCopy(repoPath, localPath string) error {
|
|||
}
|
||||
|
||||
// UpdateLocalCopy makes sure the local copy of repository is up-to-date.
|
||||
func (repo *Repository) UpdateLocalCopy() error {
|
||||
return updateLocalCopy(repo.RepoPath(), repo.LocalCopyPath())
|
||||
func (repo *Repository) UpdateLocalCopy(branch string) error {
|
||||
return updateLocalCopy(repo.RepoPath(), repo.LocalCopyPath(), branch)
|
||||
}
|
||||
|
||||
// PatchPath returns corresponding patch file path of repository by given issue ID.
|
||||
|
@ -2255,3 +2267,426 @@ func (repo *Repository) GetForks() ([]*Repository, error) {
|
|||
forks := make([]*Repository, 0, repo.NumForks)
|
||||
return forks, x.Find(&forks, &Repository{ForkID: repo.ID})
|
||||
}
|
||||
|
||||
// ___________ .___.__ __ ___________.__.__
|
||||
// \_ _____/ __| _/|__|/ |_ \_ _____/|__| | ____
|
||||
// | __)_ / __ | | \ __\ | __) | | | _/ __ \
|
||||
// | \/ /_/ | | || | | \ | | |_\ ___/
|
||||
// /_______ /\____ | |__||__| \___ / |__|____/\___ >
|
||||
// \/ \/ \/ \/
|
||||
|
||||
var repoWorkingPool = &workingPool{
|
||||
pool: make(map[string]*sync.Mutex),
|
||||
count: make(map[string]int),
|
||||
}
|
||||
|
||||
func (repo *Repository) LocalRepoPath() string {
|
||||
return path.Join(setting.AppDataPath, "tmp/local-repo", com.ToStr(repo.ID))
|
||||
}
|
||||
|
||||
// UpdateLocalRepo makes sure the local copy of repository is up-to-date.
|
||||
func (repo *Repository) UpdateLocalRepo(branchName string) error {
|
||||
return updateLocalCopy(repo.RepoPath(), repo.LocalRepoPath(), branchName)
|
||||
}
|
||||
|
||||
// DiscardLocalRepoChanges makes sure the local copy of repository is the same as the source
|
||||
func (repo *Repository) DiscardLocalRepoChanges(branchName string) error {
|
||||
return discardLocalRepoChanges(repo.LocalRepoPath(), branchName)
|
||||
}
|
||||
|
||||
// discardLocalRepoChanges discards local commits make sure
|
||||
// it is even to remote branch when local copy exists.
|
||||
func discardLocalRepoChanges(localPath string, branch string) error {
|
||||
if !com.IsExist(localPath) {
|
||||
return nil
|
||||
}
|
||||
// No need to check if nothing in the repository.
|
||||
if !git.IsBranchExist(localPath, branch) {
|
||||
return nil
|
||||
}
|
||||
if err := git.ResetHEAD(localPath, true, "origin/"+branch); err != nil {
|
||||
return fmt.Errorf("ResetHEAD: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckoutNewBranch checks out a new branch from the given branch name
|
||||
func (repo *Repository) CheckoutNewBranch(oldBranchName, newBranchName string) error {
|
||||
return checkoutNewBranch(repo.RepoPath(), repo.LocalRepoPath(), oldBranchName, newBranchName)
|
||||
}
|
||||
|
||||
func checkoutNewBranch(repoPath, localPath, oldBranch, newBranch string) error {
|
||||
if !com.IsExist(localPath) {
|
||||
if err := updateLocalCopy(repoPath, localPath, oldBranch); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := git.Checkout(localPath, git.CheckoutOptions{
|
||||
Branch: newBranch,
|
||||
OldBranch: oldBranch,
|
||||
Timeout: time.Duration(setting.Git.Timeout.Pull) * time.Second,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Checkout New Branch: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateRepoFile adds new file to repository.
|
||||
func (repo *Repository) UpdateRepoFile(doer *User, oldBranchName, branchName, oldTreeName, treeName, content, message string, isNewFile bool) (err error) {
|
||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
if err = repo.DiscardLocalRepoChanges(oldBranchName); err != nil {
|
||||
return fmt.Errorf("discardLocalRepoChanges: %s - %v", oldBranchName, err)
|
||||
} else if err = repo.UpdateLocalRepo(oldBranchName); err != nil {
|
||||
return fmt.Errorf("UpdateLocalRepo: %s - %v", oldBranchName, err)
|
||||
}
|
||||
|
||||
if oldBranchName != branchName {
|
||||
if err := repo.CheckoutNewBranch(oldBranchName, branchName); err != nil {
|
||||
return fmt.Errorf("CheckoutNewBranch: %s - %s: %v", oldBranchName, branchName, err)
|
||||
}
|
||||
}
|
||||
|
||||
localPath := repo.LocalRepoPath()
|
||||
filePath := path.Join(localPath, treeName)
|
||||
|
||||
if len(message) == 0 {
|
||||
if isNewFile {
|
||||
message = "Add '" + treeName + "'"
|
||||
} else {
|
||||
message = "Update '" + treeName + "'"
|
||||
}
|
||||
}
|
||||
|
||||
os.MkdirAll(filepath.Dir(filePath), os.ModePerm)
|
||||
|
||||
// If new file, make sure it doesn't exist; if old file, move if file name change
|
||||
if isNewFile {
|
||||
if com.IsExist(filePath) {
|
||||
return ErrRepoFileAlreadyExist{filePath}
|
||||
}
|
||||
} else if oldTreeName != "" && treeName != "" && treeName != oldTreeName {
|
||||
if err = git.MoveFile(localPath, oldTreeName, treeName); err != nil {
|
||||
return fmt.Errorf("MoveFile: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(filePath, []byte(content), 0666); err != nil {
|
||||
return fmt.Errorf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("AddChanges: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, "origin", branchName); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo *Repository) GetPreviewDiff(repoPath, branchName, treeName, text string, maxlines, maxchars, maxfiles int) (diff *Diff, err error) {
|
||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
if err = repo.DiscardLocalRepoChanges(branchName); err != nil {
|
||||
return nil, fmt.Errorf("discardLocalRepoChanges: %s - %v", branchName, err)
|
||||
} else if err = repo.UpdateLocalRepo(branchName); err != nil {
|
||||
return nil, fmt.Errorf("UpdateLocalRepo: %s - %v", branchName, err)
|
||||
}
|
||||
|
||||
localPath := repo.LocalRepoPath()
|
||||
filePath := path.Join(localPath, treeName)
|
||||
|
||||
os.MkdirAll(filepath.Dir(filePath), os.ModePerm)
|
||||
|
||||
if err = ioutil.WriteFile(filePath, []byte(text), 0666); err != nil {
|
||||
return nil, fmt.Errorf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
var cmd *exec.Cmd
|
||||
cmd = exec.Command("git", "diff", treeName)
|
||||
cmd.Dir = localPath
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("StdoutPipe: %v", err)
|
||||
}
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("Start: %v", err)
|
||||
}
|
||||
|
||||
pid := process.Add(fmt.Sprintf("GetDiffRange (%s)", repoPath), cmd)
|
||||
defer process.Remove(pid)
|
||||
|
||||
diff, err = ParsePatch(maxlines, maxchars, maxfiles, stdout)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ParsePatch: %v", err)
|
||||
}
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
return nil, fmt.Errorf("Wait: %v", err)
|
||||
}
|
||||
|
||||
return diff, nil
|
||||
}
|
||||
|
||||
// ________ .__ __ ___________.__.__
|
||||
// \______ \ ____ | | _____/ |_ ____ \_ _____/|__| | ____
|
||||
// | | \_/ __ \| | _/ __ \ __\/ __ \ | __) | | | _/ __ \
|
||||
// | ` \ ___/| |_\ ___/| | \ ___/ | \ | | |_\ ___/
|
||||
// /_______ /\___ >____/\___ >__| \___ > \___ / |__|____/\___ >
|
||||
// \/ \/ \/ \/ \/ \/
|
||||
//
|
||||
|
||||
func (repo *Repository) DeleteRepoFile(doer *User, branch, treeName, message string) (err error) {
|
||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
localPath := repo.LocalRepoPath()
|
||||
if err = discardLocalRepoChanges(localPath, branch); err != nil {
|
||||
return fmt.Errorf("discardLocalRepoChanges: %v", err)
|
||||
} else if err = repo.UpdateLocalRepo(branch); err != nil {
|
||||
return fmt.Errorf("UpdateLocalRepo: %v", err)
|
||||
}
|
||||
|
||||
filePath := path.Join(localPath, treeName)
|
||||
os.Remove(filePath)
|
||||
|
||||
if len(message) == 0 {
|
||||
message = "Delete file '" + treeName + "'"
|
||||
}
|
||||
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("AddChanges: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, "origin", branch); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ____ ___ .__ .___ ___________.___.__
|
||||
// | | \______ | | _________ __| _/ \_ _____/| | | ____ ______
|
||||
// | | /\____ \| | / _ \__ \ / __ | | __) | | | _/ __ \ / ___/
|
||||
// | | / | |_> > |_( <_> ) __ \_/ /_/ | | \ | | |_\ ___/ \___ \
|
||||
// |______/ | __/|____/\____(____ /\____ | \___ / |___|____/\___ >____ >
|
||||
// |__| \/ \/ \/ \/ \/
|
||||
//
|
||||
|
||||
// uploadRepoFiles uploads new files to repository.
|
||||
func (repo *Repository) UploadRepoFiles(doer *User, oldBranchName, branchName, treeName, message string, uuids []string) (err error) {
|
||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
localPath := repo.LocalRepoPath()
|
||||
|
||||
if err = discardLocalRepoChanges(localPath, oldBranchName); err != nil {
|
||||
return fmt.Errorf("discardLocalRepoChanges: %v", err)
|
||||
} else if err = repo.UpdateLocalRepo(oldBranchName); err != nil {
|
||||
return fmt.Errorf("UpdateLocalRepo: %v", err)
|
||||
}
|
||||
|
||||
if oldBranchName != branchName {
|
||||
repo.CheckoutNewBranch(oldBranchName, branchName)
|
||||
}
|
||||
|
||||
dirPath := path.Join(localPath, treeName)
|
||||
os.MkdirAll(dirPath, os.ModePerm)
|
||||
|
||||
// Copy uploaded files into repository.
|
||||
for _, uuid := range uuids {
|
||||
upload, err := getUpload(uuid, doer.ID, repo.ID)
|
||||
if err != nil {
|
||||
if IsErrUploadNotExist(err) {
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("getUpload[%s]: %v", uuid, err)
|
||||
}
|
||||
uuidPath := upload.LocalPath()
|
||||
filePath := dirPath + "/" + upload.Name
|
||||
if err := os.Rename(uuidPath, filePath); err != nil {
|
||||
DeleteUpload(upload, true)
|
||||
return fmt.Errorf("Rename[%s -> %s]: %v", uuidPath, filePath, err)
|
||||
}
|
||||
DeleteUpload(upload, false) // false because we have moved the file
|
||||
}
|
||||
|
||||
if len(message) == 0 {
|
||||
message = "Add files to '" + treeName + "'"
|
||||
}
|
||||
|
||||
if err = git.AddChanges(localPath, true); err != nil {
|
||||
return fmt.Errorf("AddChanges: %v", err)
|
||||
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
|
||||
return fmt.Errorf("CommitChanges: %v", err)
|
||||
} else if err = git.Push(localPath, "origin", branchName); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Upload represent a uploaded file to a repo to be deleted when moved
|
||||
type Upload struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UUID string `xorm:"uuid UNIQUE"`
|
||||
UID int64 `xorm:"INDEX"`
|
||||
RepoID int64 `xorm:"INDEX"`
|
||||
Name string
|
||||
Created time.Time `xorm:"-"`
|
||||
CreatedUnix int64
|
||||
}
|
||||
|
||||
func (u *Upload) BeforeInsert() {
|
||||
u.CreatedUnix = time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
func (u *Upload) AfterSet(colName string, _ xorm.Cell) {
|
||||
switch colName {
|
||||
case "created_unix":
|
||||
u.Created = time.Unix(u.CreatedUnix, 0).Local()
|
||||
}
|
||||
}
|
||||
|
||||
// UploadLocalPath returns where uploads is stored in local file system based on given UUID.
|
||||
func UploadLocalPath(uuid string) string {
|
||||
return path.Join(setting.UploadTempPath, uuid[0:1], uuid[1:2], uuid)
|
||||
}
|
||||
|
||||
// LocalPath returns where uploads are temporarily stored in local file system.
|
||||
func (upload *Upload) LocalPath() string {
|
||||
return UploadLocalPath(upload.UUID)
|
||||
}
|
||||
|
||||
// NewUpload creates a new upload object.
|
||||
func NewUpload(name string, buf []byte, file multipart.File, userId, repoId int64) (_ *Upload, err error) {
|
||||
up := &Upload{
|
||||
UUID: gouuid.NewV4().String(),
|
||||
Name: name,
|
||||
UID: userId,
|
||||
RepoID: repoId,
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(path.Dir(up.LocalPath()), os.ModePerm); err != nil {
|
||||
return nil, fmt.Errorf("MkdirAll: %v", err)
|
||||
}
|
||||
|
||||
fw, err := os.Create(up.LocalPath())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Create: %v", err)
|
||||
}
|
||||
defer fw.Close()
|
||||
|
||||
if _, err = fw.Write(buf); err != nil {
|
||||
return nil, fmt.Errorf("Write: %v", err)
|
||||
} else if _, err = io.Copy(fw, file); err != nil {
|
||||
return nil, fmt.Errorf("Copy: %v", err)
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err := sess.Begin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := sess.Insert(up); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return up, sess.Commit()
|
||||
}
|
||||
|
||||
// RemoveUpload removes the file by UUID
|
||||
func RemoveUpload(uuid string, userId, repoId int64) (err error) {
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
upload, err := getUpload(uuid, userId, repoId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getUpload[%s]: %v", uuid, err)
|
||||
}
|
||||
|
||||
if err := DeleteUpload(upload, true); err != nil {
|
||||
return fmt.Errorf("DeleteUpload[%s]: %v", uuid, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getUpload(uuid string, userID, repoID int64) (*Upload, error) {
|
||||
up := &Upload{UUID: uuid, UID: userID, RepoID: repoID}
|
||||
has, err := x.Get(up)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrUploadNotExist{0, uuid, userID, repoID}
|
||||
}
|
||||
return up, nil
|
||||
}
|
||||
|
||||
// GetUpload returns Upload by given UUID.
|
||||
func GetUpload(uuid string, userId, repoId int64) (*Upload, error) {
|
||||
return getUpload(uuid, userId, repoId)
|
||||
}
|
||||
|
||||
// DeleteUpload deletes the given upload
|
||||
func DeleteUpload(u *Upload, remove bool) error {
|
||||
_, err := DeleteUploads([]*Upload{u}, remove)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteUploads deletes the given uploads
|
||||
func DeleteUploads(uploads []*Upload, remove bool) (int, error) {
|
||||
for i, u := range uploads {
|
||||
if remove {
|
||||
if err := os.Remove(u.LocalPath()); err != nil {
|
||||
return i, err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := x.Delete(u); err != nil {
|
||||
return i, err
|
||||
}
|
||||
}
|
||||
|
||||
return len(uploads), nil
|
||||
}
|
||||
|
||||
// __________ .__
|
||||
// \______ \____________ ____ ____ | |__
|
||||
// | | _/\_ __ \__ \ / \_/ ___\| | \
|
||||
// | | \ | | \// __ \| | \ \___| Y \
|
||||
// |______ / |__| (____ /___| /\___ >___| /
|
||||
// \/ \/ \/ \/ \/
|
||||
//
|
||||
|
||||
func (repo *Repository) CreateNewBranch(doer *User, oldBranchName, branchName string) (err error) {
|
||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||
|
||||
localPath := repo.LocalRepoPath()
|
||||
|
||||
if err = discardLocalRepoChanges(localPath, oldBranchName); err != nil {
|
||||
return fmt.Errorf("discardLocalRepoChanges: %v", err)
|
||||
} else if err = repo.UpdateLocalRepo(oldBranchName); err != nil {
|
||||
return fmt.Errorf("UpdateLocalRepo: %v", err)
|
||||
}
|
||||
|
||||
if err = repo.CheckoutNewBranch(oldBranchName, branchName); err != nil {
|
||||
return fmt.Errorf("CreateNewBranch: %v", err)
|
||||
}
|
||||
|
||||
if err = git.Push(localPath, "origin", branchName); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -21,44 +21,6 @@ import (
|
|||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
// workingPool represents a pool of working status which makes sure
|
||||
// that only one instance of same task is performing at a time.
|
||||
// However, different type of tasks can performing at the same time.
|
||||
type workingPool struct {
|
||||
lock sync.Mutex
|
||||
pool map[string]*sync.Mutex
|
||||
count map[string]int
|
||||
}
|
||||
|
||||
// CheckIn checks in a task and waits if others are running.
|
||||
func (p *workingPool) CheckIn(name string) {
|
||||
p.lock.Lock()
|
||||
|
||||
lock, has := p.pool[name]
|
||||
if !has {
|
||||
lock = &sync.Mutex{}
|
||||
p.pool[name] = lock
|
||||
}
|
||||
p.count[name]++
|
||||
|
||||
p.lock.Unlock()
|
||||
lock.Lock()
|
||||
}
|
||||
|
||||
// CheckOut checks out a task to let other tasks run.
|
||||
func (p *workingPool) CheckOut(name string) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
p.pool[name].Unlock()
|
||||
if p.count[name] == 1 {
|
||||
delete(p.pool, name)
|
||||
delete(p.count, name)
|
||||
} else {
|
||||
p.count[name]--
|
||||
}
|
||||
}
|
||||
|
||||
var wikiWorkingPool = &workingPool{
|
||||
pool: make(map[string]*sync.Mutex),
|
||||
count: make(map[string]int),
|
||||
|
@ -117,7 +79,7 @@ func (repo *Repository) LocalWikiPath() string {
|
|||
|
||||
// UpdateLocalWiki makes sure the local copy of repository wiki is up-to-date.
|
||||
func (repo *Repository) UpdateLocalWiki() error {
|
||||
return updateLocalCopy(repo.WikiPath(), repo.LocalWikiPath())
|
||||
return updateLocalCopy(repo.WikiPath(), repo.LocalWikiPath(), "")
|
||||
}
|
||||
|
||||
// discardLocalWikiChanges discards local commits make sure
|
||||
|
|
47
models/working_pool.go
Normal file
47
models/working_pool.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// workingPool represents a pool of working status which makes sure
|
||||
// that only one instance of same task is performing at a time.
|
||||
// However, different type of tasks can performing at the same time.
|
||||
type workingPool struct {
|
||||
lock sync.Mutex
|
||||
pool map[string]*sync.Mutex
|
||||
count map[string]int
|
||||
}
|
||||
|
||||
// CheckIn checks in a task and waits if others are running.
|
||||
func (p *workingPool) CheckIn(name string) {
|
||||
p.lock.Lock()
|
||||
|
||||
lock, has := p.pool[name]
|
||||
if !has {
|
||||
lock = &sync.Mutex{}
|
||||
p.pool[name] = lock
|
||||
}
|
||||
p.count[name]++
|
||||
|
||||
p.lock.Unlock()
|
||||
lock.Lock()
|
||||
}
|
||||
|
||||
// CheckOut checks out a task to let other tasks run.
|
||||
func (p *workingPool) CheckOut(name string) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
p.pool[name].Unlock()
|
||||
if p.count[name] == 1 {
|
||||
delete(p.pool, name)
|
||||
delete(p.count, name)
|
||||
} else {
|
||||
p.count[name]--
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue