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.

197 lines
4.0 KiB

  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. // IsRepoURLAccessible checks if given repository URL is accessible.
  37. func IsRepoURLAccessible(url string) bool {
  38. _, err := NewCommand("ls-remote", "-q", "-h", url, "HEAD").Run()
  39. if err != nil {
  40. return false
  41. }
  42. return true
  43. }
  44. // InitRepository initializes a new Git repository.
  45. func InitRepository(repoPath string, bare bool) error {
  46. os.MkdirAll(repoPath, os.ModePerm)
  47. cmd := NewCommand("init")
  48. if bare {
  49. cmd.AddArguments("--bare")
  50. }
  51. _, err := cmd.RunInDir(repoPath)
  52. return err
  53. }
  54. // OpenRepository opens the repository at the given path.
  55. func OpenRepository(repoPath string) (*Repository, error) {
  56. repoPath, err := filepath.Abs(repoPath)
  57. if err != nil {
  58. return nil, err
  59. } else if !isDir(repoPath) {
  60. return nil, errors.New("no such file or directory")
  61. }
  62. return &Repository{
  63. Path: repoPath,
  64. commitCache: newObjectCache(),
  65. tagCache: newObjectCache(),
  66. }, nil
  67. }
  68. type CloneRepoOptions struct {
  69. Timeout time.Duration
  70. Mirror bool
  71. Bare bool
  72. Quiet bool
  73. Branch string
  74. }
  75. // Clone clones original repository to target path.
  76. func Clone(from, to string, opts CloneRepoOptions) (err error) {
  77. toDir := path.Dir(to)
  78. if err = os.MkdirAll(toDir, os.ModePerm); err != nil {
  79. return err
  80. }
  81. cmd := NewCommand("clone")
  82. if opts.Mirror {
  83. cmd.AddArguments("--mirror")
  84. }
  85. if opts.Bare {
  86. cmd.AddArguments("--bare")
  87. }
  88. if opts.Quiet {
  89. cmd.AddArguments("--quiet")
  90. }
  91. if len(opts.Branch) > 0 {
  92. cmd.AddArguments("-b", opts.Branch)
  93. }
  94. cmd.AddArguments(from, to)
  95. if opts.Timeout <= 0 {
  96. opts.Timeout = -1
  97. }
  98. _, err = cmd.RunTimeout(opts.Timeout)
  99. return err
  100. }
  101. type PullRemoteOptions struct {
  102. Timeout time.Duration
  103. All bool
  104. Rebase bool
  105. Remote string
  106. Branch string
  107. }
  108. // Pull pulls changes from remotes.
  109. func Pull(repoPath string, opts PullRemoteOptions) error {
  110. cmd := NewCommand("pull")
  111. if opts.Rebase {
  112. cmd.AddArguments("--rebase")
  113. }
  114. if opts.All {
  115. cmd.AddArguments("--all")
  116. } else {
  117. cmd.AddArguments(opts.Remote)
  118. cmd.AddArguments(opts.Branch)
  119. }
  120. if opts.Timeout <= 0 {
  121. opts.Timeout = -1
  122. }
  123. _, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
  124. return err
  125. }
  126. // Push pushs local commits to given remote branch.
  127. func Push(repoPath, remote, branch string) error {
  128. _, err := NewCommand("push", remote, branch).RunInDir(repoPath)
  129. return err
  130. }
  131. type CheckoutOptions struct {
  132. Timeout time.Duration
  133. Branch string
  134. OldBranch string
  135. }
  136. // Checkout checkouts a branch
  137. func Checkout(repoPath string, opts CheckoutOptions) error {
  138. cmd := NewCommand("checkout")
  139. if len(opts.OldBranch) > 0 {
  140. cmd.AddArguments("-b")
  141. }
  142. if opts.Timeout <= 0 {
  143. opts.Timeout = -1
  144. }
  145. cmd.AddArguments(opts.Branch)
  146. if len(opts.OldBranch) > 0 {
  147. cmd.AddArguments(opts.OldBranch)
  148. }
  149. _, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
  150. return err
  151. }
  152. // ResetHEAD resets HEAD to given revision or head of branch.
  153. func ResetHEAD(repoPath string, hard bool, revision string) error {
  154. cmd := NewCommand("reset")
  155. if hard {
  156. cmd.AddArguments("--hard")
  157. }
  158. _, err := cmd.AddArguments(revision).RunInDir(repoPath)
  159. return err
  160. }
  161. // MoveFile moves a file to another file or directory.
  162. func MoveFile(repoPath, oldTreeName, newTreeName string) error {
  163. _, err := NewCommand("mv").AddArguments(oldTreeName, newTreeName).RunInDir(repoPath)
  164. return err
  165. }