vcs.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "os"
  6. "os/exec"
  7. "strings"
  8. "time"
  9. )
  10. // Info contains the last commit sha of a repo
  11. type vcsInfo map[string]shaInfos
  12. type shaInfos map[string]shaInfo
  13. type shaInfo struct {
  14. Protocols []string `json:"protocols"`
  15. Brach string `json:"branch"`
  16. SHA string `json:"sha"`
  17. }
  18. // createDevelDB forces yay to create a DB of the existing development packages
  19. func createDevelDB() error {
  20. _, _, _, remoteNames, err := filterPackages()
  21. if err != nil {
  22. return err
  23. }
  24. config.NoConfirm = true
  25. arguments := makeArguments()
  26. arguments.addArg("gendb")
  27. arguments.addTarget(remoteNames...)
  28. err = install(arguments)
  29. return err
  30. }
  31. // parseSource returns the git url and efault branch
  32. func parseSource(source string) (url string, branch string, protocols []string) {
  33. if !(strings.Contains(source, "git://") ||
  34. strings.Contains(source, ".git") ||
  35. strings.Contains(source, "git+https://")) {
  36. return
  37. }
  38. split := strings.Split(source, "::")
  39. source = split[len(split)-1]
  40. split = strings.SplitN(source, "://", 2)
  41. if len(split) != 2 {
  42. return
  43. }
  44. protocols = strings.Split(split[0], "+")
  45. split = strings.SplitN(split[1], "#", 2)
  46. if len(split) == 2 {
  47. secondSplit := strings.SplitN(split[1], "=", 2)
  48. if secondSplit[0] != "branch" {
  49. //source has #commit= or #tag= which makes them not vcs
  50. //packages because they reference a specific point
  51. return
  52. }
  53. if len(secondSplit) == 2 {
  54. url = split[0]
  55. branch = secondSplit[1]
  56. }
  57. } else {
  58. url = split[0]
  59. branch = "HEAD"
  60. }
  61. return
  62. }
  63. func updateVCSData(pkgName string, sources []string) {
  64. if savedInfo == nil {
  65. savedInfo = make(vcsInfo)
  66. }
  67. info := make(shaInfos)
  68. for _, source := range sources {
  69. url, branch, protocols := parseSource(source)
  70. if url == "" || branch == "" {
  71. continue
  72. }
  73. commit := getCommit(url, branch, protocols)
  74. if commit == "" {
  75. continue
  76. }
  77. info[url] = shaInfo{
  78. protocols,
  79. branch,
  80. commit,
  81. }
  82. savedInfo[pkgName] = info
  83. saveVCSInfo()
  84. }
  85. }
  86. func getCommit(url string, branch string, protocols []string) string {
  87. for _, protocol := range protocols {
  88. var outbuf bytes.Buffer
  89. cmd := exec.Command("git", "ls-remote", protocol+"://"+url, branch)
  90. cmd.Stdout = &outbuf
  91. err := cmd.Start()
  92. if err != nil {
  93. continue
  94. }
  95. //for some reason
  96. //git://bitbucket.org/volumesoffun/polyvox.git` hangs on my
  97. //machine but using http:// instead of git does not hang.
  98. //Introduce a time out so this can not hang
  99. timer := time.AfterFunc(5*time.Second, func() {
  100. cmd.Process.Kill()
  101. })
  102. err = cmd.Wait()
  103. timer.Stop()
  104. if err != nil {
  105. continue
  106. }
  107. err = cmd.Run()
  108. stdout := outbuf.String()
  109. split := strings.Fields(stdout)
  110. if len(split) < 2 {
  111. continue
  112. }
  113. commit := split[0]
  114. return commit
  115. }
  116. return ""
  117. }
  118. func (infos shaInfos) needsUpdate() bool {
  119. for url, info := range infos {
  120. hash := getCommit(url, info.Brach, info.Protocols)
  121. if hash != info.SHA {
  122. return true
  123. }
  124. }
  125. return false
  126. }
  127. func inStore(pkgName string) shaInfos {
  128. return savedInfo[pkgName]
  129. }
  130. func saveVCSInfo() error {
  131. marshalledinfo, err := json.MarshalIndent(savedInfo, "", "\t")
  132. if err != nil || string(marshalledinfo) == "null" {
  133. return err
  134. }
  135. in, err := os.OpenFile(vcsFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
  136. if err != nil {
  137. return err
  138. }
  139. defer in.Close()
  140. _, err = in.Write(marshalledinfo)
  141. if err != nil {
  142. return err
  143. }
  144. err = in.Sync()
  145. return err
  146. }