Gruntfile.coffee 13 KB

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