api_nodejs.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package buildpacks
  2. import (
  3. "encoding/json"
  4. "strings"
  5. "sync"
  6. "github.com/google/go-github/github"
  7. )
  8. type apiNodeRuntime struct {
  9. wg sync.WaitGroup
  10. }
  11. func NewAPINodeRuntime() *apiNodeRuntime {
  12. return &apiNodeRuntime{}
  13. }
  14. func (runtime *apiNodeRuntime) detectYarn(results chan struct {
  15. string
  16. bool
  17. }, directoryContent []*github.RepositoryContent) {
  18. yarnLockFound := false
  19. packageJSONFound := false
  20. for i := 0; i < len(directoryContent); i++ {
  21. name := directoryContent[i].GetName()
  22. if name == "yarn.lock" {
  23. yarnLockFound = true
  24. } else if name == "package.json" {
  25. packageJSONFound = true
  26. }
  27. if yarnLockFound && packageJSONFound {
  28. break
  29. }
  30. }
  31. if yarnLockFound && packageJSONFound {
  32. results <- struct {
  33. string
  34. bool
  35. }{yarn, true}
  36. } else {
  37. results <- struct {
  38. string
  39. bool
  40. }{yarn, false}
  41. }
  42. runtime.wg.Done()
  43. }
  44. func (runtime *apiNodeRuntime) detectNPM(results chan struct {
  45. string
  46. bool
  47. }, directoryContent []*github.RepositoryContent) {
  48. packageJSONFound := false
  49. for i := 0; i < len(directoryContent); i++ {
  50. name := directoryContent[i].GetName()
  51. if name == "package.json" {
  52. packageJSONFound = true
  53. break
  54. }
  55. }
  56. if packageJSONFound {
  57. results <- struct {
  58. string
  59. bool
  60. }{npm, true}
  61. } else {
  62. results <- struct {
  63. string
  64. bool
  65. }{npm, false}
  66. }
  67. runtime.wg.Done()
  68. }
  69. func (runtime *apiNodeRuntime) detectStandalone(results chan struct {
  70. string
  71. bool
  72. }, directoryContent []*github.RepositoryContent) {
  73. jsFileFound := false
  74. for i := 0; i < len(directoryContent); i++ {
  75. name := directoryContent[i].GetName()
  76. if name == "server.js" || name == "app.js" || name == "main.js" || name == "index.js" {
  77. jsFileFound = true
  78. break
  79. }
  80. }
  81. if jsFileFound {
  82. results <- struct {
  83. string
  84. bool
  85. }{standalone, true}
  86. } else {
  87. results <- struct {
  88. string
  89. bool
  90. }{standalone, false}
  91. }
  92. runtime.wg.Done()
  93. }
  94. func (runtime *apiNodeRuntime) Detect(directoryContent []*github.RepositoryContent) map[string]interface{} {
  95. results := make(chan struct {
  96. string
  97. bool
  98. }, 3)
  99. runtime.wg.Add(3)
  100. go runtime.detectYarn(results, directoryContent)
  101. go runtime.detectNPM(results, directoryContent)
  102. go runtime.detectStandalone(results, directoryContent)
  103. runtime.wg.Wait()
  104. close(results)
  105. atLeastOne := false
  106. detected := make(map[string]bool)
  107. for result := range results {
  108. if result.bool {
  109. atLeastOne = true
  110. }
  111. detected[result.string] = result.bool
  112. }
  113. if atLeastOne {
  114. if detected[yarn] || detected[npm] {
  115. // it is safe to assume that the project contains a package.json
  116. var packageJSONRef *github.RepositoryContent
  117. for i := 0; i < len(directoryContent); i++ {
  118. name := directoryContent[i].GetName()
  119. if name == "package.json" {
  120. packageJSONRef = directoryContent[i]
  121. break
  122. }
  123. }
  124. content, err := packageJSONRef.GetContent()
  125. if err != nil {
  126. // FIXME: log somewhere
  127. return nil
  128. }
  129. var packageJSON struct {
  130. Scripts map[string]string `json:"scripts"`
  131. Engines struct {
  132. Node string `json:"node"`
  133. } `json:"engines"`
  134. }
  135. err = json.NewDecoder(strings.NewReader(content)).Decode(&packageJSON)
  136. if err != nil {
  137. // FIXME: log somewhere
  138. return nil
  139. }
  140. if detected[yarn] {
  141. return map[string]interface{}{"runtime": yarn, "scripts": packageJSON.Scripts, "node_engine": packageJSON.Engines.Node}
  142. } else {
  143. return map[string]interface{}{"runtime": npm, "scripts": packageJSON.Scripts, "node_engine": packageJSON.Engines.Node}
  144. }
  145. }
  146. return map[string]interface{}{"runtime": "node-standalone"}
  147. }
  148. return nil
  149. }