identity.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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(strings.ToLower(scanner.Text()), "|")
  56. for _, id := range ids {
  57. dict[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 := make(map[string]int)
  69. emails := make(map[int][]string)
  70. names := make(map[int][]string)
  71. size := 0
  72. for _, commit := range commits {
  73. email := strings.ToLower(commit.Author.Email)
  74. name := strings.ToLower(commit.Author.Name)
  75. id, exists := dict[email]
  76. if exists {
  77. _, exists := dict[name]
  78. if !exists {
  79. dict[name] = id
  80. names[id] = append(names[id], name)
  81. }
  82. continue
  83. }
  84. id, exists = dict[name]
  85. if exists {
  86. dict[email] = id
  87. emails[id] = append(emails[id], email)
  88. continue
  89. }
  90. dict[email] = size
  91. dict[name] = size
  92. emails[size] = append(emails[size], email)
  93. names[size] = append(names[size], name)
  94. size += 1
  95. }
  96. reverse_dict := make([]string, size)
  97. for _, val := range dict {
  98. reverse_dict[val] = strings.Join(names[val], "|") + "|" + strings.Join(emails[val], "|")
  99. }
  100. id.PeopleDict = dict
  101. id.ReversePeopleDict = reverse_dict
  102. }