index.js 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. var fs = require('graceful-fs')
  2. var path = require('path')
  3. var writers = {}
  4. // Returns a temporary file
  5. // Example: for /some/file will return /some/.~file
  6. function getTempFile (file) {
  7. return path.join(path.dirname(file), '.~' + path.basename(file))
  8. }
  9. function Writer (file) {
  10. this.file = file
  11. this.callbacks = []
  12. this.nextData = null
  13. this.nextCallbacks = []
  14. }
  15. Writer.prototype.write = function (data, cb) {
  16. if (this.lock) {
  17. // File is locked
  18. // Save callback for later
  19. this.nextCallbacks.push(cb)
  20. // Set next data to be written
  21. this.nextData = data
  22. } else {
  23. // File is not locked
  24. // Lock it
  25. this.lock = true
  26. // Write data to a temporary file
  27. var tmpFile = getTempFile(this.file)
  28. fs.writeFile(tmpFile, data, function (err) {
  29. if (err) {
  30. // On error, call all the stored callbacks and the current one
  31. // Then return
  32. while (this.callbacks.length) this.callbacks.shift()(err)
  33. cb(err)
  34. return
  35. }
  36. // On success rename the temporary file to the real file
  37. fs.rename(tmpFile, this.file, function (err) {
  38. // call all the stored callbacks and the current one
  39. while (this.callbacks.length) this.callbacks.shift()(err)
  40. cb()
  41. // Unlock file
  42. this.lock = false
  43. // Write next data if any
  44. if (this.nextData) {
  45. var data = this.nextData
  46. this.callbacks = this.nextCallbacks
  47. this.nextData = null
  48. this.nextCallbacks = []
  49. this.write(data, this.callbacks.pop())
  50. }
  51. }.bind(this))
  52. }.bind(this))
  53. }
  54. }
  55. module.exports.writeFile = function (file, data, cb) {
  56. // Convert to absolute path
  57. file = path.resolve(file)
  58. // Create or get writer
  59. writers[file] = writers[file] || new Writer(file)
  60. // Write
  61. writers[file].write(data, cb)
  62. }
  63. module.exports.writeFileSync = function (file, data) {
  64. fs.writeFileSync(getTempFile(file), data)
  65. fs.renameSync(getTempFile(file), file)
  66. }