From 165e3e8f18bb7d38722d0c836ddbf8c95023cf67 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Thu, 26 Jun 2014 21:39:27 +0800
Subject: [PATCH 1/4] path bug fixed

---
 models/repo.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/models/repo.go b/models/repo.go
index d13c349f11..600827344a 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -390,7 +390,7 @@ func CreateRepository(user *User, name, desc, lang, license string, private, mir
 
 // extractGitBareZip extracts git-bare.zip to repository path.
 func extractGitBareZip(repoPath string) error {
-	z, err := zip.Open(path.Join(setting.RepoRootPath, "git-bare.zip"))
+	z, err := zip.Open(filepath.Join(setting.RepoRootPath, "git-bare.zip"))
 	if err != nil {
 		return err
 	}

From e5ae41e21f7fa1e25f04a28d907b89c78196c824 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Sat, 28 Jun 2014 14:55:33 +0800
Subject: [PATCH 2/4] bug fixed #261

---
 models/update.go     | 31 ++++++++++++++++++++++
 routers/repo/http.go | 61 ++++++++++++++++++++++++++++++++++----------
 2 files changed, 79 insertions(+), 13 deletions(-)

diff --git a/models/update.go b/models/update.go
index 5675a94cf4..188e6cb9c7 100644
--- a/models/update.go
+++ b/models/update.go
@@ -16,6 +16,8 @@ import (
 )
 
 func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName string, userId int64) {
+	//fmt.Println(refName, oldCommitId, newCommitId)
+	//fmt.Println(userName, repoUserName, repoName)
 	isNew := strings.HasPrefix(oldCommitId, "0000000")
 	if isNew &&
 		strings.HasPrefix(newCommitId, "0000000") {
@@ -74,11 +76,40 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 		log.GitLogger.Fatal("runUpdate.GetRepositoryByName userId: %v", err)
 	}
 
+	// if tags push
+	if strings.HasPrefix(refName, "refs/tags/") {
+		tagName := git.RefEndName(refName)
+		tag, err := repo.GetTag(tagName)
+		if err != nil {
+			log.GitLogger.Fatal("runUpdate.GetTag: %v", err)
+		}
+
+		var actEmail string
+		if tag.Tagger != nil {
+			actEmail = tag.Tagger.Email
+		} else {
+			cmt, err := tag.Commit()
+			if err != nil {
+				log.GitLogger.Fatal("runUpdate.GetTag Commit: %v", err)
+			}
+			actEmail = cmt.Committer.Email
+		}
+
+		commit := &base.PushCommits{}
+
+		if err = CommitRepoAction(userId, ru.Id, userName, actEmail,
+			repos.Id, repoUserName, repoName, refName, commit); err != nil {
+			log.GitLogger.Fatal("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
+		}
+		return
+	}
+
 	commits := make([]*base.PushCommit, 0)
 	var maxCommits = 3
 	var actEmail string
 	for e := l.Front(); e != nil; e = e.Next() {
 		commit := e.Value.(*git.Commit)
+
 		if actEmail == "" {
 			actEmail = commit.Committer.Email
 		}
diff --git a/routers/repo/http.go b/routers/repo/http.go
index 08bbfc99a5..2f28742bb9 100644
--- a/routers/repo/http.go
+++ b/routers/repo/http.go
@@ -7,6 +7,7 @@ package repo
 import (
 	"bytes"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"net/http"
 	"os"
@@ -130,21 +131,49 @@ func Http(ctx *middleware.Context, params martini.Params) {
 		}
 	}
 
-	config := Config{setting.RepoRootPath, "git", true, true, func(rpc string, input []byte) {
-		if rpc == "receive-pack" {
-			firstLine := bytes.IndexRune(input, '\000')
-			if firstLine > -1 {
-				fields := strings.Fields(string(input[:firstLine]))
-				if len(fields) == 3 {
-					oldCommitId := fields[0][4:]
-					newCommitId := fields[1]
-					refName := fields[2]
+	var f func(rpc string, input []byte)
 
-					models.Update(refName, oldCommitId, newCommitId, authUsername, username, reponame, authUser.Id)
+	f = func(rpc string, input []byte) {
+		if rpc == "receive-pack" {
+			var lastLine int64 = 0
+
+			for {
+				head := input[lastLine : lastLine+2]
+				if head[0] == '0' && head[1] == '0' {
+					size, err := strconv.ParseInt(string(input[lastLine+2:lastLine+4]), 16, 32)
+					if err != nil {
+						log.Error("%v", err)
+						return
+					}
+
+					if size == 0 {
+						//fmt.Println(string(input[lastLine:]))
+						break
+					}
+
+					line := input[lastLine : lastLine+size]
+					idx := bytes.IndexRune(line, '\000')
+					if idx > -1 {
+						line = line[:idx]
+					}
+					fields := strings.Fields(string(line))
+					if len(fields) >= 3 {
+						oldCommitId := fields[0][4:]
+						newCommitId := fields[1]
+						refName := fields[2]
+
+						models.Update(refName, oldCommitId, newCommitId, authUsername, username, reponame, authUser.Id)
+					}
+					lastLine = lastLine + size
+				} else {
+					//fmt.Println("ddddddddddd")
+					break
 				}
 			}
 		}
-	}}
+	}
+
+	config := Config{setting.RepoRootPath, "git", true, true, f}
 
 	handler := HttpBackend(&config)
 	handler(ctx.ResponseWriter, ctx.Req)
@@ -237,8 +266,14 @@ func serviceRpc(rpc string, hr handler) {
 	w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", rpc))
 	w.WriteHeader(http.StatusOK)
 
-	input, _ := ioutil.ReadAll(r.Body)
-	br := bytes.NewReader(input)
+	var input []byte
+	var br io.Reader
+	if hr.Config.OnSucceed != nil {
+		input, _ = ioutil.ReadAll(r.Body)
+		br = bytes.NewReader(input)
+	} else {
+		br = r.Body
+	}
 
 	args := []string{rpc, "--stateless-rpc", dir}
 	cmd := exec.Command(hr.Config.GitBinPath, args...)

From 54e17c7cca15aafc11bf394752ed0f1feb6f6979 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Sat, 28 Jun 2014 15:00:03 +0800
Subject: [PATCH 3/4] bug fixed #261

---
 models/update.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/models/update.go b/models/update.go
index 0231b6af38..6702ad3b46 100644
--- a/models/update.go
+++ b/models/update.go
@@ -100,7 +100,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 			repos.Id, repoUserName, repoName, refName, commit); err != nil {
 			log.GitLogger.Fatal("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
 		}
-		return
+		return err
 	}
 
 	// if commits push

From 1c46d68abaf08890e10386b3af674233b4dda2d3 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Sat, 28 Jun 2014 23:56:41 +0800
Subject: [PATCH 4/4] bug fixed for message tag

---
 cmd/serve.go                  | 25 +++++++++++-
 cmd/update.go                 | 27 +++++++++----
 models/models.go              |  3 +-
 models/update.go              | 76 ++++++++++++++++++++++++-----------
 modules/middleware/context.go |  2 +
 modules/middleware/repo.go    |  7 ++--
 6 files changed, 105 insertions(+), 35 deletions(-)

diff --git a/cmd/serve.go b/cmd/serve.go
index 2a76da7937..351553b91e 100644
--- a/cmd/serve.go
+++ b/cmd/serve.go
@@ -13,6 +13,7 @@ import (
 	"strings"
 
 	"github.com/codegangsta/cli"
+	"github.com/satori/go.uuid"
 
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/log"
@@ -165,7 +166,9 @@ func runServ(k *cli.Context) {
 		return
 	}
 
-	models.SetRepoEnvs(user.Id, user.Name, repoName, repoUserName)
+	//models.SetRepoEnvs(user.Id, user.Name, repoName, repoUserName)
+	uuid := uuid.NewV4().String()
+	os.Setenv("uuid", uuid)
 
 	gitcmd := exec.Command(verb, repoPath)
 	gitcmd.Dir = setting.RepoRootPath
@@ -177,4 +180,24 @@ func runServ(k *cli.Context) {
 		println("Gogs: internal error:", err)
 		log.GitLogger.Fatal("Fail to execute git command: %v", err)
 	}
+
+	if isWrite {
+		tasks, err := models.GetUpdateTasksByUuid(uuid)
+		if err != nil {
+			log.GitLogger.Fatal("Fail to get update task: %v", err)
+		}
+
+		for _, task := range tasks {
+			err = models.Update(task.RefName, task.OldCommitId, task.NewCommitId,
+				user.Name, repoUserName, repoName, user.Id)
+			if err != nil {
+				log.GitLogger.Fatal("Fail to update: %v", err)
+			}
+		}
+
+		err = models.DelUpdateTasksByUuid(uuid)
+		if err != nil {
+			log.GitLogger.Fatal("Fail to del update task: %v", err)
+		}
+	}
 }
diff --git a/cmd/update.go b/cmd/update.go
index c030b6cfb2..551fd09ef3 100644
--- a/cmd/update.go
+++ b/cmd/update.go
@@ -6,10 +6,8 @@ package cmd
 
 import (
 	"os"
-	"strconv"
 
 	"github.com/codegangsta/cli"
-
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/log"
 )
@@ -37,12 +35,27 @@ func runUpdate(c *cli.Context) {
 		log.GitLogger.Fatal("refName is empty, shouldn't use")
 	}
 
-	userName := os.Getenv("userName")
-	userId, _ := strconv.ParseInt(os.Getenv("userId"), 10, 64)
-	repoUserName := os.Getenv("repoUserName")
-	repoName := os.Getenv("repoName")
+	//userName := os.Getenv("userName")
+	//userId, _ := strconv.ParseInt(os.Getenv("userId"), 10, 64)
+	//repoUserName := os.Getenv("repoUserName")
+	//repoName := os.Getenv("repoName")
+	uuid := os.Getenv("uuid")
 
-	if err := models.Update(args[0], args[1], args[2], userName, repoUserName, repoName, userId); err != nil {
+	task := models.UpdateTask{
+		Uuid:        uuid,
+		RefName:     args[0],
+		OldCommitId: args[1],
+		NewCommitId: args[2],
+	}
+
+	log.GitLogger.Error("%v", task)
+
+	if err := models.AddUpdateTask(&task); err != nil {
 		log.GitLogger.Fatal(err.Error())
 	}
+
+	/*if err := models.Update(args[0], args[1], args[2], userName, repoUserName, repoName, userId); err != nil {
+		log.GitLogger.Fatal(err.Error())
+	}*/
+	//setEnvs(args[0], args[1], args[2], userName, repoUserName, repoName, userId)
 }
diff --git a/models/models.go b/models/models.go
index 4e65c00bcb..070784f137 100644
--- a/models/models.go
+++ b/models/models.go
@@ -35,7 +35,8 @@ func init() {
 	tables = append(tables, new(User), new(PublicKey), new(Repository), new(Watch),
 		new(Action), new(Access), new(Issue), new(Comment), new(Oauth2), new(Follow),
 		new(Mirror), new(Release), new(LoginSource), new(Webhook), new(IssueUser),
-		new(Milestone), new(Label), new(HookTask), new(Team), new(OrgUser), new(TeamUser))
+		new(Milestone), new(Label), new(HookTask), new(Team), new(OrgUser), new(TeamUser),
+		new(UpdateTask))
 }
 
 func LoadModelsConfig() {
diff --git a/models/update.go b/models/update.go
index 6702ad3b46..cf7f5d2a79 100644
--- a/models/update.go
+++ b/models/update.go
@@ -16,6 +16,36 @@ import (
 	"github.com/gogits/gogs/modules/log"
 )
 
+type UpdateTask struct {
+	Id          int64
+	Uuid        string `xorm:"index"`
+	RefName     string
+	OldCommitId string
+	NewCommitId string
+}
+
+func AddUpdateTask(task *UpdateTask) error {
+	_, err := x.Insert(task)
+	return err
+}
+
+func GetUpdateTasksByUuid(uuid string) ([]*UpdateTask, error) {
+	task := &UpdateTask{
+		Uuid: uuid,
+	}
+	tasks := make([]*UpdateTask, 0)
+	err := x.Find(&tasks, task)
+	if err != nil {
+		return nil, err
+	}
+	return tasks, nil
+}
+
+func DelUpdateTasksByUuid(uuid string) error {
+	_, err := x.Delete(&UpdateTask{Uuid: uuid})
+	return err
+}
+
 func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName string, userId int64) error {
 	//fmt.Println(refName, oldCommitId, newCommitId)
 	//fmt.Println(userName, repoUserName, repoName)
@@ -42,29 +72,6 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 		return fmt.Errorf("runUpdate.Open repoId: %v", err)
 	}
 
-	newCommit, err := repo.GetCommit(newCommitId)
-	if err != nil {
-		return fmt.Errorf("runUpdate GetCommit of newCommitId: %v", err)
-	}
-
-	var l *list.List
-	// if a new branch
-	if isNew {
-		l, err = newCommit.CommitsBefore()
-		if err != nil {
-			return fmt.Errorf("Find CommitsBefore erro: %v", err)
-		}
-	} else {
-		l, err = newCommit.CommitsBeforeUntil(oldCommitId)
-		if err != nil {
-			return fmt.Errorf("Find CommitsBeforeUntil erro: %v", err)
-		}
-	}
-
-	if err != nil {
-		return fmt.Errorf("runUpdate.Commit repoId: %v", err)
-	}
-
 	ru, err := GetUserByName(repoUserName)
 	if err != nil {
 		return fmt.Errorf("runUpdate.GetUserByName: %v", err)
@@ -103,6 +110,29 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 		return err
 	}
 
+	newCommit, err := repo.GetCommit(newCommitId)
+	if err != nil {
+		return fmt.Errorf("runUpdate GetCommit of newCommitId: %v", err)
+	}
+
+	var l *list.List
+	// if a new branch
+	if isNew {
+		l, err = newCommit.CommitsBefore()
+		if err != nil {
+			return fmt.Errorf("Find CommitsBefore erro: %v", err)
+		}
+	} else {
+		l, err = newCommit.CommitsBeforeUntil(oldCommitId)
+		if err != nil {
+			return fmt.Errorf("Find CommitsBeforeUntil erro: %v", err)
+		}
+	}
+
+	if err != nil {
+		return fmt.Errorf("runUpdate.Commit repoId: %v", err)
+	}
+
 	// if commits push
 	commits := make([]*base.PushCommit, 0)
 	var maxCommits = 3
diff --git a/modules/middleware/context.go b/modules/middleware/context.go
index 45f0140a28..8e7ac4209e 100644
--- a/modules/middleware/context.go
+++ b/modules/middleware/context.go
@@ -56,8 +56,10 @@ type Context struct {
 		Repository *models.Repository
 		Owner      *models.User
 		Commit     *git.Commit
+		Tag        *git.Tag
 		GitRepo    *git.Repository
 		BranchName string
+		TagName    string
 		CommitId   string
 		RepoLink   string
 		CloneLink  struct {
diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go
index 0c64027552..7ba211c71f 100644
--- a/modules/middleware/repo.go
+++ b/modules/middleware/repo.go
@@ -185,16 +185,16 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler {
 					ctx.Repo.CommitId = ctx.Repo.Commit.Id.String()
 
 				} else if gitRepo.IsTagExist(refName) {
-					ctx.Repo.IsBranch = true
+					ctx.Repo.IsTag = true
 					ctx.Repo.BranchName = refName
 
-					ctx.Repo.Commit, err = gitRepo.GetCommitOfTag(refName)
+					ctx.Repo.Tag, err = gitRepo.GetTag(refName)
 					if err != nil {
 						ctx.Handle(404, "RepoAssignment invalid tag", nil)
 						return
 					}
+					ctx.Repo.Commit, _ = ctx.Repo.Tag.Commit()
 					ctx.Repo.CommitId = ctx.Repo.Commit.Id.String()
-
 				} else if len(refName) == 40 {
 					ctx.Repo.IsCommit = true
 					ctx.Repo.CommitId = refName
@@ -244,6 +244,7 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler {
 		}
 
 		ctx.Data["BranchName"] = ctx.Repo.BranchName
+		ctx.Data["TagName"] = ctx.Repo.TagName
 		brs, err := ctx.Repo.GitRepo.GetBranches()
 		if err != nil {
 			log.Error("RepoAssignment(GetBranches): %v", err)