vcs.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "net/http"
  7. "os"
  8. "strings"
  9. "time"
  10. )
  11. // branch contains the information of a repository branch
  12. type branch struct {
  13. Name string `json:"name"`
  14. Commit struct {
  15. SHA string `json:"sha"`
  16. URL string `json:"url"`
  17. } `json:"commit"`
  18. }
  19. type branches []branch
  20. // Info contains the last commit sha of a repo
  21. type Info struct {
  22. Package string `json:"pkgname"`
  23. URL string `json:"url"`
  24. SHA string `json:"sha"`
  25. }
  26. type infos []Info
  27. // Repo contains information about the repository
  28. type repo struct {
  29. ID int `json:"id"`
  30. Name string `json:"name"`
  31. FullName string `json:"full_name"`
  32. Owner struct {
  33. Login string `json:"login"`
  34. ID int `json:"id"`
  35. AvatarURL string `json:"avatar_url"`
  36. GravatarID string `json:"gravatar_id"`
  37. URL string `json:"url"`
  38. HTMLURL string `json:"html_url"`
  39. FollowersURL string `json:"followers_url"`
  40. FollowingURL string `json:"following_url"`
  41. GistsURL string `json:"gists_url"`
  42. StarredURL string `json:"starred_url"`
  43. SubscriptionsURL string `json:"subscriptions_url"`
  44. OrganizationsURL string `json:"organizations_url"`
  45. ReposURL string `json:"repos_url"`
  46. EventsURL string `json:"events_url"`
  47. ReceivedEventsURL string `json:"received_events_url"`
  48. Type string `json:"type"`
  49. SiteAdmin bool `json:"site_admin"`
  50. } `json:"owner"`
  51. Private bool `json:"private"`
  52. HTMLURL string `json:"html_url"`
  53. Description string `json:"description"`
  54. Fork bool `json:"fork"`
  55. URL string `json:"url"`
  56. ForksURL string `json:"forks_url"`
  57. KeysURL string `json:"keys_url"`
  58. CollaboratorsURL string `json:"collaborators_url"`
  59. TeamsURL string `json:"teams_url"`
  60. HooksURL string `json:"hooks_url"`
  61. IssueEventsURL string `json:"issue_events_url"`
  62. EventsURL string `json:"events_url"`
  63. AssigneesURL string `json:"assignees_url"`
  64. BranchesURL string `json:"branches_url"`
  65. TagsURL string `json:"tags_url"`
  66. BlobsURL string `json:"blobs_url"`
  67. GitTagsURL string `json:"git_tags_url"`
  68. GitRefsURL string `json:"git_refs_url"`
  69. TreesURL string `json:"trees_url"`
  70. StatusesURL string `json:"statuses_url"`
  71. LanguagesURL string `json:"languages_url"`
  72. StargazersURL string `json:"stargazers_url"`
  73. ContributorsURL string `json:"contributors_url"`
  74. SubscribersURL string `json:"subscribers_url"`
  75. SubscriptionURL string `json:"subscription_url"`
  76. CommitsURL string `json:"commits_url"`
  77. GitCommitsURL string `json:"git_commits_url"`
  78. CommentsURL string `json:"comments_url"`
  79. IssueCommentURL string `json:"issue_comment_url"`
  80. ContentsURL string `json:"contents_url"`
  81. CompareURL string `json:"compare_url"`
  82. MergesURL string `json:"merges_url"`
  83. ArchiveURL string `json:"archive_url"`
  84. DownloadsURL string `json:"downloads_url"`
  85. IssuesURL string `json:"issues_url"`
  86. PullsURL string `json:"pulls_url"`
  87. MilestonesURL string `json:"milestones_url"`
  88. NotificationsURL string `json:"notifications_url"`
  89. LabelsURL string `json:"labels_url"`
  90. ReleasesURL string `json:"releases_url"`
  91. DeploymentsURL string `json:"deployments_url"`
  92. CreatedAt time.Time `json:"created_at"`
  93. UpdatedAt time.Time `json:"updated_at"`
  94. PushedAt time.Time `json:"pushed_at"`
  95. GitURL string `json:"git_url"`
  96. SSHURL string `json:"ssh_url"`
  97. CloneURL string `json:"clone_url"`
  98. SvnURL string `json:"svn_url"`
  99. Homepage string `json:"homepage"`
  100. Size int `json:"size"`
  101. StargazersCount int `json:"stargazers_count"`
  102. WatchersCount int `json:"watchers_count"`
  103. Language string `json:"language"`
  104. HasIssues bool `json:"has_issues"`
  105. HasProjects bool `json:"has_projects"`
  106. HasDownloads bool `json:"has_downloads"`
  107. HasWiki bool `json:"has_wiki"`
  108. HasPages bool `json:"has_pages"`
  109. ForksCount int `json:"forks_count"`
  110. MirrorURL interface{} `json:"mirror_url"`
  111. Archived bool `json:"archived"`
  112. OpenIssuesCount int `json:"open_issues_count"`
  113. License struct {
  114. Key string `json:"key"`
  115. Name string `json:"name"`
  116. SpdxID interface{} `json:"spdx_id"`
  117. URL interface{} `json:"url"`
  118. } `json:"license"`
  119. Forks int `json:"forks"`
  120. OpenIssues int `json:"open_issues"`
  121. Watchers int `json:"watchers"`
  122. DefaultBranch string `json:"default_branch"`
  123. Organization struct {
  124. Login string `json:"login"`
  125. ID int `json:"id"`
  126. AvatarURL string `json:"avatar_url"`
  127. GravatarID string `json:"gravatar_id"`
  128. URL string `json:"url"`
  129. HTMLURL string `json:"html_url"`
  130. FollowersURL string `json:"followers_url"`
  131. FollowingURL string `json:"following_url"`
  132. GistsURL string `json:"gists_url"`
  133. StarredURL string `json:"starred_url"`
  134. SubscriptionsURL string `json:"subscriptions_url"`
  135. OrganizationsURL string `json:"organizations_url"`
  136. ReposURL string `json:"repos_url"`
  137. EventsURL string `json:"events_url"`
  138. ReceivedEventsURL string `json:"received_events_url"`
  139. Type string `json:"type"`
  140. SiteAdmin bool `json:"site_admin"`
  141. } `json:"organization"`
  142. NetworkCount int `json:"network_count"`
  143. SubscribersCount int `json:"subscribers_count"`
  144. }
  145. // createDevelDB forces yay to create a DB of the existing development packages
  146. func createDevelDB() error {
  147. _, _, _, remoteNames, err := filterPackages()
  148. if err != nil {
  149. return err
  150. }
  151. config.NoConfirm = true
  152. arguments := makeArguments()
  153. arguments.addArg("gendb")
  154. arguments.addTarget(remoteNames...)
  155. err = install(arguments)
  156. return err
  157. }
  158. // parseSource returns owner and repo from source
  159. func parseSource(source string) (owner string, repo string) {
  160. if !(strings.Contains(source, "git://") ||
  161. strings.Contains(source, ".git") ||
  162. strings.Contains(source, "git+https://")) {
  163. return
  164. }
  165. split := strings.Split(source, "github.com/")
  166. if len(split) > 1 {
  167. secondSplit := strings.Split(split[1], "/")
  168. if len(secondSplit) > 1 {
  169. owner = secondSplit[0]
  170. thirdSplit := strings.Split(secondSplit[1], ".git")
  171. if len(thirdSplit) > 0 {
  172. repo = thirdSplit[0]
  173. }
  174. }
  175. }
  176. return
  177. }
  178. func (info *Info) needsUpdate() bool {
  179. var newRepo repo
  180. var newBranches branches
  181. if strings.HasSuffix(info.URL, "/branches") {
  182. info.URL = info.URL[:len(info.URL)-9]
  183. }
  184. infoResp, infoErr := http.Get(info.URL)
  185. if infoErr != nil {
  186. fmt.Println(infoErr)
  187. return false
  188. }
  189. defer infoResp.Body.Close()
  190. infoBody, _ := ioutil.ReadAll(infoResp.Body)
  191. var err = json.Unmarshal(infoBody, &newRepo)
  192. if err != nil {
  193. fmt.Printf("Cannot update '%v'\nError: %v\nStatus code: %v\nBody: %v\n",
  194. info.Package, err, infoResp.StatusCode, string(infoBody))
  195. return false
  196. }
  197. defaultBranch := newRepo.DefaultBranch
  198. branchesURL := info.URL + "/branches"
  199. branchResp, branchErr := http.Get(branchesURL)
  200. if branchErr != nil {
  201. fmt.Println(branchErr)
  202. return false
  203. }
  204. defer branchResp.Body.Close()
  205. branchBody, _ := ioutil.ReadAll(branchResp.Body)
  206. err = json.Unmarshal(branchBody, &newBranches)
  207. if err != nil {
  208. fmt.Printf("Cannot update '%v'\nError: %v\nStatus code: %v\nBody: %v\n",
  209. info.Package, err, branchResp.StatusCode, string(branchBody))
  210. return false
  211. }
  212. for _, e := range newBranches {
  213. if e.Name == defaultBranch {
  214. return e.Commit.SHA != info.SHA
  215. }
  216. }
  217. return false
  218. }
  219. func inStore(pkgName string) *Info {
  220. for i, e := range savedInfo {
  221. if pkgName == e.Package {
  222. return &savedInfo[i]
  223. }
  224. }
  225. return nil
  226. }
  227. // branchInfo updates saved information
  228. func branchInfo(pkgName string, owner string, repoName string) (err error) {
  229. updated = true
  230. var newRepo repo
  231. var newBranches branches
  232. url := "https://api.github.com/repos/" + owner + "/" + repoName
  233. repoResp, err := http.Get(url)
  234. if err != nil {
  235. return
  236. }
  237. defer repoResp.Body.Close()
  238. _ = json.NewDecoder(repoResp.Body).Decode(&newRepo)
  239. defaultBranch := newRepo.DefaultBranch
  240. branchesUrl := url + "/branches"
  241. branchResp, err := http.Get(branchesUrl)
  242. if err != nil {
  243. return
  244. }
  245. defer branchResp.Body.Close()
  246. _ = json.NewDecoder(branchResp.Body).Decode(&newBranches)
  247. packinfo := inStore(pkgName)
  248. for _, e := range newBranches {
  249. if e.Name == defaultBranch {
  250. if packinfo != nil {
  251. packinfo.Package = pkgName
  252. packinfo.URL = url
  253. packinfo.SHA = e.Commit.SHA
  254. } else {
  255. savedInfo = append(savedInfo, Info{Package: pkgName, URL: url, SHA: e.Commit.SHA})
  256. }
  257. }
  258. }
  259. return
  260. }
  261. func saveVCSInfo() error {
  262. marshalledinfo, err := json.MarshalIndent(savedInfo, "", "\t")
  263. if err != nil || string(marshalledinfo) == "null" {
  264. return err
  265. }
  266. in, err := os.OpenFile(vcsFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
  267. if err != nil {
  268. return err
  269. }
  270. defer in.Close()
  271. _, err = in.Write(marshalledinfo)
  272. if err != nil {
  273. return err
  274. }
  275. err = in.Sync()
  276. return err
  277. }