Gruntfile.coffee 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. fs = require "fs"
  2. module.exports = (grunt) ->
  3. grunt.loadNpmTasks 'grunt-contrib-coffee'
  4. grunt.loadNpmTasks 'grunt-contrib-less'
  5. grunt.loadNpmTasks 'grunt-contrib-clean'
  6. grunt.loadNpmTasks 'grunt-mocha-test'
  7. grunt.loadNpmTasks 'grunt-available-tasks'
  8. grunt.loadNpmTasks 'grunt-contrib-requirejs'
  9. grunt.loadNpmTasks 'grunt-bunyan'
  10. grunt.loadNpmTasks 'grunt-sed'
  11. grunt.loadNpmTasks 'grunt-git-rev-parse'
  12. grunt.loadNpmTasks 'grunt-file-append'
  13. grunt.loadNpmTasks 'grunt-file-append'
  14. grunt.loadNpmTasks 'grunt-env'
  15. grunt.loadNpmTasks 'grunt-newer'
  16. grunt.loadNpmTasks 'grunt-contrib-watch'
  17. grunt.loadNpmTasks 'grunt-parallel'
  18. grunt.loadNpmTasks 'grunt-exec'
  19. config =
  20. exec:
  21. run:
  22. command:"node app.js | ./node_modules/logger-sharelatex/node_modules/bunyan/bin/bunyan --color"
  23. watch:
  24. coffee:
  25. files: '**/*.coffee'
  26. tasks: ['quickcompile:coffee']
  27. options: {}
  28. less:
  29. files: '**/*.less'
  30. tasks: ['compile:css']
  31. options: {}
  32. parallel:
  33. run:
  34. tasks:['exec', 'watch']
  35. options:
  36. grunt:true
  37. stream:true
  38. coffee:
  39. app_dir:
  40. expand: true,
  41. flatten: false,
  42. cwd: 'app/coffee',
  43. src: ['**/*.coffee'],
  44. dest: 'app/js/',
  45. ext: '.js'
  46. app:
  47. src: 'app.coffee'
  48. dest: 'app.js'
  49. sharejs:
  50. options:
  51. join: true
  52. files:
  53. "public/js/libs/sharejs.js": [
  54. "public/coffee/ide/editor/sharejs/header.coffee"
  55. "public/coffee/ide/editor/sharejs/vendor/types/helpers.coffee"
  56. "public/coffee/ide/editor/sharejs/vendor/types/text.coffee"
  57. "public/coffee/ide/editor/sharejs/vendor/types/text-api.coffee"
  58. "public/coffee/ide/editor/sharejs/vendor/client/microevent.coffee"
  59. "public/coffee/ide/editor/sharejs/vendor/client/doc.coffee"
  60. "public/coffee/ide/editor/sharejs/vendor/client/ace.coffee"
  61. ]
  62. client:
  63. expand: true,
  64. flatten: false,
  65. cwd: 'public/coffee',
  66. src: ['**/*.coffee'],
  67. dest: 'public/js/',
  68. ext: '.js'
  69. smoke_tests:
  70. expand: true,
  71. flatten: false,
  72. cwd: 'test/smoke/coffee',
  73. src: ['**/*.coffee'],
  74. dest: 'test/smoke/js/',
  75. ext: '.js'
  76. unit_tests:
  77. expand: true,
  78. flatten: false,
  79. cwd: 'test/UnitTests/coffee',
  80. src: ['**/*.coffee'],
  81. dest: 'test/UnitTests/js/',
  82. ext: '.js'
  83. acceptance_tests:
  84. expand: true,
  85. flatten: false,
  86. cwd: 'test/acceptance/coffee',
  87. src: ['**/*.coffee'],
  88. dest: 'test/acceptance/js/',
  89. ext: '.js'
  90. less:
  91. app:
  92. files:
  93. "public/stylesheets/style.css": "public/stylesheets/style.less"
  94. env:
  95. run:
  96. add:
  97. NODE_TLS_REJECT_UNAUTHORIZED:0
  98. requirejs:
  99. compile:
  100. options:
  101. optimize:"uglify2"
  102. uglify2:
  103. mangle: false
  104. appDir: "public/js"
  105. baseUrl: "./"
  106. dir: "public/minjs"
  107. inlineText: false
  108. preserveLicenseComments: false
  109. paths:
  110. "moment": "libs/moment-2.9.0"
  111. "mathjax": "/js/libs/mathjax/MathJax.js?config=TeX-AMS_HTML"
  112. "libs/pdf": "libs/pdfjs-1.3.91/pdf"
  113. shim:
  114. "libs/pdf":
  115. deps: ["libs/pdfjs-1.3.91/compatibility"]
  116. skipDirOptimize: true
  117. modules: [
  118. {
  119. name: "main",
  120. exclude: ["libs"]
  121. }, {
  122. name: "ide",
  123. exclude: ["libs", "libs/pdf"]
  124. }, {
  125. name: "libs"
  126. },{
  127. name: "ace/mode-latex"
  128. }
  129. ]
  130. clean:
  131. app: ["app/js"]
  132. unit_tests: ["test/UnitTests/js"]
  133. acceptance_tests: ["test/acceptance/js"]
  134. mochaTest:
  135. unit:
  136. src: ["test/UnitTests/js/#{grunt.option('feature') or '**'}/*.js"]
  137. options:
  138. reporter: grunt.option('reporter') or 'spec'
  139. grep: grunt.option("grep")
  140. smoke:
  141. src: ['test/smoke/js/**/*.js']
  142. options:
  143. reporter: grunt.option('reporter') or 'spec'
  144. grep: grunt.option("grep")
  145. acceptance:
  146. src: ["test/acceptance/js/#{grunt.option('feature') or '**'}/*.js"]
  147. options:
  148. timeout: 10000
  149. reporter: grunt.option('reporter') or 'spec'
  150. grep: grunt.option("grep")
  151. "git-rev-parse":
  152. version:
  153. options:
  154. prop: 'commit'
  155. file_append:
  156. default_options: files: [ {
  157. append: '\n//ide.js is complete - used for automated testing'
  158. input: 'public/minjs/ide.js'
  159. output: 'public/minjs/ide.js'
  160. }]
  161. sed:
  162. version:
  163. path: "app/views/sentry.jade"
  164. pattern: '@@COMMIT@@',
  165. replacement: '<%= commit %>',
  166. release:
  167. path: "app/views/sentry.jade"
  168. pattern: "@@RELEASE@@"
  169. replacement: process.env.BUILD_NUMBER || "(unknown build)"
  170. availabletasks:
  171. tasks:
  172. options:
  173. filter: 'exclude',
  174. tasks: [
  175. 'coffee'
  176. 'less'
  177. 'clean'
  178. 'mochaTest'
  179. 'availabletasks'
  180. 'wrap_sharejs'
  181. 'requirejs'
  182. 'execute'
  183. 'bunyan'
  184. ]
  185. groups:
  186. "Compile tasks": [
  187. "compile:server"
  188. "compile:client"
  189. "compile:tests"
  190. "compile"
  191. "compile:unit_tests"
  192. "compile:smoke_tests"
  193. "compile:css"
  194. "compile:minify"
  195. "install"
  196. ]
  197. "Test tasks": [
  198. "test:unit"
  199. "test:acceptance"
  200. ]
  201. "Run tasks": [
  202. "run"
  203. "default"
  204. ]
  205. "Misc": [
  206. "help"
  207. ]
  208. moduleCompileServerTasks = []
  209. moduleCompileUnitTestTasks = []
  210. moduleUnitTestTasks = []
  211. moduleCompileClientTasks = []
  212. moduleIdeClientSideIncludes = []
  213. moduleMainClientSideIncludes = []
  214. if fs.existsSync "./modules"
  215. for module in fs.readdirSync "./modules"
  216. if fs.existsSync "./modules/#{module}/index.coffee"
  217. config.coffee["module_#{module}_server"] = {
  218. expand: true,
  219. flatten: false,
  220. cwd: "modules/#{module}/app/coffee",
  221. src: ['**/*.coffee'],
  222. dest: "modules/#{module}/app/js",
  223. ext: '.js'
  224. }
  225. config.coffee["module_#{module}_index"] = {
  226. src: "modules/#{module}/index.coffee",
  227. dest: "modules/#{module}/index.js"
  228. }
  229. moduleCompileServerTasks.push "coffee:module_#{module}_server"
  230. moduleCompileServerTasks.push "coffee:module_#{module}_index"
  231. config.coffee["module_#{module}_unit_tests"] = {
  232. expand: true,
  233. flatten: false,
  234. cwd: "modules/#{module}/test/unit/coffee",
  235. src: ['**/*.coffee'],
  236. dest: "modules/#{module}/test/unit/js",
  237. ext: '.js'
  238. }
  239. config.mochaTest["module_#{module}_unit"] = {
  240. src: ["modules/#{module}/test/unit/js/*.js"]
  241. options:
  242. reporter: grunt.option('reporter') or 'spec'
  243. grep: grunt.option("grep")
  244. }
  245. moduleCompileUnitTestTasks.push "coffee:module_#{module}_unit_tests"
  246. moduleUnitTestTasks.push "mochaTest:module_#{module}_unit"
  247. if fs.existsSync "./modules/#{module}/public/coffee/ide/index.coffee"
  248. config.coffee["module_#{module}_client_ide"] = {
  249. expand: true,
  250. flatten: false,
  251. cwd: "modules/#{module}/public/coffee/ide",
  252. src: ['**/*.coffee'],
  253. dest: "public/js/ide/#{module}",
  254. ext: '.js'
  255. }
  256. moduleCompileClientTasks.push "coffee:module_#{module}_client_ide"
  257. moduleIdeClientSideIncludes.push "ide/#{module}/index"
  258. if fs.existsSync "./modules/#{module}/public/coffee/main/index.coffee"
  259. config.coffee["module_#{module}_client_main"] = {
  260. expand: true,
  261. flatten: false,
  262. cwd: "modules/#{module}/public/coffee/main",
  263. src: ['**/*.coffee'],
  264. dest: "public/js/main/#{module}",
  265. ext: '.js'
  266. }
  267. moduleCompileClientTasks.push "coffee:module_#{module}_client_main"
  268. moduleMainClientSideIncludes.push "main/#{module}/index"
  269. grunt.initConfig config
  270. grunt.registerTask 'wrap_sharejs', 'Wrap the compiled ShareJS code for AMD module loading', () ->
  271. content = fs.readFileSync "public/js/libs/sharejs.js"
  272. fs.writeFileSync "public/js/libs/sharejs.js", """
  273. define(["ace/ace"], function() {
  274. #{content}
  275. return window.sharejs;
  276. });
  277. """
  278. grunt.registerTask 'help', 'Display this help list', 'availabletasks'
  279. grunt.registerTask 'compile:modules:server', 'Compile all the modules', moduleCompileServerTasks
  280. grunt.registerTask 'compile:modules:unit_tests', 'Compile all the modules unit tests', moduleCompileUnitTestTasks
  281. grunt.registerTask 'compile:modules:client', 'Compile all the module client side code', moduleCompileClientTasks
  282. grunt.registerTask 'compile:modules:inject_clientside_includes', () ->
  283. content = fs.readFileSync("public/js/ide.js").toString()
  284. content = content.replace(/, "__IDE_CLIENTSIDE_INCLUDES__"/g, moduleIdeClientSideIncludes.map((i) -> ", \"#{i}\"").join(""))
  285. fs.writeFileSync "public/js/ide.js", content
  286. content = fs.readFileSync("public/js/main.js").toString()
  287. content = content.replace(/, "__MAIN_CLIENTSIDE_INCLUDES__"/g, moduleMainClientSideIncludes.map((i) -> ", \"#{i}\"").join(""))
  288. fs.writeFileSync "public/js/main.js", content
  289. grunt.registerTask 'compile:server', 'Compile the server side coffee script', ['clean:app', 'coffee:app', 'coffee:app_dir', 'compile:modules:server']
  290. grunt.registerTask 'compile:client', 'Compile the client side coffee script', ['coffee:client', 'coffee:sharejs', 'wrap_sharejs', "compile:modules:client", 'compile:modules:inject_clientside_includes']
  291. grunt.registerTask 'compile:css', 'Compile the less files to css', ['less']
  292. grunt.registerTask 'compile:minify', 'Concat and minify the client side js', ['requirejs', "file_append"]
  293. grunt.registerTask 'compile:unit_tests', 'Compile the unit tests', ['clean:unit_tests', 'coffee:unit_tests']
  294. grunt.registerTask 'compile:acceptance_tests', 'Compile the acceptance tests', ['clean:acceptance_tests', 'coffee:acceptance_tests']
  295. grunt.registerTask 'compile:smoke_tests', 'Compile the smoke tests', ['coffee:smoke_tests']
  296. grunt.registerTask 'compile:tests', 'Compile all the tests', ['compile:smoke_tests', 'compile:unit_tests']
  297. grunt.registerTask 'compile', 'Compiles everything need to run web-sharelatex', ['compile:server', 'compile:client', 'compile:css']
  298. grunt.registerTask 'quickcompile:coffee', 'Compiles only changed coffee files',['newer:coffee']
  299. grunt.registerTask 'install', "Compile everything when installing as an npm module", ['compile']
  300. grunt.registerTask 'test:unit', 'Run the unit tests (use --grep=<regex> or --feature=<feature> for individual tests)', ['compile:server', 'compile:modules:server', 'compile:unit_tests', 'compile:modules:unit_tests', 'mochaTest:unit'].concat(moduleUnitTestTasks)
  301. grunt.registerTask 'test:acceptance', 'Run the acceptance tests (use --grep=<regex> or --feature=<feature> for individual tests)', ['compile:acceptance_tests', 'mochaTest:acceptance']
  302. grunt.registerTask 'test:smoke', 'Run the smoke tests', ['compile:smoke_tests', 'mochaTest:smoke']
  303. grunt.registerTask 'test:modules:unit', 'Run the unit tests for the modules', ['compile:modules:server', 'compile:modules:unit_tests'].concat(moduleUnitTestTasks)
  304. grunt.registerTask 'run', "Compile and run the web-sharelatex server", ['compile', 'env:run', 'parallel']
  305. grunt.registerTask 'default', 'run'
  306. grunt.registerTask 'version', "Write the version number into sentry.jade", ['git-rev-parse', 'sed']
  307. grunt.registerTask 'create-admin-user', "Create a user with the given email address and make them an admin. Update in place if the user already exists", () ->
  308. done = @async()
  309. email = grunt.option("email")
  310. if !email?
  311. console.error "Usage: grunt create-admin-user --email joe@example.com"
  312. process.exit(1)
  313. settings = require "settings-sharelatex"
  314. UserRegistrationHandler = require "./app/js/Features/User/UserRegistrationHandler"
  315. OneTimeTokenHandler = require "./app/js/Features/Security/OneTimeTokenHandler"
  316. UserRegistrationHandler.registerNewUser {
  317. email: email
  318. password: require("crypto").randomBytes(32).toString("hex")
  319. }, (error, user) ->
  320. if error? and error?.message != "EmailAlreadyRegistered"
  321. throw error
  322. user.isAdmin = true
  323. user.save (error) ->
  324. throw error if error?
  325. ONE_WEEK = 7 * 24 * 60 * 60 # seconds
  326. OneTimeTokenHandler.getNewToken user._id, { expiresIn: ONE_WEEK }, (err, token)->
  327. return next(err) if err?
  328. console.log ""
  329. console.log """
  330. Successfully created #{email} as an admin user.
  331. Please visit the following URL to set a password for #{email} and log in:
  332. #{settings.siteUrl}/user/password/set?passwordResetToken=#{token}
  333. """
  334. done()
  335. grunt.registerTask 'delete-user', "deletes a user and all their data", () ->
  336. done = @async()
  337. email = grunt.option("email")
  338. if !email?
  339. console.error "Usage: grunt delete-user --email joe@example.com"
  340. process.exit(1)
  341. settings = require "settings-sharelatex"
  342. UserGetter = require "./app/js/Features/User/UserGetter"
  343. UserDeleter = require "./app/js/Features/User/UserDeleter"
  344. UserGetter.getUser email:email, (error, user) ->
  345. if error?
  346. throw error
  347. if !user?
  348. console.log("user #{email} not in database, potentially already deleted")
  349. return done()
  350. UserDeleter.deleteUser user._id, (err)->
  351. if err?
  352. throw err
  353. done()