From b1b6def5bcb016d555e8078af404e8e2fa948748 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Thu, 20 Feb 2014 14:53:56 +0800
Subject: [PATCH] improved ssh supports

---
 conf/app.ini     |  4 ++++
 gogs.go          |  3 +--
 models/models.go |  2 ++
 models/repo.go   | 29 +++++++++++++++++++++--------
 models/user.go   | 23 +++++++++++++++++++++--
 serve.go         | 35 +++++++++++++++++------------------
 6 files changed, 66 insertions(+), 30 deletions(-)

diff --git a/conf/app.ini b/conf/app.ini
index c8953cc5f2..0003ad0325 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -1,4 +1,8 @@
 APP_NAME = Gogs - Go Git Service
+RUN_USER = git
+
+[repository]
+ROOT = /home/git/gogs-repositories
 
 [server]
 HTTP_ADDR = 
diff --git a/gogs.go b/gogs.go
index 63ad3318c7..bf2586d886 100644
--- a/gogs.go
+++ b/gogs.go
@@ -17,7 +17,7 @@ import (
 // Test that go1.1 tag above is included in builds. main.go refers to this definition.
 const go11tag = true
 
-const APP_VER = "0.0.0.0219"
+const APP_VER = "0.0.0.0220"
 
 func init() {
 	runtime.GOMAXPROCS(runtime.NumCPU())
@@ -36,5 +36,4 @@ func main() {
 		cli.BoolFlag{"noterm", "disable color output"},
 	}...)
 	app.Run(os.Args)
-	println("wo cao???")
 }
