diff --git a/lib/dest/writeContents/writeDir.js b/lib/dest/writeContents/writeDir.js index ef7622c9..82c8325f 100644 --- a/lib/dest/writeContents/writeDir.js +++ b/lib/dest/writeContents/writeDir.js @@ -1,16 +1,11 @@ 'use strict'; var fs = require('graceful-fs'); -var mkdirp = require('mkdirp'); var fo = require('../../fileOperations'); function writeDir(writePath, file, written) { - var mkdirpOpts = { - mode: file.stat.mode, - fs: fs, - }; - mkdirp(writePath, mkdirpOpts, onMkdirp); + fo.mkdirp(writePath, file.stat.mode, onMkdirp); function onMkdirp(mkdirpErr) { if (mkdirpErr) { diff --git a/lib/fileOperations.js b/lib/fileOperations.js index e323fb70..db0cae76 100644 --- a/lib/fileOperations.js +++ b/lib/fileOperations.js @@ -1,6 +1,7 @@ 'use strict'; var fs = require('graceful-fs'); +var path = require('path'); var assign = require('object-assign'); var isEqual = require('lodash.isequal'); var isValidDate = require('vali-date'); @@ -9,6 +10,7 @@ var isValidDate = require('vali-date'); // TODO include sticky/setuid/setgid, i.e. 7777? var MASK_MODE = parseInt('0777', 8); var DEFAULT_FILE_MODE = parseInt('0666', 8); +var DEFAULT_DIR_MODE = parseInt('0777', 8); var APPEND_MODE_REGEXP = /a/; function closeFd(propagatedErr, fd, callback) { @@ -161,7 +163,7 @@ function updateMetadata(fd, file, callback) { file descriptor after the write is complete. Most of the implementation taken from node core. */ -function writeFile(path, data, options, callback) { +function writeFile(filepath, data, options, callback) { if (typeof options === 'function') { callback = options; options = {}; @@ -181,7 +183,7 @@ function writeFile(path, data, options, callback) { var flag = options.flag || 'w'; var position = APPEND_MODE_REGEXP.test(flag) ? null : 0; - fs.open(path, flag, mode, onOpen); + fs.open(filepath, flag, mode, onOpen); function onOpen(err, fd) { if (err) { @@ -196,6 +198,49 @@ function writeFile(path, data, options, callback) { } } +function mkdirp(dirpath, mode, callback) { + if (typeof mode === 'function') { + callback = mode; + mode = undefined; + } + + var m = mode || DEFAULT_DIR_MODE; + var cb = callback || function() {}; + dirpath = path.resolve(dirpath); + + fs.mkdir(dirpath, m, function(er) { + if (!er) { + return cb(); + } + switch (er.code) { + case 'ENOENT': { + mkdirp(path.dirname(dirpath), m, function(er) { + if (er) { + cb(er); + } else { + mkdirp(dirpath, m, cb); + } + }); + break; + } + + case 'EEXIST': { + if (mode) { + fs.chmod(dirpath, mode, cb); + } else { + cb(); + } + break; + } + + default: { + cb(er); + break; + } + } + }); +} + module.exports = { closeFd: closeFd, getModeDiff: getModeDiff, @@ -203,4 +248,5 @@ module.exports = { isOwner: isOwner, updateMetadata: updateMetadata, writeFile: writeFile, + mkdirp: mkdirp, }; diff --git a/lib/prepareWrite.js b/lib/prepareWrite.js index 50d86cd1..152663ec 100644 --- a/lib/prepareWrite.js +++ b/lib/prepareWrite.js @@ -2,8 +2,8 @@ var assign = require('object-assign'); var path = require('path'); -var mkdirp = require('mkdirp'); var fs = require('graceful-fs'); +var fo = require('./fileOperations'); function booleanOrFunc(v, file) { if (typeof v !== 'boolean' && typeof v !== 'function') { @@ -53,12 +53,7 @@ function prepareWrite(outFolder, file, opt, cb) { file.base = basePath; file.path = writePath; - // Mkdirp the folder the file is going in - var mkdirpOpts = { - mode: options.dirMode, - fs: fs, - }; - mkdirp(writeFolder, mkdirpOpts, function(err) { + fo.mkdirp(writeFolder, options.dirMode, function(err) { if (err) { return cb(err); } diff --git a/package.json b/package.json index cca6081b..0ad58387 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ "lazystream": "^1.0.0", "lodash.isequal": "^4.0.0", "merge-stream": "^1.0.0", - "mkdirp": "^0.5.0", "object-assign": "^4.0.0", "readable-stream": "^2.0.4", "strip-bom": "^2.0.0", diff --git a/test/dest.js b/test/dest.js index ef0431b4..96c1f6ec 100644 --- a/test/dest.js +++ b/test/dest.js @@ -1100,12 +1100,12 @@ describe('dest stream', function() { }); var stream = vfs.dest(outputDir); - stream.write(expectedFile); stream.on('error', function(err) { expect(err).toExist(); expect(mkdirSpy.calls.length).toEqual(1); done(); }); + stream.write(expectedFile); }); it('errors if vinyl object is a directory and we cannot mkdirp', function(done) { diff --git a/test/fileOperations.js b/test/fileOperations.js index c5ccaac6..912895b0 100644 --- a/test/fileOperations.js +++ b/test/fileOperations.js @@ -12,6 +12,7 @@ var defaultResolution = require('default-resolution'); var fo = require('../lib/fileOperations'); +var mkdirp = fo.mkdirp; var closeFd = fo.closeFd; var isOwner = fo.isOwner; var writeFile = fo.writeFile; @@ -892,3 +893,121 @@ describe('updateMetadata', function() { }); }); }); + +describe('mkdirp', function() { + var DEFAULT_DIR_MODE = parseInt('0777', 8); + var MODE_MASK = parseInt('0777', 8); + + it('makes single directory', function(done) { + if (isWindows) { + this.skip(); + return; + } + + var dir = path.join(__dirname, './fixtures/bif'); + mkdirp(dir, function(err) { + expect(err).toNotExist(); + + fs.stat(dir, function(err2, stats) { + expect(err2).toNotExist(); + expect(stats.mode & MODE_MASK).toEqual(DEFAULT_DIR_MODE & ~process.umask()); + del(dir); + + done(); + }); + }); + }); + + it('makes multiple directories', function(done) { + if (isWindows) { + this.skip(); + return; + } + + var dir = path.join(__dirname, './fixtures/bif/bam/bof'); + mkdirp(dir, function(err) { + expect(err).toNotExist(); + + fs.stat(dir, function(err2, stats) { + expect(err2).toNotExist(); + expect(stats.mode & MODE_MASK).toEqual(DEFAULT_DIR_MODE & ~process.umask()); + del(path.join(__dirname, './fixtures/bif')); + + done(); + }); + }); + }); + + it('makes directory with mode', function(done) { + if (isWindows) { + this.skip(); + return; + } + + var dir = path.join(__dirname, './fixtures/bif'); + var mode = parseInt('0700',8); + mkdirp(dir, mode, function(err) { + expect(err).toNotExist(); + + fs.stat(dir, function(err2, stats) { + expect(err2).toNotExist(); + expect(stats.mode & MODE_MASK).toEqual(mode & ~process.umask()); + del(dir).then(function() { + done(); + }); + }); + }); + }); + + it('makes multiple directories with mode', function(done) { + if (isWindows) { + this.skip(); + return; + } + + var dir = path.join(__dirname, './fixtures/bif/bam/bof'); + var mode = parseInt('0700',8); + mkdirp(dir, mode, function(err) { + expect(err).toNotExist(); + + fs.stat(dir, function(err2, stats) { + expect(err2).toNotExist(); + expect(stats.mode & MODE_MASK).toEqual(mode & ~process.umask()); + del(path.join(__dirname, './fixtures/bif')) + .then(function() { + done(); + }); + }); + }); + }); + + it('changes mode of existing directory', function(done) { + if (isWindows) { + this.skip(); + return; + } + + var dir = path.join(__dirname, './fixtures/bif'); + var mode = parseInt('0700',8); + mkdirp(dir, function(err) { + expect(err).toNotExist(); + + fs.stat(dir, function(err2, stats) { + expect(err2).toNotExist(); + expect(stats.mode & MODE_MASK).toEqual(DEFAULT_DIR_MODE & ~process.umask()); + + mkdirp(dir, mode, function(err3) { + expect(err3).toNotExist(); + + fs.stat(dir, function(err4, stats) { + expect(err2).toNotExist(); + expect(stats.mode & MODE_MASK).toEqual(mode & ~process.umask()); + del(path.join(__dirname, './fixtures/bif')); + + done(); + }); + }); + }); + }); + }); +});