Gruntfile.coffee 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. coffee:
  35. migrate:
  36. expand: true,
  37. flatten: false,
  38. cwd: './',
  39. src: ['./migrations/*.coffee'],
  40. dest: './',
  41. ext: '.js'
  42. options:
  43. bare:true
  44. shell:
  45. migrate:
  46. command: "./node_modules/east/bin/east migrate --adapter east-mongo --url #{settings?.mongo?.url}"
  47. availabletasks:
  48. tasks:
  49. options:
  50. filter: 'exclude',
  51. tasks: [
  52. 'concurrent'
  53. 'execute'
  54. 'bunyan'
  55. 'availabletasks'
  56. ]
  57. groups:
  58. "Run tasks": [
  59. "run"
  60. "run:all"
  61. "default"
  62. ].concat ("run:#{service.name}" for service in SERVICES)
  63. "Misc": [
  64. "help"
  65. ]
  66. "Install tasks": ("install:#{service.name}" for service in SERVICES).concat(["install:all", "install"])
  67. "Update tasks": ("update:#{service.name}" for service in SERVICES).concat(["update:all", "update"])
  68. "Checks": ["check", "check:redis", "check:latexmk", "check:s3", "check:make", "check:mongo"]
  69. for service in SERVICES
  70. do (service) ->
  71. grunt.registerTask "install:#{service.name}", "Download and set up the #{service.name} service", () ->
  72. done = @async()
  73. Helpers.installService(service, done)
  74. grunt.registerTask 'install:all', "Download and set up all ShareLaTeX services",
  75. [].concat(
  76. ("install:#{service.name}" for service in SERVICES)
  77. ).concat(['postinstall'])
  78. grunt.registerTask 'install', 'install:all'
  79. grunt.registerTask 'postinstall', 'Explain postinstall steps', () ->
  80. Helpers.postinstallMessage @async()
  81. grunt.registerTask 'update:all', "Checkout and update all ShareLaTeX services",
  82. ["check:make"].concat(
  83. ("update:#{service.name}" for service in SERVICES)
  84. )
  85. grunt.registerTask 'update', 'update:all'
  86. grunt.registerTask 'run', "Run all of the sharelatex processes", ['concurrent:all']
  87. grunt.registerTask 'run:all', 'run'
  88. grunt.registerTask 'help', 'Display this help list', 'availabletasks'
  89. grunt.registerTask 'default', 'run'
  90. grunt.registerTask "check:redis", "Check that redis is installed and running", () ->
  91. Helpers.checkRedisConnect @async()
  92. grunt.registerTask "check:mongo", "Check that mongo is installed", () ->
  93. Helpers.checkMongoConnect @async()
  94. grunt.registerTask "check", "Check that you have the required dependencies installed", ["check:redis", "check:mongo", "check:make"]
  95. grunt.registerTask "check:make", "Check that make is installed", () ->
  96. Helpers.checkMake @async()
  97. grunt.registerTask 'migrate', "compile migrations and run them", ["coffee:migrate", 'shell:migrate']
  98. Helpers =
  99. installService: (service, callback = (error) ->) ->
  100. console.log "Installing #{service.name}"
  101. Helpers.cloneGitRepo service, (error) ->
  102. if error?
  103. callback(error)
  104. else
  105. callback()
  106. cloneGitRepo: (service, callback = (error) ->) ->
  107. repo_src = service.repo
  108. dir = service.name
  109. if !fs.existsSync(dir)
  110. proc = spawn "git", [
  111. "clone",
  112. repo_src,
  113. dir
  114. ], stdio: "inherit"
  115. proc.on "close", () ->
  116. Helpers.checkoutVersion service, callback
  117. else
  118. console.log "#{dir} already installed, skipping."
  119. callback()
  120. checkoutVersion: (service, callback = (error) ->) ->
  121. dir = service.name
  122. grunt.log.write "checking out #{service.name} #{service.version}"
  123. proc = spawn "git", ["checkout", service.version], stdio: "inherit", cwd: dir
  124. proc.on "close", () ->
  125. callback()
  126. postinstallMessage: (callback = (error) ->) ->
  127. grunt.log.write """
  128. Services cloned:
  129. #{service.name for service in SERVICES}
  130. To install services run:
  131. $ source bin/install-services
  132. This will install the required node versions and run `npm install` for each service.
  133. See https://github.com/sharelatex/sharelatex/pull/549 for more info.
  134. """
  135. callback()
  136. checkMake: (callback = (error) ->) ->
  137. grunt.log.write "Checking make is installed... "
  138. exec "make --version", (error, stdout, stderr) ->
  139. if error? and error.message.match("not found")
  140. grunt.log.error "FAIL."
  141. grunt.log.errorlns """
  142. Either make is not installed or is not in your path.
  143. On Ubuntu you can install make with:
  144. sudo apt-get install build-essential
  145. """
  146. return callback(error)
  147. else if error?
  148. return callback(error)
  149. else
  150. grunt.log.write "OK."
  151. return callback()
  152. checkMongoConnect: (callback = (error) ->) ->
  153. grunt.log.write "Checking can connect to mongo"
  154. mongojs = require("mongojs")
  155. db = mongojs(settings.mongo.url, ["tags"])
  156. db.runCommand { ping: 1 }, (err, res) ->
  157. if !err and res.ok
  158. grunt.log.write "OK."
  159. return callback()
  160. db.on 'error', (err)->
  161. err = "Can not connect to mongodb"
  162. grunt.log.error "FAIL."
  163. grunt.log.errorlns """
  164. !!!!!!!!!!!!!! MONGO ERROR !!!!!!!!!!!!!!
  165. ShareLaTeX can not talk to the mongdb instance
  166. Check the mongodb instance is running and accessible on env var SHARELATEX_MONGO_URL
  167. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  168. """
  169. throw new Error("Can not connect to Mongodb")
  170. return callback(err)
  171. checkRedisConnect: (callback = (error) ->) ->
  172. grunt.log.write "Checking can connect to redis\n"
  173. rclient = require("redis").createClient(settings.redis.web)
  174. rclient.ping (err, res) ->
  175. if !err?
  176. grunt.log.write "OK."
  177. else
  178. throw new Error("Can not connect to redis")
  179. return callback()
  180. errorHandler = _.once (err)->
  181. err = "Can not connect to redis"
  182. grunt.log.error "FAIL."
  183. grunt.log.errorlns """
  184. !!!!!!!!!!!!!! REDIS ERROR !!!!!!!!!!!!!!
  185. ShareLaTeX can not talk to the redis instance
  186. Check the redis instance is running and accessible on env var SHARELATEX_REDIS_HOST
  187. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  188. """
  189. throw new Error("Can not connect to redis")
  190. return callback(err)
  191. rclient.on 'error', errorHandler