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.

193 lines
3.9 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. Remote string
  105. Branch string
  106. }
  107. // Pull pulls changes from remotes.
  108. func Pull(repoPath string, opts PullRemoteOptions) error {
  109. cmd := NewCommand("pull")
  110. if opts.All {
  111. cmd.AddArguments("--all")
  112. } else {
  113. cmd.AddArguments(opts.Remote)
  114. cmd.AddArguments(opts.Branch)
  115. }
  116. if opts.Timeout <= 0 {
  117. opts.Timeout = -1
  118. }
  119. _, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
  120. return err
  121. }
  122. // Push pushs local commits to given remote branch.
  123. func Push(repoPath, remote, branch string) error {
  124. _, err := NewCommand("push", remote, branch).RunInDir(repoPath)
  125. return err
  126. }
  127. type CheckoutOptions struct {
  128. Timeout time.Duration
  129. Branch string
  130. OldBranch string
  131. }
  132. // Checkout checkouts a branch
  133. func Checkout(repoPath string, opts CheckoutOptions) error {
  134. cmd := NewCommand("checkout")
  135. if len(opts.OldBranch) > 0 {
  136. cmd.AddArguments("-b")
  137. }
  138. if opts.Timeout <= 0 {
  139. opts.Timeout = -1
  140. }
  141. cmd.AddArguments(opts.Branch)
  142. if len(opts.OldBranch) > 0 {
  143. cmd.AddArguments(opts.OldBranch)
  144. }
  145. _, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
  146. return err
  147. }
  148. // ResetHEAD resets HEAD to given revision or head of branch.
  149. func ResetHEAD(repoPath string, hard bool, revision string) error {
  150. cmd := NewCommand("reset")
  151. if hard {
  152. cmd.AddArguments("--hard")
  153. }
  154. _, err := cmd.AddArguments(revision).RunInDir(repoPath)
  155. return err
  156. }
  157. // MoveFile moves a file to another file or directory.
  158. func MoveFile(repoPath, oldTreeName, newTreeName string) error {
  159. _, err := NewCommand("mv").AddArguments(oldTreeName, newTreeName).RunInDir(repoPath)
  160. return err
  161. }