ArchiveManager.coffee 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. child = require "child_process"
  2. logger = require "logger-sharelatex"
  3. metrics = require "../../infrastructure/Metrics"
  4. fs = require "fs"
  5. Path = require "path"
  6. _ = require("underscore")
  7. ONE_MEG = 1024 * 1024
  8. module.exports = ArchiveManager =
  9. _isZipTooLarge: (source, callback = (err, isTooLarge)->)->
  10. callback = _.once callback
  11. unzip = child.spawn("unzip", ["-l", source])
  12. output = ""
  13. unzip.stdout.on "data", (d)->
  14. output += d
  15. error = null
  16. unzip.stderr.on "data", (chunk) ->
  17. error ||= ""
  18. error += chunk
  19. unzip.on "error", (err) ->
  20. logger.error {err, source}, "unzip failed"
  21. if err.code == "ENOENT"
  22. logger.error "unzip command not found. Please check the unzip command is installed"
  23. callback(err)
  24. unzip.on "close", (exitCode) ->
  25. if error?
  26. error = new Error(error)
  27. logger.error err:error, source: source, "error checking zip size"
  28. lines = output.split("\n")
  29. lastLine = lines[lines.length - 2]?.trim()
  30. totalSizeInBytes = lastLine?.split(" ")?[0]
  31. totalSizeInBytesAsInt = parseInt(totalSizeInBytes)
  32. if !totalSizeInBytesAsInt? or isNaN(totalSizeInBytesAsInt)
  33. logger.err source:source, totalSizeInBytes:totalSizeInBytes, totalSizeInBytesAsInt:totalSizeInBytesAsInt, lastLine:lastLine, exitCode:exitCode, "error getting bytes of zip"
  34. return callback(new Error("error getting bytes of zip"))
  35. isTooLarge = totalSizeInBytes > (ONE_MEG * 300)
  36. callback(error, isTooLarge)
  37. extractZipArchive: (source, destination, _callback = (err) ->) ->
  38. callback = (args...) ->
  39. _callback(args...)
  40. _callback = () ->
  41. ArchiveManager._isZipTooLarge source, (err, isTooLarge)->
  42. if err?
  43. logger.err err:err, "error checking size of zip file"
  44. return callback(err)
  45. if isTooLarge
  46. return callback(new Error("zip_too_large"))
  47. timer = new metrics.Timer("unzipDirectory")
  48. logger.log source: source, destination: destination, "unzipping file"
  49. unzip = child.spawn("unzip", [source, "-d", destination])
  50. # don't remove this line, some zips need
  51. # us to listen on this for some unknow reason
  52. unzip.stdout.on "data", (d)->
  53. error = null
  54. unzip.stderr.on "data", (chunk) ->
  55. error ||= ""
  56. error += chunk
  57. unzip.on "error", (err) ->
  58. logger.error {err, source, destination}, "unzip failed"
  59. if err.code == "ENOENT"
  60. logger.error "unzip command not found. Please check the unzip command is installed"
  61. callback(err)
  62. unzip.on "close", () ->
  63. timer.done()
  64. if error?
  65. error = new Error(error)
  66. logger.error err:error, source: source, destination: destination, "error unzipping file"
  67. callback(error)
  68. findTopLevelDirectory: (directory, callback = (error, topLevelDir) ->) ->
  69. fs.readdir directory, (error, files) ->
  70. return callback(error) if error?
  71. if files.length == 1
  72. childPath = Path.join(directory, files[0])
  73. fs.stat childPath, (error, stat) ->
  74. return callback(error) if error?
  75. if stat.isDirectory()
  76. return callback(null, childPath)
  77. else
  78. return callback(null, directory)
  79. else
  80. return callback(null, directory)