contents.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright 2020 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 repo
  5. import (
  6. "encoding/base64"
  7. "fmt"
  8. "path"
  9. "github.com/gogs/git-module"
  10. "github.com/pkg/errors"
  11. "gogs.io/gogs/internal/context"
  12. "gogs.io/gogs/internal/gitutil"
  13. )
  14. func GetContents(c *context.APIContext) {
  15. gitRepo, err := git.Open(c.Repo.Repository.RepoPath())
  16. if err != nil {
  17. c.ServerError("open repository", err)
  18. return
  19. }
  20. ref := c.Query("ref")
  21. if ref == "" {
  22. ref = c.Repo.Repository.DefaultBranch
  23. }
  24. commit, err := gitRepo.CatFileCommit(ref)
  25. if err != nil {
  26. c.NotFoundOrServerError("get commit", gitutil.IsErrRevisionNotExist, err)
  27. return
  28. }
  29. treePath := c.Params("*")
  30. entry, err := commit.TreeEntry(treePath)
  31. if err != nil {
  32. c.NotFoundOrServerError("get tree entry", gitutil.IsErrRevisionNotExist, err)
  33. return
  34. }
  35. type links struct {
  36. Git string `json:"git"`
  37. Self string `json:"self"`
  38. HTML string `json:"html"`
  39. }
  40. type repoContent struct {
  41. Type string `json:"type"`
  42. Target string `json:"target,omitempty"`
  43. SubmoduleGitURL string `json:"submodule_git_url,omitempty"`
  44. Encoding string `json:"encoding,omitempty"`
  45. Size int64 `json:"size"`
  46. Name string `json:"name"`
  47. Path string `json:"path"`
  48. Content string `json:"content,omitempty"`
  49. Sha string `json:"sha"`
  50. URL string `json:"url"`
  51. GitURL string `json:"git_url"`
  52. HTMLURL string `json:"html_url"`
  53. DownloadURL string `json:"download_url"`
  54. Links links `json:"_links"`
  55. }
  56. toRepoContent := func(subpath string, entry *git.TreeEntry) (*repoContent, error) {
  57. repoURL := fmt.Sprintf("%s/repos/%s/%s", c.BaseURL, c.Params(":username"), c.Params(":reponame"))
  58. selfURL := fmt.Sprintf("%s/contents/%s", repoURL, subpath)
  59. htmlURL := fmt.Sprintf("%s/src/%s/%s", c.Repo.Repository.HTMLURL(), ref, entry.Name())
  60. downloadURL := fmt.Sprintf("%s/raw/%s/%s", c.Repo.Repository.HTMLURL(), ref, entry.Name())
  61. content := &repoContent{
  62. Size: entry.Size(),
  63. Name: entry.Name(),
  64. Path: subpath,
  65. Sha: entry.ID().String(),
  66. URL: selfURL,
  67. HTMLURL: htmlURL,
  68. DownloadURL: downloadURL,
  69. Links: links{
  70. Self: selfURL,
  71. HTML: htmlURL,
  72. },
  73. }
  74. switch {
  75. case entry.IsBlob(), entry.IsExec():
  76. content.Type = "file"
  77. p, err := entry.Blob().Bytes()
  78. if err != nil {
  79. return nil, errors.Wrap(err, "get blob content")
  80. }
  81. content.Encoding = "base64"
  82. content.Content = base64.StdEncoding.EncodeToString(p)
  83. content.GitURL = fmt.Sprintf("%s/git/blobs/%s", repoURL, entry.ID().String())
  84. case entry.IsTree():
  85. content.Type = "dir"
  86. content.GitURL = fmt.Sprintf("%s/git/trees/%s", repoURL, entry.ID().String())
  87. case entry.IsSymlink():
  88. content.Type = "symlink"
  89. p, err := entry.Blob().Bytes()
  90. if err != nil {
  91. return nil, errors.Wrap(err, "get blob content")
  92. }
  93. content.Target = string(p)
  94. case entry.IsCommit():
  95. content.Type = "submodule"
  96. mod, err := commit.Submodule(subpath)
  97. if err != nil {
  98. return nil, errors.Wrap(err, "get submodule")
  99. }
  100. content.SubmoduleGitURL = mod.URL
  101. default:
  102. panic("unreachable")
  103. }
  104. content.Links.Git = content.GitURL
  105. return content, nil
  106. }
  107. if !entry.IsTree() {
  108. content, err := toRepoContent(treePath, entry)
  109. if err != nil {
  110. c.Errorf(err, "convert %q to repoContent", treePath)
  111. return
  112. }
  113. c.JSONSuccess(content)
  114. return
  115. }
  116. // The entry is a directory
  117. dir, err := gitRepo.LsTree(entry.ID().String())
  118. if err != nil {
  119. c.NotFoundOrServerError("get tree", gitutil.IsErrRevisionNotExist, err)
  120. return
  121. }
  122. entries, err := dir.Entries()
  123. if err != nil {
  124. c.NotFoundOrServerError("list entries", gitutil.IsErrRevisionNotExist, err)
  125. return
  126. }
  127. if len(entries) == 0 {
  128. c.JSONSuccess([]string{})
  129. return
  130. }
  131. contents := make([]*repoContent, 0, len(entries))
  132. for _, entry := range entries {
  133. subpath := path.Join(treePath, entry.Name())
  134. content, err := toRepoContent(subpath, entry)
  135. if err != nil {
  136. c.Errorf(err, "convert %q to repoContent", subpath)
  137. return
  138. }
  139. contents = append(contents, content)
  140. }
  141. c.JSONSuccess(contents)
  142. }