repo.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright 2015 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 git
  5. import (
  6. "bytes"
  7. "container/list"
  8. "errors"
  9. "os"
  10. "path"
  11. "path/filepath"
  12. "time"
  13. )
  14. // Repository represents a Git repository.
  15. type Repository struct {
  16. Path string
  17. commitCache *objectCache
  18. tagCache *objectCache
  19. }
  20. const _PRETTY_LOG_FORMAT = `--pretty=format:%H`
  21. func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, error) {
  22. l := list.New()
  23. if len(logs) == 0 {
  24. return l, nil
  25. }
  26. parts := bytes.Split(logs, []byte{'\n'})
  27. for _, commitId := range parts {
  28. commit, err := repo.GetCommit(string(commitId))
  29. if err != nil {
  30. return nil, err
  31. }
  32. l.PushBack(commit)
  33. }
  34. return l, nil
  35. }
  36. type NetworkOptions struct {
  37. URL string
  38. Timeout time.Duration
  39. }
  40. // IsRepoURLAccessible checks if given repository URL is accessible.
  41. func IsRepoURLAccessible(opts NetworkOptions) bool {
  42. cmd := NewCommand("ls-remote", "-q", "-h", opts.URL, "HEAD")
  43. if opts.Timeout <= 0 {
  44. opts.Timeout = -1
  45. }
  46. _, err := cmd.RunTimeout(opts.Timeout)
  47. if err != nil {
  48. return false
  49. }
  50. return true
  51. }
  52. // InitRepository initializes a new Git repository.
  53. func InitRepository(repoPath string, bare bool) error {
  54. os.MkdirAll(repoPath, os.ModePerm)
  55. cmd := NewCommand("init")
  56. if bare {
  57. cmd.AddArguments("--bare")
  58. }
  59. _, err := cmd.RunInDir(repoPath)
  60. return err
  61. }
  62. // OpenRepository opens the repository at the given path.
  63. func OpenRepository(repoPath string) (*Repository, error) {
  64. repoPath, err := filepath.Abs(repoPath)
  65. if err != nil {
  66. return nil, err
  67. } else if !isDir(repoPath) {
  68. return nil, errors.New("no such file or directory")
  69. }
  70. return &Repository{
  71. Path: repoPath,
  72. commitCache: newObjectCache(),
  73. tagCache: newObjectCache(),
  74. }, nil
  75. }
  76. type CloneRepoOptions struct {
  77. Mirror bool
  78. Bare bool
  79. Quiet bool
  80. Branch string
  81. Timeout time.Duration
  82. }
  83. // Clone clones original repository to target path.
  84. func Clone(from, to string, opts CloneRepoOptions) (err error) {
  85. toDir := path.Dir(to)
  86. if err = os.MkdirAll(toDir, os.ModePerm); err != nil {
  87. return err
  88. }
  89. cmd := NewCommand("clone")
  90. if opts.Mirror {
  91. cmd.AddArguments("--mirror")
  92. }
  93. if opts.Bare {
  94. cmd.AddArguments("--bare")
  95. }
  96. if opts.Quiet {
  97. cmd.AddArguments("--quiet")
  98. }
  99. if len(opts.Branch) > 0 {
  100. cmd.AddArguments("-b", opts.Branch)
  101. }
  102. cmd.AddArguments(from, to)
  103. if opts.Timeout <= 0 {
  104. opts.Timeout = -1
  105. }
  106. _, err = cmd.RunTimeout(opts.Timeout)
  107. return err
  108. }
  109. type FetchRemoteOptions struct {
  110. Prune bool
  111. Timeout time.Duration
  112. }
  113. // Fetch fetches changes from remotes without merging.
  114. func Fetch(repoPath string, opts FetchRemoteOptions) error {
  115. cmd := NewCommand("fetch")
  116. if opts.Prune {
  117. cmd.AddArguments("--prune")
  118. }
  119. if opts.Timeout <= 0 {
  120. opts.Timeout = -1
  121. }
  122. _, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
  123. return err
  124. }
  125. type PullRemoteOptions struct {
  126. All bool
  127. Rebase bool
  128. Remote string
  129. Branch string
  130. Timeout time.Duration
  131. }
  132. // Pull pulls changes from remotes.
  133. func Pull(repoPath string, opts PullRemoteOptions) error {
  134. cmd := NewCommand("pull")
  135. if opts.Rebase {
  136. cmd.AddArguments("--rebase")
  137. }
  138. if opts.All {
  139. cmd.AddArguments("--all")
  140. } else {
  141. cmd.AddArguments(opts.Remote)
  142. cmd.AddArguments(opts.Branch)
  143. }
  144. if opts.Timeout <= 0 {
  145. opts.Timeout = -1
  146. }
  147. _, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
  148. return err
  149. }
  150. // Push pushs local commits to given remote branch.
  151. func Push(repoPath, remote, branch string) error {
  152. _, err := NewCommand("push", remote, branch).RunInDir(repoPath)
  153. return err
  154. }
  155. type CheckoutOptions struct {
  156. Branch string
  157. OldBranch string
  158. Timeout time.Duration
  159. }
  160. // Checkout checkouts a branch
  161. func Checkout(repoPath string, opts CheckoutOptions) error {
  162. cmd := NewCommand("checkout")
  163. if len(opts.OldBranch) > 0 {
  164. cmd.AddArguments("-b")
  165. }
  166. cmd.AddArguments(opts.Branch)
  167. if len(opts.OldBranch) > 0 {
  168. cmd.AddArguments(opts.OldBranch)
  169. }
  170. if opts.Timeout <= 0 {
  171. opts.Timeout = -1
  172. }
  173. _, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
  174. return err
  175. }
  176. // ResetHEAD resets HEAD to given revision or head of branch.
  177. func ResetHEAD(repoPath string, hard bool, revision string) error {
  178. cmd := NewCommand("reset")
  179. if hard {
  180. cmd.AddArguments("--hard")
  181. }
  182. _, err := cmd.AddArguments(revision).RunInDir(repoPath)
  183. return err
  184. }
  185. // MoveFile moves a file to another file or directory.
  186. func MoveFile(repoPath, oldTreeName, newTreeName string) error {
  187. _, err := NewCommand("mv").AddArguments(oldTreeName, newTreeName).RunInDir(repoPath)
  188. return err
  189. }