Gruntfile.coffee 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. coffee = require("coffee-script")
  2. fs = require "fs"
  3. spawn = require("child_process").spawn
  4. exec = require("child_process").exec
  5. rimraf = require "rimraf"
  6. Path = require "path"
  7. semver = require "semver"
  8. knox = require "knox"
  9. crypto = require "crypto"
  10. async = require "async"
  11. settings = require("settings-sharelatex")
  12. _ = require("underscore")
  13. SERVICES = require("./config/services")
  14. module.exports = (grunt) ->
  15. grunt.loadNpmTasks 'grunt-bunyan'
  16. grunt.loadNpmTasks 'grunt-execute'
  17. grunt.loadNpmTasks 'grunt-available-tasks'
  18. grunt.loadNpmTasks 'grunt-concurrent'
  19. grunt.loadNpmTasks "grunt-contrib-coffee"
  20. grunt.loadNpmTasks "grunt-shell"
  21. grunt.task.loadTasks "./tasks"
  22. execute = {}
  23. for service in SERVICES
  24. execute[service.name] =
  25. src: "#{service.name}/app.js"
  26. grunt.initConfig
  27. execute: execute
  28. concurrent:
  29. all:
  30. tasks: ("run:#{service.name}" for service in SERVICES)
  31. options:
  32. limit: SERVICES.length
  33. logConcurrentOutput: true
  34. availabletasks:
  35. tasks:
  36. options:
  37. filter: 'exclude',
  38. tasks: [
  39. 'concurrent'
  40. 'execute'
  41. 'bunyan'
  42. 'availabletasks'
  43. ]
  44. groups:
  45. "Run tasks": [
  46. "run"
  47. "run:all"
  48. "default"
  49. ].concat ("run:#{service.name}" for service in SERVICES)
  50. "Misc": [
  51. "help"
  52. ]
  53. "Install tasks": ("install:#{service.name}" for service in SERVICES).concat(["install:all", "install"])
  54. "Update tasks": ("update:#{service.name}" for service in SERVICES).concat(["update:all", "update"])
  55. "Checks": ["check", "check:redis", "check:latexmk", "check:s3", "check:make", "check:mongo"]
  56. for service in SERVICES
  57. do (service) ->
  58. grunt.registerTask "install:#{service.name}", "Download and set up the #{service.name} service", () ->
  59. done = @async()
  60. Helpers.installService(service, done)
  61. grunt.registerTask 'install:all', "Download and set up all ShareLaTeX services",
  62. [].concat(
  63. ("install:#{service.name}" for service in SERVICES)
  64. ).concat(['postinstall'])
  65. grunt.registerTask 'install', 'install:all'
  66. grunt.registerTask 'postinstall', 'Explain postinstall steps', () ->
  67. Helpers.postinstallMessage @async()
  68. grunt.registerTask 'update:all', "Checkout and update all ShareLaTeX services",
  69. ["check:make"].concat(
  70. ("update:#{service.name}" for service in SERVICES)
  71. )
  72. grunt.registerTask 'update', 'update:all'
  73. grunt.registerTask 'run', "Run all of the sharelatex processes", ['concurrent:all']
  74. grunt.registerTask 'run:all', 'run'
  75. grunt.registerTask 'help', 'Display this help list', 'availabletasks'
  76. grunt.registerTask 'default', 'run'
  77. grunt.registerTask "check:redis", "Check that redis is installed and running", () ->
  78. Helpers.checkRedisConnect @async()
  79. grunt.registerTask "check:mongo", "Check that mongo is installed", () ->
  80. Helpers.checkMongoConnect @async()
  81. grunt.registerTask "check", "Check that you have the required dependencies installed", ["check:redis", "check:mongo", "check:make"]
  82. grunt.registerTask "check:make", "Check that make is installed", () ->
  83. Helpers.checkMake @async()
  84. Helpers =
  85. installService: (service, callback = (error) ->) ->
  86. console.log "Installing #{service.name}"
  87. Helpers.cloneGitRepo service, (error) ->
  88. if error?
  89. callback(error)
  90. else
  91. callback()
  92. cloneGitRepo: (service, callback = (error) ->) ->
  93. repo_src = service.repo
  94. dir = service.name
  95. if !fs.existsSync(dir)
  96. proc = spawn "git", [
  97. "clone",
  98. repo_src,
  99. dir
  100. ], stdio: "inherit"
  101. proc.on "close", () ->
  102. Helpers.checkoutVersion service, callback
  103. else
  104. console.log "#{dir} already installed, skipping."
  105. callback()
  106. checkoutVersion: (service, callback = (error) ->) ->
  107. dir = service.name
  108. grunt.log.write "checking out #{service.name} #{service.version}"
  109. proc = spawn "git", ["checkout", service.version], stdio: "inherit", cwd: dir
  110. proc.on "close", () ->
  111. callback()
  112. postinstallMessage: (callback = (error) ->) ->
  113. grunt.log.write """
  114. Services cloned:
  115. #{service.name for service in SERVICES}
  116. To install services run:
  117. $ source bin/install-services
  118. This will install the required node versions and run `npm install` for each service.
  119. See https://github.com/sharelatex/sharelatex/pull/549 for more info.
  120. """
  121. callback()
  122. checkMake: (callback = (error) ->) ->
  123. grunt.log.write "Checking make is installed... "
  124. exec "make --version", (error, stdout, stderr) ->
  125. if error? and error.message.match("not found")
  126. grunt.log.error "FAIL."
  127. grunt.log.errorlns """
  128. Either make is not installed or is not in your path.
  129. On Ubuntu you can install make with:
  130. sudo apt-get install build-essential
  131. """
  132. return callback(error)
  133. else if error?
  134. return callback(error)
  135. else
  136. grunt.log.write "OK."
  137. return callback()
  138. checkMongoConnect: (callback = (error) ->) ->
  139. grunt.log.write "Checking can connect to mongo"
  140. mongojs = require("mongojs")
  141. db = mongojs(settings.mongo.url, ["tags"])
  142. db.runCommand { ping: 1 }, (err, res) ->
  143. if !err and res.ok
  144. grunt.log.write "OK."
  145. return callback()
  146. db.on 'error', (err)->
  147. err = "Can not connect to mongodb"
  148. grunt.log.error "FAIL."
  149. grunt.log.errorlns """
  150. !!!!!!!!!!!!!! MONGO ERROR !!!!!!!!!!!!!!
  151. ShareLaTeX can not talk to the mongodb instance
  152. Check the mongodb instance is running and accessible on env var SHARELATEX_MONGO_URL
  153. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  154. """
  155. throw new Error("Can not connect to Mongodb")
  156. return callback(err)
  157. checkRedisConnect: (callback = (error) ->) ->
  158. grunt.log.write "Checking can connect to redis\n"
  159. rclient = require("redis").createClient(settings.redis.web)
  160. rclient.ping (err, res) ->
  161. if !err?
  162. grunt.log.write "OK."
  163. else
  164. throw new Error("Can not connect to redis")
  165. return callback()
  166. errorHandler = _.once (err)->
  167. err = "Can not connect to redis"
  168. grunt.log.error "FAIL."
  169. grunt.log.errorlns """
  170. !!!!!!!!!!!!!! REDIS ERROR !!!!!!!!!!!!!!
  171. ShareLaTeX can not talk to the redis instance
  172. Check the redis instance is running and accessible on env var SHARELATEX_REDIS_HOST
  173. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  174. """
  175. throw new Error("Can not connect to redis")
  176. return callback(err)
  177. rclient.on 'error', errorHandler