diff options
author | Richard Mahn <richard_mahn@wycliffeassociates.org> | 2016-08-11 05:48:08 -0700 |
---|---|---|
committer | Unknwon <u@gogs.io> | 2016-08-14 23:52:24 -0700 |
commit | d0a0239bacf02eb004634dfe1bb0a3f7dfe5adb6 (patch) | |
tree | 8459045909d43af85df2afa34f785a0481ae0b9e /models | |
parent | 7e7613cdecf6ceaf97ac280ae98bb9541679963f (diff) | |
download | gitea-d0a0239bacf02eb004634dfe1bb0a3f7dfe5adb6.tar.gz gitea-d0a0239bacf02eb004634dfe1bb0a3f7dfe5adb6.zip |
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: 7fc8a89 991ce42
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: 889e9fa ad7ea88
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: bb57912 cf85e9e
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: fa1b752 1c7dcdd
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
Diffstat (limited to 'models')
-rw-r--r-- | models/error.go | 37 | ||||
-rw-r--r-- | models/issue.go | 15 | ||||
-rw-r--r-- | models/pull.go | 2 | ||||
-rw-r--r-- | models/repo.go | 443 | ||||
-rw-r--r-- | models/wiki.go | 40 | ||||
-rw-r--r-- | models/working_pool.go | 47 |
6 files changed, 530 insertions, 54 deletions
diff --git a/models/error.go b/models/error.go index 1778701ef6..e608677028 100644 --- a/models/error.go +++ b/models/error.go @@ -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) +} diff --git a/models/issue.go b/models/issue.go index 9d9d3db0a3..e0b72952eb 100644 --- a/models/issue.go +++ b/models/issue.go @@ -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 } } diff --git a/models/pull.go b/models/pull.go index d6df00dc7f..1dde7608f6 100644 --- a/models/pull.go +++ b/models/pull.go @@ -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) } diff --git a/models/repo.go b/models/repo.go index f3eb439cac..c2ed6e012e 100644 --- a/models/repo.go +++ b/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 +} diff --git a/models/wiki.go b/models/wiki.go index 6809c28821..89e9fdaa39 100644 --- a/models/wiki.go +++ b/models/wiki.go @@ -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 diff --git a/models/working_pool.go b/models/working_pool.go new file mode 100644 index 0000000000..c522de56a0 --- /dev/null +++ b/models/working_pool.go @@ -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]-- + } +} |