You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

332 lines
7.6 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "errors"
  7. "fmt"
  8. "io/ioutil"
  9. "os"
  10. "path/filepath"
  11. "strings"
  12. "time"
  13. "unicode/utf8"
  14. "github.com/Unknwon/com"
  15. git "github.com/libgit2/git2go"
  16. "github.com/gogits/gogs/modules/base"
  17. "github.com/gogits/gogs/modules/log"
  18. )
  19. type Repository struct {
  20. Id int64
  21. OwnerId int64 `xorm:"unique(s)"`
  22. ForkId int64
  23. LowerName string `xorm:"unique(s) index not null"`
  24. Name string `xorm:"index not null"`
  25. Description string
  26. Private bool
  27. NumWatchs int
  28. NumStars int
  29. NumForks int
  30. Created time.Time `xorm:"created"`
  31. Updated time.Time `xorm:"updated"`
  32. }
  33. type Star struct {
  34. Id int64
  35. RepoId int64
  36. UserId int64
  37. Created time.Time `xorm:"created"`
  38. }
  39. var (
  40. LanguageIgns, Licenses []string
  41. )
  42. var (
  43. ErrRepoAlreadyExist = errors.New("Repository already exist")
  44. ErrRepoNotExist = errors.New("Repository does not exist")
  45. )
  46. func init() {
  47. LanguageIgns = strings.Split(base.Cfg.MustValue("repository", "LANG_IGNS"), "|")
  48. Licenses = strings.Split(base.Cfg.MustValue("repository", "LICENSES"), "|")
  49. }
  50. // check if repository is exist
  51. func IsRepositoryExist(user *User, repoName string) (bool, error) {
  52. repo := Repository{OwnerId: user.Id}
  53. has, err := orm.Where("lower_name = ?", strings.ToLower(repoName)).Get(&repo)
  54. if err != nil {
  55. return has, err
  56. }
  57. s, err := os.Stat(RepoPath(user.Name, repoName))
  58. if err != nil {
  59. return false, nil
  60. }
  61. return s.IsDir(), nil
  62. }
  63. // CreateRepository creates a repository for given user or orgnaziation.
  64. func CreateRepository(user *User, repoName, desc, repoLang, license string, private bool, initReadme bool) (*Repository, error) {
  65. isExist, err := IsRepositoryExist(user, repoName)
  66. if err != nil {
  67. return nil, err
  68. } else if isExist {
  69. return nil, ErrRepoAlreadyExist
  70. }
  71. repo := &Repository{
  72. OwnerId: user.Id,
  73. Name: repoName,
  74. LowerName: strings.ToLower(repoName),
  75. Description: desc,
  76. Private: private,
  77. }
  78. f := RepoPath(user.Name, repoName)
  79. if err = initRepository(f, user, repo, initReadme, repoLang, license); err != nil {
  80. return nil, err
  81. }
  82. session := orm.NewSession()
  83. defer session.Close()
  84. session.Begin()
  85. if _, err = session.Insert(repo); err != nil {
  86. if err2 := os.RemoveAll(f); err2 != nil {
  87. return nil, errors.New(fmt.Sprintf(
  88. "delete repo directory %s/%s failed", user.Name, repoName))
  89. }
  90. session.Rollback()
  91. return nil, err
  92. }
  93. access := Access{
  94. UserName: user.Name,
  95. RepoName: repo.Name,
  96. Mode: AU_WRITABLE,
  97. }
  98. if _, err = session.Insert(&access); err != nil {
  99. session.Rollback()
  100. if err2 := os.RemoveAll(f); err2 != nil {
  101. return nil, errors.New(fmt.Sprintf(
  102. "delete repo directory %s/%s failed", user.Name, repoName))
  103. }
  104. return nil, err
  105. }
  106. if _, err = session.Exec("update user set num_repos = num_repos + 1 where id = ?", user.Id); err != nil {
  107. session.Rollback()
  108. if err2 := os.RemoveAll(f); err2 != nil {
  109. return nil, errors.New(fmt.Sprintf(
  110. "delete repo directory %s/%s failed", user.Name, repoName))
  111. }
  112. return nil, err
  113. }
  114. if err = session.Commit(); err != nil {
  115. session.Rollback()
  116. if err2 := os.RemoveAll(f); err2 != nil {
  117. return nil, errors.New(fmt.Sprintf(
  118. "delete repo directory %s/%s failed", user.Name, repoName))
  119. }
  120. return nil, err
  121. }
  122. return repo, NewRepoAction(user, repo)
  123. }
  124. // InitRepository initializes README and .gitignore if needed.
  125. func initRepository(f string, user *User, repo *Repository, initReadme bool, repoLang, license string) error {
  126. fileName := map[string]string{}
  127. if initReadme {
  128. fileName["readme"] = "README.md"
  129. }
  130. if repoLang != "" {
  131. fileName["gitign"] = ".gitignore"
  132. }
  133. if license != "" {
  134. fileName["license"] = "LICENSE"
  135. }
  136. workdir := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()))
  137. os.MkdirAll(workdir, os.ModePerm)
  138. sig := user.NewGitSig()
  139. // README
  140. if initReadme {
  141. defaultReadme := repo.Name + "\n" + strings.Repeat("=",
  142. utf8.RuneCountInString(repo.Name)) + "\n\n" + repo.Description
  143. if err := ioutil.WriteFile(filepath.Join(workdir, fileName["readme"]),
  144. []byte(defaultReadme), 0644); err != nil {
  145. return err
  146. }
  147. }
  148. if repoLang != "" {
  149. // .gitignore
  150. filePath := "conf/gitignore/" + repoLang
  151. if com.IsFile(filePath) {
  152. if _, err := com.Copy(filePath,
  153. filepath.Join(workdir, fileName["gitign"])); err != nil {
  154. return err
  155. }
  156. }
  157. }
  158. if license != "" {
  159. // LICENSE
  160. filePath := "conf/license/" + license
  161. if com.IsFile(filePath) {
  162. if _, err := com.Copy(filePath,
  163. filepath.Join(workdir, fileName["license"])); err != nil {
  164. return err
  165. }
  166. }
  167. }
  168. rp, err := git.InitRepository(f, true)
  169. if err != nil {
  170. return err
  171. }
  172. rp.SetWorkdir(workdir, false)
  173. idx, err := rp.Index()
  174. if err != nil {
  175. return err
  176. }
  177. for _, name := range fileName {
  178. if err = idx.AddByPath(name); err != nil {
  179. return err
  180. }
  181. }
  182. treeId, err := idx.WriteTree()
  183. if err != nil {
  184. return err
  185. }
  186. message := "Init commit"
  187. tree, err := rp.LookupTree(treeId)
  188. if err != nil {
  189. return err
  190. }
  191. if _, err = rp.CreateCommit("HEAD", sig, sig, message, tree); err != nil {
  192. return err
  193. }
  194. pu, err := os.OpenFile(filepath.Join(f, "hooks", "post-update"), os.O_CREATE|os.O_WRONLY, 0777)
  195. if err != nil {
  196. return err
  197. }
  198. defer pu.Close()
  199. ep, err := exePath()
  200. if err != nil {
  201. return err
  202. }
  203. _, err = pu.WriteString(fmt.Sprintf("#!/usr/bin/env bash\n%s update\n", ep))
  204. return err
  205. }
  206. func GetRepositoryByName(user *User, repoName string) (*Repository, error) {
  207. repo := &Repository{
  208. OwnerId: user.Id,
  209. LowerName: strings.ToLower(repoName),
  210. }
  211. has, err := orm.Get(repo)
  212. if err != nil {
  213. return nil, err
  214. } else if !has {
  215. return nil, ErrRepoNotExist
  216. }
  217. return repo, err
  218. }
  219. func GetRepositoryById(id int64) (repo *Repository, err error) {
  220. has, err := orm.Id(id).Get(repo)
  221. if err != nil {
  222. return nil, err
  223. } else if !has {
  224. return nil, ErrRepoNotExist
  225. }
  226. return repo, err
  227. }
  228. // GetRepositories returns the list of repositories of given user.
  229. func GetRepositories(user *User) ([]Repository, error) {
  230. repos := make([]Repository, 0, 10)
  231. err := orm.Desc("updated").Find(&repos, &Repository{OwnerId: user.Id})
  232. return repos, err
  233. }
  234. func GetRepositoryCount(user *User) (int64, error) {
  235. return orm.Count(&Repository{OwnerId: user.Id})
  236. }
  237. func StarReposiory(user *User, repoName string) error {
  238. return nil
  239. }
  240. func UnStarRepository() {
  241. }
  242. func WatchRepository() {
  243. }
  244. func UnWatchRepository() {
  245. }
  246. func ForkRepository(reposName string, userId int64) {
  247. }
  248. func RepoPath(userName, repoName string) string {
  249. return filepath.Join(UserPath(userName), repoName+".git")
  250. }
  251. // DeleteRepository deletes a repository for a user or orgnaztion.
  252. func DeleteRepository(userId, repoId int64, userName string) (err error) {
  253. repo := &Repository{Id: repoId, OwnerId: userId}
  254. has, err := orm.Get(repo)
  255. if err != nil {
  256. return err
  257. } else if !has {
  258. return ErrRepoNotExist
  259. }
  260. session := orm.NewSession()
  261. if _, err = session.Delete(&Repository{Id: repoId}); err != nil {
  262. session.Rollback()
  263. return err
  264. }
  265. if _, err := session.Delete(&Access{UserName: userName, RepoName: repo.Name}); err != nil {
  266. session.Rollback()
  267. return err
  268. }
  269. if _, err = session.Exec("update user set num_repos = num_repos - 1 where id = ?", userId); err != nil {
  270. session.Rollback()
  271. return err
  272. }
  273. if err = session.Commit(); err != nil {
  274. session.Rollback()
  275. return err
  276. }
  277. if err = os.RemoveAll(RepoPath(userName, repo.Name)); err != nil {
  278. // TODO: log and delete manully
  279. log.Error("delete repo %s/%s failed", userName, repo.Name)
  280. return err
  281. }
  282. return nil
  283. }