diff --git a/models/models.go b/models/models.go
index 8341f99616..0f8fcac1a8 100644
--- a/models/models.go
+++ b/models/models.go
@@ -77,6 +77,8 @@ func setEngine() {
 	//x.ShowSQL = true
 
 	log.Trace("Initialized database -> %s", dbName)
+
+	RepoRootPath = utils.Cfg.MustValue("repository", "ROOT")
 }
 
 func init() {
diff --git a/models/repo.go b/models/repo.go
index d48c9a9787..27807303f9 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -11,6 +11,7 @@ import (
 	"time"
 
 	git "github.com/libgit2/git2go"
+	"github.com/qiniu/log"
 )
 
 type Repo struct {
@@ -35,7 +36,7 @@ func IsRepositoryExist(user *User, reposName string) (bool, error) {
 	}
 	s, err := os.Stat(filepath.Join(RepoRootPath, user.Name, reposName))
 	if err != nil {
-		return false, err
+		return false, nil
 	}
 	return s.IsDir(), nil
 }
@@ -44,9 +45,7 @@ func IsRepositoryExist(user *User, reposName string) (bool, error) {
 // create a repository for a user or orgnaziation
 //
 func CreateRepository(user *User, reposName string) (*Repo, error) {
-	p := filepath.Join(RepoRootPath, user.Name)
-	os.MkdirAll(p, os.ModePerm)
-	f := filepath.Join(p, reposName+".git")
+	f := RepoPath(user.Name, reposName)
 	_, err := git.InitRepository(f, false)
 	if err != nil {
 		return nil, err
@@ -58,19 +57,28 @@ func CreateRepository(user *User, reposName string) (*Repo, error) {
 	session.Begin()
 	_, err = session.Insert(&repo)
 	if err != nil {
-		os.RemoveAll(f)
+		err2 := os.RemoveAll(f)
+		if err2 != nil {
+			log.Error("delete repo directory %s/%s failed", user.Name, reposName)
+		}
 		session.Rollback()
 		return nil, err
 	}
 	_, err = session.Exec("update user set num_repos = num_repos + 1 where id = ?", user.Id)
 	if err != nil {
-		os.RemoveAll(f)
+		err2 := os.RemoveAll(f)
+		if err2 != nil {
+			log.Error("delete repo directory %s/%s failed", user.Name, reposName)
+		}
 		session.Rollback()
 		return nil, err
 	}
 	err = session.Commit()
 	if err != nil {
-		os.RemoveAll(f)
+		err2 := os.RemoveAll(f)
+		if err2 != nil {
+			log.Error("delete repo directory %s/%s failed", user.Name, reposName)
+		}
 		session.Rollback()
 		return nil, err
 	}
@@ -100,6 +108,10 @@ func UnWatchRepository() {
 
 }
 
+func RepoPath(userName, repoName string) string {
+	return filepath.Join(UserPath(userName), repoName+".git")
+}
+
 // DeleteRepository deletes a repository for a user or orgnaztion.
 func DeleteRepository(user *User, reposName string) (err error) {
 	session := orm.NewSession()
@@ -115,8 +127,9 @@ func DeleteRepository(user *User, reposName string) (err error) {
 		session.Rollback()
 		return err
 	}
-	if err = os.RemoveAll(filepath.Join(RepoRootPath, user.Name, reposName+".git")); err != nil {
+	if err = os.RemoveAll(RepoPath(user.Name, reposName)); err != nil {
 		// TODO: log and delete manully
+		log.Error("delete repo %s/%s failed", user.Name, reposName)
 		return err
 	}
 	return nil
diff --git a/models/user.go b/models/user.go
index 2527a19774..4618273b3d 100644
--- a/models/user.go
+++ b/models/user.go
@@ -7,12 +7,15 @@ package models
 import (
 	"errors"
 	"fmt"
+	"os"
+	"path/filepath"
 	"strings"
 	"time"
 
 	"github.com/dchest/scrypt"
 
 	"github.com/gogits/gogs/utils"
+	"github.com/gogits/gogs/utils/log"
 )
 
 // User types.
@@ -96,10 +99,22 @@ func RegisterUser(user *User) (err error) {
 
 	user.LowerName = strings.ToLower(user.Name)
 	user.Avatar = utils.EncodeMd5(user.Email)
-	user.Updated = time.Now()
 	user.EncodePasswd()
 	_, err = orm.Insert(user)
-	return err
+	if err != nil {
+		return err
+	}
+
+	err = os.MkdirAll(UserPath(user.Name), os.ModePerm)
+	if err != nil {
+		_, err2 := orm.Id(user.Id).Delete(&User{})
+		if err2 != nil {
+			log.Error("create userpath %s failed and delete table record faild",
+				user.Name)
+		}
+		return err
+	}
+	return nil
 }
 
 // UpdateUser updates user's information.
@@ -129,6 +144,10 @@ func (user *User) EncodePasswd() error {
 	return err
 }
 
+func UserPath(userName string) string {
+	return filepath.Join(RepoRootPath, userName)
+}
+
 func GetUserByKeyId(keyId int64) (*User, error) {
 	user := new(User)
 	has, err := orm.Sql("select a.* from user as a, public_key as b where a.id = b.owner_id and b.id=?", keyId).Get(user)
diff --git a/serve.go b/serve.go
index 066faa30ec..6b4caa1dd7 100644
--- a/serve.go
+++ b/serve.go
@@ -4,7 +4,6 @@ import (
 	"fmt"
 	"os"
 	"os/exec"
-	"path/filepath"
 	"strconv"
 	"strings"
 
@@ -66,16 +65,12 @@ func runServ(*cli.Context) {
 		return
 	}
 
-	f, _ := os.Create("test2.log")
-	f.WriteString(cmd)
-	f.Close()
-
-	log.Info("cmd is %s", cmd)
+	println(cmd)
 
 	verb, args := parseCmd(cmd)
-	rr := strings.SplitN(strings.Trim(args, "'"), "/", 1)
+	rr := strings.SplitN(strings.Trim(args, "'"), "/", 2)
 	if len(rr) != 2 {
-		fmt.Printf("Unavilable repository")
+		println("Unavilable repository", args)
 		return
 	}
 	repoName := rr[1]
@@ -84,6 +79,9 @@ func runServ(*cli.Context) {
 	}
 	isWrite := In(verb, COMMANDS_WRITE)
 	isRead := In(verb, COMMANDS_READONLY)
+
+	println("repoPath:", models.RepoPath(user.Name, repoName))
+
 	switch {
 	case isWrite:
 		has, err := models.HasAccess(user.Name, repoName, COMMANDS_WRITE[verb])
@@ -92,7 +90,7 @@ func runServ(*cli.Context) {
 			return
 		}
 		if !has {
-			fmt.Println("You have no right to access this repository")
+			println("You have no right to access this repository")
 			return
 		}
 	case isRead:
@@ -109,36 +107,36 @@ func runServ(*cli.Context) {
 			}
 		}
 		if !has {
-			fmt.Println("You have no right to access this repository")
+			println("You have no right to access this repository")
 			return
 		}
 	default:
-		fmt.Println("Unknown command")
+		println("Unknown command")
 		return
 	}
 
 	isExist, err := models.IsRepositoryExist(user, repoName)
 	if err != nil {
-		fmt.Println("Inernel error")
+		println("Inernel error:", err.Error())
 		return
 	}
 
 	if !isExist {
 		if isRead {
-			fmt.Println("Repository is not exist")
+			println("Repository", user.Name+"/"+repoName, "is not exist")
 			return
 		} else if isWrite {
 			_, err := models.CreateRepository(user, repoName)
 			if err != nil {
-				fmt.Println("Create repository failed")
+				println("Create repository failed")
 				return
 			}
 		}
 	}
 
-	fullPath := filepath.Join(models.RepoRootPath, user.Name, repoName+".git")
+	fullPath := models.RepoPath(user.Name, repoName)
 	newcmd := fmt.Sprintf("%s '%s'", verb, fullPath)
-	fmt.Println(newcmd)
+	println(newcmd)
 	gitcmd := exec.Command("git", "shell", "-c", newcmd)
 	gitcmd.Stdout = os.Stdout
 	gitcmd.Stderr = os.Stderr
@@ -150,13 +148,14 @@ func runServ(*cli.Context) {
 }
 
 func parseCmd(cmd string) (string, string) {
-	ss := strings.SplitN(cmd, " ", 1)
+	ss := strings.SplitN(cmd, " ", 2)
 	if len(ss) != 2 {
 		return "", ""
 	}
+
 	verb, args := ss[0], ss[1]
 	if verb == "git" {
-		ss = strings.SplitN(args, " ", 1)
+		ss = strings.SplitN(args, " ", 2)
 		args = ss[1]
 		verb = fmt.Sprintf("%s %s", verb, ss[0])
 	}