context_gin.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package context
  2. import (
  3. "strings"
  4. "github.com/G-Node/gogs/internal/conf"
  5. "github.com/G-Node/gogs/internal/db"
  6. "github.com/G-Node/libgin/libgin"
  7. "github.com/gogs/git-module"
  8. log "gopkg.in/clog.v1"
  9. )
  10. // getRepoDOI returns the DOI for the repository based on the following rules:
  11. // - if the repository belongs to the DOI user and has a tag that matches the
  12. // DOI prefix, returns the tag.
  13. // - if the repo is forked by the DOI user, check the DOI fork for the tag as above.
  14. // - if the repo is forked by the DOI user and the fork doesn't have a tag,
  15. // returns the (old-style) calculated DOI, based on the hash of the repository
  16. // path.
  17. // - An empty string is returned if it is not not forked by the DOI user.
  18. // If an error occurs at any point, returns an empty string (the error is logged).
  19. // Tag retrieval is allowed to fail and falls back on the hashed DOI method.
  20. func getRepoDOI(c *Context) string {
  21. repo := c.Repo.Repository
  22. var doiFork *db.Repository
  23. if repo.Owner.Name == "doi" {
  24. doiFork = repo
  25. } else {
  26. if forks, err := repo.GetForks(); err == nil {
  27. for _, fork := range forks {
  28. if fork.MustOwner().Name == "doi" {
  29. doiFork = fork
  30. break
  31. }
  32. }
  33. } else {
  34. log.Error(2, "failed to get forks for repository %q (%d): %v", repo.FullName(), repo.ID, err)
  35. return ""
  36. }
  37. }
  38. if doiFork == nil {
  39. // not owned or forked by DOI, so not registered
  40. return ""
  41. }
  42. // check the DOI fork for a tag that matches our DOI prefix
  43. // if multiple exit, get the latest one
  44. doiBase := conf.DOI.Base
  45. doiForkGit, err := git.Open(doiFork.RepoPath())
  46. if err != nil {
  47. log.Error(2, "failed to open git repository at %q (%d): %v", doiFork.RepoPath(), doiFork.ID, err)
  48. return ""
  49. }
  50. if tags, err := doiForkGit.Tags(); err == nil {
  51. var latestTime int64
  52. latestTag := ""
  53. for _, tagName := range tags {
  54. if strings.Contains(tagName, doiBase) {
  55. tag, err := doiForkGit.Tag(tagName)
  56. if err != nil {
  57. // log the error and continue to the next tag
  58. log.Error(2, "failed to get information for tag %q for repository at %q: %v", tagName, doiForkGit.Path(), err)
  59. continue
  60. }
  61. commit, err := tag.Commit()
  62. if err != nil {
  63. // log the error and continue to the next tag
  64. log.Error(2, "failed to get commit for tag %q for repository at %q: %v", tagName, doiForkGit.Path(), err)
  65. continue
  66. }
  67. commitTime := commit.Committer.When.Unix()
  68. if commitTime > latestTime {
  69. latestTag = tagName
  70. latestTime = commitTime
  71. }
  72. }
  73. }
  74. return latestTag
  75. } else {
  76. // this shouldn't happen even if there are no tags
  77. // log the error, but fall back to the old method anyway
  78. log.Error(2, "failed to get tags for repository at %q: %v", doiForkGit.Path(), err)
  79. }
  80. // Has DOI fork but isn't tagged: return old style has-based DOI
  81. repoPath := repo.FullName()
  82. // get base repo name if it's a DOI fork
  83. if c.Repo.Repository.IsFork && c.Repo.Owner.Name == "doi" {
  84. repoPath = c.Repo.Repository.BaseRepo.FullName()
  85. }
  86. uuid := libgin.RepoPathToUUID(repoPath)
  87. return doiBase + uuid[:6]
  88. }
  89. // hasDataCite returns 'true' if a repository includes a file called
  90. // 'datacite.yml' in its root. No checks are made to determine if the file is
  91. // valid. If any error occurs, for example due to an uninitialised repository
  92. // or missing repository root, it returns 'false' without error.
  93. func hasDataCite(c *Context) bool {
  94. commit, err := c.Repo.GitRepo.BranchCommit(c.Repo.Repository.DefaultBranch)
  95. if err != nil {
  96. log.Trace("Couldn't get commit: %v", err)
  97. return false
  98. }
  99. _, err = commit.Blob("/datacite.yml")
  100. log.Trace("Found datacite? %t", err == nil)
  101. return err == nil
  102. }
  103. // True if repository is not Private, is not registered, or is registered and
  104. // has changes (HEAD is not registered)
  105. func isDOIReady(c *Context) bool {
  106. if hasDC, ok := c.Data["HasDataCite"]; !ok || !hasDC.(bool) {
  107. return false
  108. }
  109. dbrepo := c.Repo.Repository
  110. gitrepo := c.Repo.GitRepo
  111. headIsRegistered := func() bool {
  112. currentDOI, ok := c.Data["DOI"]
  113. if !ok {
  114. return false
  115. }
  116. headBranch, err := gitrepo.SymbolicRef(git.SymbolicRefOptions{Name: "HEAD"})
  117. if err != nil {
  118. log.Error(2, "Failed to get HEAD branch for repo at %q: %v", gitrepo.Path(), err)
  119. return false
  120. }
  121. headCommit, err := gitrepo.BranchCommitID(headBranch)
  122. if err != nil {
  123. log.Error(2, "Failed to get commit ID of branch %q for repo at %q: %v", headBranch, gitrepo.Path(), err)
  124. return false
  125. }
  126. // if current valid and registered DOI matches the HEAD commit, can't
  127. // register again
  128. doiCommit, err := gitrepo.TagCommitID(currentDOI.(string))
  129. if err != nil {
  130. log.Error(2, "Failed to get commit ID of tag %q for repo at %q: %v", currentDOI, gitrepo.Path(), err)
  131. return false
  132. }
  133. log.Trace("%s ?= %s", headCommit, doiCommit)
  134. return headCommit == doiCommit
  135. }()
  136. return !dbrepo.IsPrivate && !headIsRegistered
  137. }