| 
									
										
										
										
											2014-02-14 18:16:54 -05:00
										 |  |  | // Copyright 2014 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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | package models | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2014-03-10 20:48:58 -04:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2014-03-11 12:18:44 +08:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2014-03-23 19:53:50 +08:00
										 |  |  | 	"os/exec" | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2014-03-20 11:41:24 -04:00
										 |  |  | 	"regexp" | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2014-03-11 00:53:53 -04:00
										 |  |  | 	"unicode/utf8" | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 	"github.com/Unknwon/cae/zip" | 
					
						
							| 
									
										
										
										
											2014-03-11 01:32:36 -04:00
										 |  |  | 	"github.com/Unknwon/com" | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/gogits/git" | 
					
						
							| 
									
										
										
										
											2014-03-07 17:22:15 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-11 01:32:36 -04:00
										 |  |  | 	"github.com/gogits/gogs/modules/base" | 
					
						
							| 
									
										
										
										
											2014-03-07 17:22:15 -05:00
										 |  |  | 	"github.com/gogits/gogs/modules/log" | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-11 01:32:36 -04:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | 	ErrRepoAlreadyExist  = errors.New("Repository already exist") | 
					
						
							|  |  |  | 	ErrRepoNotExist      = errors.New("Repository does not exist") | 
					
						
							|  |  |  | 	ErrRepoFileNotExist  = errors.New("Target Repo file does not exist") | 
					
						
							|  |  |  | 	ErrRepoNameIllegal   = errors.New("Repository name contains illegal characters") | 
					
						
							|  |  |  | 	ErrRepoFileNotLoaded = fmt.Errorf("repo file not loaded") | 
					
						
							| 
									
										
										
										
											2014-03-11 01:32:36 -04:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | 	LanguageIgns, Licenses []string | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-21 01:48:10 -04:00
										 |  |  | func LoadRepoConfig() { | 
					
						
							| 
									
										
										
										
											2014-03-11 01:32:36 -04:00
										 |  |  | 	LanguageIgns = strings.Split(base.Cfg.MustValue("repository", "LANG_IGNS"), "|") | 
					
						
							|  |  |  | 	Licenses = strings.Split(base.Cfg.MustValue("repository", "LICENSES"), "|") | 
					
						
							| 
									
										
										
										
											2014-03-21 01:48:10 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-21 01:48:10 -04:00
										 |  |  | func NewRepoContext() { | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 	zip.Verbose = false | 
					
						
							| 
									
										
										
										
											2014-03-17 15:58:32 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check if server has basic git setting. | 
					
						
							|  |  |  | 	stdout, _, err := com.ExecCmd("git", "config", "--get", "user.name") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		fmt.Printf("repo.init(fail to get git user.name): %v", err) | 
					
						
							|  |  |  | 		os.Exit(2) | 
					
						
							|  |  |  | 	} else if len(stdout) == 0 { | 
					
						
							|  |  |  | 		if _, _, err = com.ExecCmd("git", "config", "--global", "user.email", "gogitservice@gmail.com"); err != nil { | 
					
						
							|  |  |  | 			fmt.Printf("repo.init(fail to set git user.email): %v", err) | 
					
						
							|  |  |  | 			os.Exit(2) | 
					
						
							|  |  |  | 		} else if _, _, err = com.ExecCmd("git", "config", "--global", "user.name", "Gogs"); err != nil { | 
					
						
							|  |  |  | 			fmt.Printf("repo.init(fail to set git user.name): %v", err) | 
					
						
							|  |  |  | 			os.Exit(2) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-20 11:41:24 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize illegal patterns. | 
					
						
							|  |  |  | 	for i := range illegalPatterns[1:] { | 
					
						
							|  |  |  | 		pattern := "" | 
					
						
							|  |  |  | 		for j := range illegalPatterns[i+1] { | 
					
						
							|  |  |  | 			pattern += "[" + string(illegalPatterns[i+1][j]-32) + string(illegalPatterns[i+1][j]) + "]" | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		illegalPatterns[i+1] = pattern | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-11 01:32:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | // Repository represents a git repository. | 
					
						
							|  |  |  | type Repository struct { | 
					
						
							| 
									
										
										
										
											2014-03-27 12:48:29 -04:00
										 |  |  | 	Id              int64 | 
					
						
							|  |  |  | 	OwnerId         int64 `xorm:"unique(s)"` | 
					
						
							|  |  |  | 	ForkId          int64 | 
					
						
							|  |  |  | 	LowerName       string `xorm:"unique(s) index not null"` | 
					
						
							|  |  |  | 	Name            string `xorm:"index not null"` | 
					
						
							|  |  |  | 	Description     string | 
					
						
							|  |  |  | 	Website         string | 
					
						
							|  |  |  | 	NumWatches      int | 
					
						
							|  |  |  | 	NumStars        int | 
					
						
							|  |  |  | 	NumForks        int | 
					
						
							|  |  |  | 	NumIssues       int | 
					
						
							|  |  |  | 	NumClosedIssues int | 
					
						
							| 
									
										
										
										
											2014-03-27 16:31:32 -04:00
										 |  |  | 	NumOpenIssues   int `xorm:"-"` | 
					
						
							| 
									
										
										
										
											2014-03-27 12:48:29 -04:00
										 |  |  | 	IsPrivate       bool | 
					
						
							|  |  |  | 	IsBare          bool | 
					
						
							|  |  |  | 	Created         time.Time `xorm:"created"` | 
					
						
							|  |  |  | 	Updated         time.Time `xorm:"updated"` | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | // IsRepositoryExist returns true if the repository with given name under user has already existed. | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | func IsRepositoryExist(user *User, repoName string) (bool, error) { | 
					
						
							|  |  |  | 	repo := Repository{OwnerId: user.Id} | 
					
						
							|  |  |  | 	has, err := orm.Where("lower_name = ?", strings.ToLower(repoName)).Get(&repo) | 
					
						
							| 
									
										
										
										
											2014-02-19 17:50:53 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return has, err | 
					
						
							| 
									
										
										
										
											2014-03-27 15:24:11 -04:00
										 |  |  | 	} else if !has { | 
					
						
							|  |  |  | 		return false, nil | 
					
						
							| 
									
										
										
										
											2014-02-19 17:50:53 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-27 15:24:11 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return com.IsDir(RepoPath(user.Name, repoName)), nil | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 11:41:24 -04:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	// Define as all lower case!! | 
					
						
							| 
									
										
										
										
											2014-03-27 07:26:03 -04:00
										 |  |  | 	illegalPatterns = []string{"[.][Gg][Ii][Tt]", "raw", "user", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"} | 
					
						
							| 
									
										
										
										
											2014-03-20 11:41:24 -04:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // IsLegalName returns false if name contains illegal characters. | 
					
						
							|  |  |  | func IsLegalName(repoName string) bool { | 
					
						
							|  |  |  | 	for _, pattern := range illegalPatterns { | 
					
						
							|  |  |  | 		has, _ := regexp.MatchString(pattern, repoName) | 
					
						
							|  |  |  | 		if has { | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-07 17:08:21 -05:00
										 |  |  | // CreateRepository creates a repository for given user or orgnaziation. | 
					
						
							| 
									
										
										
										
											2014-03-11 01:32:36 -04:00
										 |  |  | func CreateRepository(user *User, repoName, desc, repoLang, license string, private bool, initReadme bool) (*Repository, error) { | 
					
						
							| 
									
										
										
										
											2014-03-20 11:41:24 -04:00
										 |  |  | 	if !IsLegalName(repoName) { | 
					
						
							|  |  |  | 		return nil, ErrRepoNameIllegal | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | 	isExist, err := IsRepositoryExist(user, repoName) | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | 	} else if isExist { | 
					
						
							|  |  |  | 		return nil, ErrRepoAlreadyExist | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	repo := &Repository{ | 
					
						
							|  |  |  | 		OwnerId:     user.Id, | 
					
						
							|  |  |  | 		Name:        repoName, | 
					
						
							|  |  |  | 		LowerName:   strings.ToLower(repoName), | 
					
						
							|  |  |  | 		Description: desc, | 
					
						
							| 
									
										
										
										
											2014-03-22 11:59:14 -04:00
										 |  |  | 		IsPrivate:   private, | 
					
						
							|  |  |  | 		IsBare:      repoLang == "" && license == "" && !initReadme, | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-11 00:53:53 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | 	repoPath := RepoPath(user.Name, repoName) | 
					
						
							|  |  |  | 	if err = initRepository(repoPath, user, repo, initReadme, repoLang, license); err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-11 00:53:53 -04:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | 	session := orm.NewSession() | 
					
						
							|  |  |  | 	defer session.Close() | 
					
						
							|  |  |  | 	session.Begin() | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if _, err = session.Insert(repo); err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | 		if err2 := os.RemoveAll(repoPath); err2 != nil { | 
					
						
							|  |  |  | 			log.Error("repo.CreateRepository(repo): %v", err) | 
					
						
							| 
									
										
										
										
											2014-03-10 20:48:58 -04:00
										 |  |  | 			return nil, errors.New(fmt.Sprintf( | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | 				"delete repo directory %s/%s failed(1): %v", user.Name, repoName, err2)) | 
					
						
							| 
									
										
										
										
											2014-02-20 14:53:56 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | 		session.Rollback() | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	access := Access{ | 
					
						
							|  |  |  | 		UserName: user.Name, | 
					
						
							| 
									
										
										
										
											2014-02-25 15:11:54 +08:00
										 |  |  | 		RepoName: repo.Name, | 
					
						
							|  |  |  | 		Mode:     AU_WRITABLE, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | 	if _, err = session.Insert(&access); err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-11 12:18:44 +08:00
										 |  |  | 		session.Rollback() | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | 		if err2 := os.RemoveAll(repoPath); err2 != nil { | 
					
						
							|  |  |  | 			log.Error("repo.CreateRepository(access): %v", err) | 
					
						
							| 
									
										
										
										
											2014-03-10 20:48:58 -04:00
										 |  |  | 			return nil, errors.New(fmt.Sprintf( | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | 				"delete repo directory %s/%s failed(2): %v", user.Name, repoName, err2)) | 
					
						
							| 
									
										
										
										
											2014-02-25 15:11:54 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-19 15:46:16 +08:00
										 |  |  | 	rawSql := "UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?" | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | 	if _, err = session.Exec(rawSql, user.Id); err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-11 12:18:44 +08:00
										 |  |  | 		session.Rollback() | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | 		if err2 := os.RemoveAll(repoPath); err2 != nil { | 
					
						
							|  |  |  | 			log.Error("repo.CreateRepository(repo count): %v", err) | 
					
						
							| 
									
										
										
										
											2014-03-10 20:48:58 -04:00
										 |  |  | 			return nil, errors.New(fmt.Sprintf( | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | 				"delete repo directory %s/%s failed(3): %v", user.Name, repoName, err2)) | 
					
						
							| 
									
										
										
										
											2014-02-20 14:53:56 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if err = session.Commit(); err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-11 12:18:44 +08:00
										 |  |  | 		session.Rollback() | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | 		if err2 := os.RemoveAll(repoPath); err2 != nil { | 
					
						
							|  |  |  | 			log.Error("repo.CreateRepository(commit): %v", err) | 
					
						
							| 
									
										
										
										
											2014-03-10 20:48:58 -04:00
										 |  |  | 			return nil, errors.New(fmt.Sprintf( | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | 				"delete repo directory %s/%s failed(3): %v", user.Name, repoName, err2)) | 
					
						
							| 
									
										
										
										
											2014-02-20 14:53:56 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-13 13:14:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-23 19:53:50 +08:00
										 |  |  | 	c := exec.Command("git", "update-server-info") | 
					
						
							| 
									
										
										
										
											2014-03-23 20:04:26 +08:00
										 |  |  | 	c.Dir = repoPath | 
					
						
							| 
									
										
										
										
											2014-03-23 19:53:50 +08:00
										 |  |  | 	err = c.Run() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		log.Error("repo.CreateRepository(exec update-server-info): %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-13 13:14:43 +08:00
										 |  |  | 	return repo, NewRepoAction(user, repo) | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // extractGitBareZip extracts git-bare.zip to repository path. | 
					
						
							|  |  |  | func extractGitBareZip(repoPath string) error { | 
					
						
							|  |  |  | 	z, err := zip.Open("conf/content/git-bare.zip") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		fmt.Println("shi?") | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer z.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return z.ExtractTo(repoPath) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // initRepoCommit temporarily changes with work directory. | 
					
						
							| 
									
										
										
										
											2014-03-25 23:53:01 -04:00
										 |  |  | func initRepoCommit(tmpPath string, sig *git.Signature) (err error) { | 
					
						
							| 
									
										
										
										
											2014-03-17 15:58:32 -04:00
										 |  |  | 	var stderr string | 
					
						
							| 
									
										
										
										
											2014-03-25 23:53:01 -04:00
										 |  |  | 	if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "add", "--all"); err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-27 15:24:11 -04:00
										 |  |  | 	if len(stderr) > 0 { | 
					
						
							|  |  |  | 		log.Trace("stderr(1): %s", stderr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-25 23:53:01 -04:00
										 |  |  | 	if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 		"-m", "Init commit"); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-27 15:24:11 -04:00
										 |  |  | 	if len(stderr) > 0 { | 
					
						
							|  |  |  | 		log.Trace("stderr(2): %s", stderr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-25 23:53:01 -04:00
										 |  |  | 	if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "push", "origin", "master"); err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-27 15:24:11 -04:00
										 |  |  | 	if len(stderr) > 0 { | 
					
						
							|  |  |  | 		log.Trace("stderr(3): %s", stderr) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-26 09:40:02 -04:00
										 |  |  | func createHookUpdate(hookPath, content string) error { | 
					
						
							|  |  |  | 	pu, err := os.OpenFile(hookPath, os.O_CREATE|os.O_WRONLY, 0777) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer pu.Close() | 
					
						
							| 
									
										
										
										
											2014-03-27 15:24:11 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	_, err = pu.WriteString(content) | 
					
						
							|  |  |  | 	return err | 
					
						
							| 
									
										
										
										
											2014-03-26 09:40:02 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-10 20:48:58 -04:00
										 |  |  | // InitRepository initializes README and .gitignore if needed. | 
					
						
							| 
									
										
										
										
											2014-03-11 01:32:36 -04:00
										 |  |  | func initRepository(f string, user *User, repo *Repository, initReadme bool, repoLang, license string) error { | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 	repoPath := RepoPath(user.Name, repo.Name) | 
					
						
							| 
									
										
										
										
											2014-03-11 18:10:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 	// Create bare new repository. | 
					
						
							|  |  |  | 	if err := extractGitBareZip(repoPath); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 17:00:35 -04:00
										 |  |  | 	// hook/post-update | 
					
						
							| 
									
										
										
										
											2014-03-26 09:40:02 -04:00
										 |  |  | 	if err := createHookUpdate(filepath.Join(repoPath, "hooks", "update"), | 
					
						
							|  |  |  | 		fmt.Sprintf("#!/usr/bin/env bash\n%s update $1 $2 $3\n", | 
					
						
							|  |  |  | 			strings.Replace(appPath, "\\", "/", -1))); err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-17 17:00:35 -04:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 	// Initialize repository according to user's choice. | 
					
						
							|  |  |  | 	fileName := map[string]string{} | 
					
						
							| 
									
										
										
										
											2014-03-11 18:10:19 +08:00
										 |  |  | 	if initReadme { | 
					
						
							|  |  |  | 		fileName["readme"] = "README.md" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if repoLang != "" { | 
					
						
							|  |  |  | 		fileName["gitign"] = ".gitignore" | 
					
						
							| 
									
										
										
										
											2014-03-11 00:53:53 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-11 18:10:19 +08:00
										 |  |  | 	if license != "" { | 
					
						
							|  |  |  | 		fileName["license"] = "LICENSE" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 	// Clone to temprory path and do the init commit. | 
					
						
							|  |  |  | 	tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond())) | 
					
						
							|  |  |  | 	os.MkdirAll(tmpDir, os.ModePerm) | 
					
						
							| 
									
										
										
										
											2014-03-11 12:18:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 	if _, _, err := com.ExecCmd("git", "clone", repoPath, tmpDir); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-11 12:18:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// README | 
					
						
							| 
									
										
										
										
											2014-03-11 18:10:19 +08:00
										 |  |  | 	if initReadme { | 
					
						
							|  |  |  | 		defaultReadme := repo.Name + "\n" + strings.Repeat("=", | 
					
						
							|  |  |  | 			utf8.RuneCountInString(repo.Name)) + "\n\n" + repo.Description | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 		if err := ioutil.WriteFile(filepath.Join(tmpDir, fileName["readme"]), | 
					
						
							| 
									
										
										
										
											2014-03-11 18:10:19 +08:00
										 |  |  | 			[]byte(defaultReadme), 0644); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-03-11 12:18:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-10 20:48:58 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 	// .gitignore | 
					
						
							| 
									
										
										
										
											2014-03-11 18:10:19 +08:00
										 |  |  | 	if repoLang != "" { | 
					
						
							|  |  |  | 		filePath := "conf/gitignore/" + repoLang | 
					
						
							|  |  |  | 		if com.IsFile(filePath) { | 
					
						
							|  |  |  | 			if _, err := com.Copy(filePath, | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 				filepath.Join(tmpDir, fileName["gitign"])); err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-11 18:10:19 +08:00
										 |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-03-11 01:32:36 -04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-11 00:53:53 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 	// LICENSE | 
					
						
							| 
									
										
										
										
											2014-03-11 18:10:19 +08:00
										 |  |  | 	if license != "" { | 
					
						
							|  |  |  | 		filePath := "conf/license/" + license | 
					
						
							|  |  |  | 		if com.IsFile(filePath) { | 
					
						
							|  |  |  | 			if _, err := com.Copy(filePath, | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 				filepath.Join(tmpDir, fileName["license"])); err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-11 18:10:19 +08:00
										 |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-03-11 01:32:36 -04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-11 12:18:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 17:00:35 -04:00
										 |  |  | 	if len(fileName) == 0 { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 11:56:50 -04:00
										 |  |  | 	// Apply changes and commit. | 
					
						
							| 
									
										
										
										
											2014-03-27 15:24:11 -04:00
										 |  |  | 	return initRepoCommit(tmpDir, user.NewGitSig()) | 
					
						
							| 
									
										
										
										
											2014-03-10 20:48:58 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-21 01:09:22 -04:00
										 |  |  | // UserRepo reporesents a repository with user name. | 
					
						
							|  |  |  | type UserRepo struct { | 
					
						
							|  |  |  | 	*Repository | 
					
						
							|  |  |  | 	UserName string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | // GetRepos returns given number of repository objects with offset. | 
					
						
							| 
									
										
										
										
											2014-03-21 01:09:22 -04:00
										 |  |  | func GetRepos(num, offset int) ([]UserRepo, error) { | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | 	repos := make([]Repository, 0, num) | 
					
						
							| 
									
										
										
										
											2014-03-21 01:09:22 -04:00
										 |  |  | 	if err := orm.Limit(num, offset).Asc("id").Find(&repos); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	urepos := make([]UserRepo, len(repos)) | 
					
						
							|  |  |  | 	for i := range repos { | 
					
						
							|  |  |  | 		urepos[i].Repository = &repos[i] | 
					
						
							|  |  |  | 		u := new(User) | 
					
						
							|  |  |  | 		has, err := orm.Id(urepos[i].Repository.OwnerId).Get(u) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} else if !has { | 
					
						
							|  |  |  | 			return nil, ErrUserNotExist | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		urepos[i].UserName = u.Name | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return urepos, nil | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func RepoPath(userName, repoName string) string { | 
					
						
							|  |  |  | 	return filepath.Join(UserPath(userName), repoName+".git") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-22 04:44:57 -04:00
										 |  |  | func UpdateRepository(repo *Repository) error { | 
					
						
							| 
									
										
										
										
											2014-03-22 16:00:46 -04:00
										 |  |  | 	if len(repo.Description) > 255 { | 
					
						
							|  |  |  | 		repo.Description = repo.Description[:255] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(repo.Website) > 255 { | 
					
						
							|  |  |  | 		repo.Website = repo.Website[:255] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-24 09:01:25 -04:00
										 |  |  | 	_, err := orm.Id(repo.Id).AllCols().Update(repo) | 
					
						
							| 
									
										
										
										
											2014-03-22 04:44:57 -04:00
										 |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | // DeleteRepository deletes a repository for a user or orgnaztion. | 
					
						
							|  |  |  | func DeleteRepository(userId, repoId int64, userName string) (err error) { | 
					
						
							|  |  |  | 	repo := &Repository{Id: repoId, OwnerId: userId} | 
					
						
							|  |  |  | 	has, err := orm.Get(repo) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} else if !has { | 
					
						
							|  |  |  | 		return ErrRepoNotExist | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	session := orm.NewSession() | 
					
						
							|  |  |  | 	if err = session.Begin(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err = session.Delete(&Repository{Id: repoId}); err != nil { | 
					
						
							|  |  |  | 		session.Rollback() | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err := session.Delete(&Access{UserName: userName, RepoName: repo.Name}); err != nil { | 
					
						
							|  |  |  | 		session.Rollback() | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	rawSql := "UPDATE `user` SET num_repos = num_repos - 1 WHERE id = ?" | 
					
						
							|  |  |  | 	if _, err = session.Exec(rawSql, userId); err != nil { | 
					
						
							|  |  |  | 		session.Rollback() | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err = session.Delete(&Watch{RepoId: repoId}); err != nil { | 
					
						
							|  |  |  | 		session.Rollback() | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err = session.Commit(); err != nil { | 
					
						
							|  |  |  | 		session.Rollback() | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err = os.RemoveAll(RepoPath(userName, repo.Name)); err != nil { | 
					
						
							|  |  |  | 		// TODO: log and delete manully | 
					
						
							|  |  |  | 		log.Error("delete repo %s/%s failed: %v", userName, repo.Name, err) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | // GetRepositoryByName returns the repository by given name under user if exists. | 
					
						
							| 
									
										
										
										
											2014-03-22 04:44:57 -04:00
										 |  |  | func GetRepositoryByName(userId int64, repoName string) (*Repository, error) { | 
					
						
							| 
									
										
										
										
											2014-03-12 22:27:11 -04:00
										 |  |  | 	repo := &Repository{ | 
					
						
							| 
									
										
										
										
											2014-03-22 04:44:57 -04:00
										 |  |  | 		OwnerId:   userId, | 
					
						
							| 
									
										
										
										
											2014-03-12 22:27:11 -04:00
										 |  |  | 		LowerName: strings.ToLower(repoName), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	has, err := orm.Get(repo) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} else if !has { | 
					
						
							|  |  |  | 		return nil, ErrRepoNotExist | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return repo, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | // GetRepositoryById returns the repository by given id if exists. | 
					
						
							| 
									
										
										
										
											2014-03-27 19:42:10 -04:00
										 |  |  | func GetRepositoryById(id int64) (*Repository, error) { | 
					
						
							|  |  |  | 	repo := &Repository{} | 
					
						
							| 
									
										
										
										
											2014-03-12 22:27:11 -04:00
										 |  |  | 	has, err := orm.Id(id).Get(repo) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} else if !has { | 
					
						
							|  |  |  | 		return nil, ErrRepoNotExist | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return repo, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 13:04:31 -05:00
										 |  |  | // GetRepositories returns the list of repositories of given user. | 
					
						
							| 
									
										
										
										
											2014-03-09 20:06:29 -04:00
										 |  |  | func GetRepositories(user *User) ([]Repository, error) { | 
					
						
							|  |  |  | 	repos := make([]Repository, 0, 10) | 
					
						
							| 
									
										
										
										
											2014-03-16 02:28:24 -04:00
										 |  |  | 	err := orm.Desc("updated").Find(&repos, &Repository{OwnerId: user.Id}) | 
					
						
							| 
									
										
										
										
											2014-02-14 22:20:57 +08:00
										 |  |  | 	return repos, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-11 14:17:05 +08:00
										 |  |  | func GetRepositoryCount(user *User) (int64, error) { | 
					
						
							|  |  |  | 	return orm.Count(&Repository{OwnerId: user.Id}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | // Watch is connection request for receiving repository notifycation. | 
					
						
							|  |  |  | type Watch struct { | 
					
						
							|  |  |  | 	Id     int64 | 
					
						
							|  |  |  | 	RepoId int64 `xorm:"UNIQUE(watch)"` | 
					
						
							|  |  |  | 	UserId int64 `xorm:"UNIQUE(watch)"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Watch or unwatch repository. | 
					
						
							|  |  |  | func WatchRepo(userId, repoId int64, watch bool) (err error) { | 
					
						
							|  |  |  | 	if watch { | 
					
						
							| 
									
										
										
										
											2014-03-20 16:14:50 -04:00
										 |  |  | 		if _, err = orm.Insert(&Watch{RepoId: repoId, UserId: userId}); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		rawSql := "UPDATE `repository` SET num_watches = num_watches + 1 WHERE id = ?" | 
					
						
							|  |  |  | 		_, err = orm.Exec(rawSql, repoId) | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2014-03-20 16:14:50 -04:00
										 |  |  | 		if _, err = orm.Delete(&Watch{0, repoId, userId}); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		rawSql := "UPDATE `repository` SET num_watches = num_watches - 1 WHERE id = ?" | 
					
						
							|  |  |  | 		_, err = orm.Exec(rawSql, repoId) | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetWatches returns all watches of given repository. | 
					
						
							|  |  |  | func GetWatches(repoId int64) ([]Watch, error) { | 
					
						
							|  |  |  | 	watches := make([]Watch, 0, 10) | 
					
						
							|  |  |  | 	err := orm.Find(&watches, &Watch{RepoId: repoId}) | 
					
						
							|  |  |  | 	return watches, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-25 14:04:57 -04:00
										 |  |  | // NotifyWatchers creates batch of actions for every watcher. | 
					
						
							| 
									
										
										
										
											2014-03-27 11:37:33 -04:00
										 |  |  | func NotifyWatchers(act *Action) error { | 
					
						
							| 
									
										
										
										
											2014-03-25 14:04:57 -04:00
										 |  |  | 	// Add feeds for user self and all watchers. | 
					
						
							| 
									
										
										
										
											2014-03-27 11:37:33 -04:00
										 |  |  | 	watches, err := GetWatches(act.RepoId) | 
					
						
							| 
									
										
										
										
											2014-03-20 13:31:24 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-25 14:04:57 -04:00
										 |  |  | 		return errors.New("repo.NotifyWatchers(get watches): " + err.Error()) | 
					
						
							| 
									
										
										
										
											2014-03-20 13:31:24 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-27 12:48:29 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Add feed for actioner. | 
					
						
							|  |  |  | 	act.UserId = act.ActUserId | 
					
						
							|  |  |  | 	if _, err = orm.InsertOne(act); err != nil { | 
					
						
							|  |  |  | 		return errors.New("repo.NotifyWatchers(create action): " + err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-20 13:31:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-25 14:04:57 -04:00
										 |  |  | 	for i := range watches { | 
					
						
							| 
									
										
										
										
											2014-03-27 12:48:29 -04:00
										 |  |  | 		if act.ActUserId == watches[i].UserId { | 
					
						
							|  |  |  | 			continue | 
					
						
							| 
									
										
										
										
											2014-03-20 13:31:24 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-28 09:06:48 -04:00
										 |  |  | 		act.Id = 0 | 
					
						
							| 
									
										
										
										
											2014-03-27 11:37:33 -04:00
										 |  |  | 		act.UserId = watches[i].UserId | 
					
						
							|  |  |  | 		if _, err = orm.InsertOne(act); err != nil { | 
					
						
							| 
									
										
										
										
											2014-03-25 14:04:57 -04:00
										 |  |  | 			return errors.New("repo.NotifyWatchers(create action): " + err.Error()) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-03-20 13:31:24 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-03-25 14:04:57 -04:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2014-03-20 13:31:24 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-20 16:04:56 -04:00
										 |  |  | // IsWatching checks if user has watched given repository. | 
					
						
							|  |  |  | func IsWatching(userId, repoId int64) bool { | 
					
						
							|  |  |  | 	has, _ := orm.Get(&Watch{0, repoId, userId}) | 
					
						
							|  |  |  | 	return has | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-02 21:58:20 +08:00
										 |  |  | func ForkRepository(reposName string, userId int64) { | 
					
						
							| 
									
										
										
										
											2014-03-18 11:22:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-17 14:03:58 -04:00
										 |  |  | } |