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

repo.go 5.8 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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. git "github.com/libgit2/git2go"
  15. "github.com/gogits/gogs/modules/log"
  16. )
  17. type Repository struct {
  18. Id int64
  19. OwnerId int64 `xorm:"unique(s)"`
  20. ForkId int64
  21. LowerName string `xorm:"unique(s) index not null"`
  22. Name string `xorm:"index not null"`
  23. Description string
  24. Private bool
  25. NumWatchs int
  26. NumStars int
  27. NumForks int
  28. Created time.Time `xorm:"created"`
  29. Updated time.Time `xorm:"updated"`
  30. }
  31. type Star struct {
  32. Id int64
  33. RepoId int64
  34. UserId int64
  35. Created time.Time `xorm:"created"`
  36. }
  37. var (
  38. ErrRepoAlreadyExist = errors.New("Repository already exist")
  39. )
  40. // check if repository is exist
  41. func IsRepositoryExist(user *User, repoName string) (bool, error) {
  42. repo := Repository{OwnerId: user.Id}
  43. has, err := orm.Where("lower_name = ?", strings.ToLower(repoName)).Get(&repo)
  44. if err != nil {
  45. return has, err
  46. }
  47. s, err := os.Stat(RepoPath(user.Name, repoName))
  48. if err != nil {
  49. return false, nil
  50. }
  51. return s.IsDir(), nil
  52. }
  53. // CreateRepository creates a repository for given user or orgnaziation.
  54. func CreateRepository(user *User, repoName, desc, repoLang string, private bool, initReadme bool) (*Repository, error) {
  55. isExist, err := IsRepositoryExist(user, repoName)
  56. if err != nil {
  57. return nil, err
  58. } else if isExist {
  59. return nil, ErrRepoAlreadyExist
  60. }
  61. repo := &Repository{
  62. OwnerId: user.Id,
  63. Name: repoName,
  64. LowerName: strings.ToLower(repoName),
  65. Description: desc,
  66. Private: private,
  67. }
  68. f := RepoPath(user.Name, repoName)
  69. if err = initRepository(f, user, repo, initReadme, repoLang); err != nil {
  70. return nil, err
  71. }
  72. session := orm.NewSession()
  73. defer session.Close()
  74. session.Begin()
  75. if _, err = session.Insert(repo); err != nil {
  76. if err2 := os.RemoveAll(f); err2 != nil {
  77. return nil, errors.New(fmt.Sprintf(
  78. "delete repo directory %s/%s failed", user.Name, repoName))
  79. }
  80. session.Rollback()
  81. return nil, err
  82. }
  83. // TODO: RemoveAll may fail due to not root access.
  84. access := Access{
  85. UserName: user.Name,
  86. RepoName: repo.Name,
  87. Mode: AU_WRITABLE,
  88. }
  89. if _, err = session.Insert(&access); err != nil {
  90. session.Rollback()
  91. if err2 := os.RemoveAll(f); err2 != nil {
  92. return nil, errors.New(fmt.Sprintf(
  93. "delete repo directory %s/%s failed", user.Name, repoName))
  94. }
  95. return nil, err
  96. }
  97. if _, err = session.Exec("update user set num_repos = num_repos + 1 where id = ?", user.Id); err != nil {
  98. session.Rollback()
  99. if err2 := os.RemoveAll(f); err2 != nil {
  100. return nil, errors.New(fmt.Sprintf(
  101. "delete repo directory %s/%s failed", user.Name, repoName))
  102. }
  103. return nil, err
  104. }
  105. if err = session.Commit(); err != nil {
  106. session.Rollback()
  107. if err2 := os.RemoveAll(f); err2 != nil {
  108. return nil, errors.New(fmt.Sprintf(
  109. "delete repo directory %s/%s failed", user.Name, repoName))
  110. }
  111. return nil, err
  112. }
  113. return repo, nil
  114. }
  115. // InitRepository initializes README and .gitignore if needed.
  116. func initRepository(f string, user *User, repo *Repository, initReadme bool, repoLang string) error {
  117. fileName := map[string]string{
  118. "readme": "README.md",
  119. "gitign": ".gitignore",
  120. }
  121. workdir := os.TempDir() + fmt.Sprintf("%d", time.Now().Nanosecond())
  122. sig := &git.Signature{
  123. Name: user.Name,
  124. Email: user.Email,
  125. When: time.Now(),
  126. }
  127. // README
  128. defaultReadme := repo.Name + "\n" + strings.Repeat("=",
  129. utf8.RuneCountInString(repo.Name)) + "\n\n" + repo.Description
  130. if err := ioutil.WriteFile(filepath.Join(workdir, fileName["readme"]),
  131. []byte(defaultReadme), 0644); err != nil {
  132. return err
  133. }
  134. // .gitignore
  135. // if err := ioutil.WriteFile(filepath.Join(workdir, gitIgn),
  136. // []byte(defaultREADME), 0644); err != nil {
  137. // return err
  138. // }
  139. // LICENSE
  140. rp, err := git.InitRepository(f, true)
  141. if err != nil {
  142. return err
  143. }
  144. rp.SetWorkdir(workdir, false)
  145. idx, err := rp.Index()
  146. if err != nil {
  147. return err
  148. }
  149. if err = idx.AddByPath(fileName["readme"]); err != nil {
  150. return err
  151. }
  152. treeId, err := idx.WriteTree()
  153. if err != nil {
  154. return err
  155. }
  156. message := "Init commit"
  157. tree, err := rp.LookupTree(treeId)
  158. if err != nil {
  159. return err
  160. }
  161. if _, err = rp.CreateCommit("HEAD", sig, sig, message, tree); err != nil {
  162. return err
  163. }
  164. return nil
  165. }
  166. // GetRepositories returns the list of repositories of given user.
  167. func GetRepositories(user *User) ([]Repository, error) {
  168. repos := make([]Repository, 0, 10)
  169. err := orm.Find(&repos, &Repository{OwnerId: user.Id})
  170. return repos, err
  171. }
  172. func StarReposiory(user *User, repoName string) error {
  173. return nil
  174. }
  175. func UnStarRepository() {
  176. }
  177. func WatchRepository() {
  178. }
  179. func UnWatchRepository() {
  180. }
  181. func ForkRepository(reposName string, userId int64) {
  182. }
  183. func RepoPath(userName, repoName string) string {
  184. return filepath.Join(UserPath(userName), repoName+".git")
  185. }
  186. // DeleteRepository deletes a repository for a user or orgnaztion.
  187. func DeleteRepository(user *User, reposName string) (err error) {
  188. session := orm.NewSession()
  189. if _, err = session.Delete(&Repository{OwnerId: user.Id, Name: reposName}); err != nil {
  190. session.Rollback()
  191. return err
  192. }
  193. if _, err = session.Exec("update user set num_repos = num_repos - 1 where id = ?", user.Id); err != nil {
  194. session.Rollback()
  195. return err
  196. }
  197. if err = session.Commit(); err != nil {
  198. session.Rollback()
  199. return err
  200. }
  201. if err = os.RemoveAll(RepoPath(user.Name, reposName)); err != nil {
  202. // TODO: log and delete manully
  203. log.Error("delete repo %s/%s failed", user.Name, reposName)
  204. return err
  205. }
  206. return nil
  207. }