identity.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package hercules
  2. import (
  3. "bufio"
  4. "os"
  5. "strings"
  6. "gopkg.in/src-d/go-git.v4"
  7. "gopkg.in/src-d/go-git.v4/plumbing/object"
  8. )
  9. type IdentityDetector struct {
  10. // Maps email || name -> developer id.
  11. PeopleDict map[string]int
  12. // Maps developer id -> description
  13. ReversePeopleDict []string
  14. }
  15. const MISSING_AUTHOR = (1 << 18) - 1
  16. const SELF_AUTHOR = (1 << 18) - 2
  17. func (id *IdentityDetector) Name() string {
  18. return "IdentityDetector"
  19. }
  20. func (id *IdentityDetector) Provides() []string {
  21. arr := [...]string{"author"}
  22. return arr[:]
  23. }
  24. func (id *IdentityDetector) Requires() []string {
  25. return []string{}
  26. }
  27. func (id *IdentityDetector) Initialize(repository *git.Repository) {
  28. }
  29. func (self *IdentityDetector) Consume(deps map[string]interface{}) (map[string]interface{}, error) {
  30. commit := deps["commit"].(*object.Commit)
  31. signature := commit.Author
  32. id, exists := self.PeopleDict[strings.ToLower(signature.Email)]
  33. if !exists {
  34. id, exists = self.PeopleDict[strings.ToLower(signature.Name)]
  35. if !exists {
  36. id = MISSING_AUTHOR
  37. }
  38. }
  39. return map[string]interface{}{"author": id}, nil
  40. }
  41. func (id *IdentityDetector) Finalize() interface{} {
  42. return nil
  43. }
  44. func (id *IdentityDetector) LoadPeopleDict(path string) error {
  45. file, err := os.Open(path)
  46. if err != nil {
  47. return err
  48. }
  49. defer file.Close()
  50. scanner := bufio.NewScanner(file)
  51. dict := make(map[string]int)
  52. reverse_dict := []string{}
  53. size := 0
  54. for scanner.Scan() {
  55. ids := strings.Split(scanner.Text(), "|")
  56. for _, id := range ids {
  57. dict[strings.ToLower(id)] = size
  58. }
  59. reverse_dict = append(reverse_dict, ids[0])
  60. size += 1
  61. }
  62. reverse_dict = append(reverse_dict, "<unmatched>")
  63. id.PeopleDict = dict
  64. id.ReversePeopleDict = reverse_dict
  65. return nil
  66. }
  67. func (id *IdentityDetector) GeneratePeopleDict(commits []*object.Commit) {
  68. dict := map[string]int{}
  69. emails := map[int][]string{}
  70. names := map[int][]string{}
  71. size := 0
  72. mailmapFile, err := commits[len(commits) - 1].File(".mailmap")
  73. if err == nil {
  74. mailMapContents, err := mailmapFile.Contents()
  75. if err == nil {
  76. mailmap := ParseMailmap(mailMapContents)
  77. for key, val := range mailmap {
  78. key = strings.ToLower(key)
  79. toEmail := strings.ToLower(val.Email)
  80. toName := strings.ToLower(val.Name)
  81. id, exists := dict[toEmail]
  82. if !exists {
  83. id, exists = dict[toName]
  84. }
  85. if exists {
  86. dict[key] = id
  87. } else {
  88. if toEmail != "" {
  89. dict[toEmail] = size
  90. }
  91. if toName != "" {
  92. dict[toName] = size
  93. }
  94. dict[key] = size
  95. size += 1
  96. }
  97. }
  98. }
  99. }
  100. for _, commit := range commits {
  101. email := strings.ToLower(commit.Author.Email)
  102. name := strings.ToLower(commit.Author.Name)
  103. id, exists := dict[email]
  104. if exists {
  105. _, exists := dict[name]
  106. if !exists {
  107. dict[name] = id
  108. names[id] = append(names[id], name)
  109. }
  110. continue
  111. }
  112. id, exists = dict[name]
  113. if exists {
  114. dict[email] = id
  115. emails[id] = append(emails[id], email)
  116. continue
  117. }
  118. dict[email] = size
  119. dict[name] = size
  120. emails[size] = append(emails[size], email)
  121. names[size] = append(names[size], name)
  122. size += 1
  123. }
  124. reverse_dict := make([]string, size)
  125. for _, val := range dict {
  126. reverse_dict[val] = strings.Join(names[val], "|") + "|" + strings.Join(emails[val], "|")
  127. }
  128. id.PeopleDict = dict
  129. id.ReversePeopleDict = reverse_dict
  130. }