From d0a0bc4fbfbb25b169906711b22f9f9622fd3a3c Mon Sep 17 00:00:00 2001 From: Joshua Richardson Date: Fri, 29 Mar 2013 14:42:48 -0700 Subject: [PATCH 1/2] Added limit option to mkdirs(). --- README.md | 40 +++++++++++++++-- lib/mkdir.js | 53 +++++++++++++++++++++- package.json | 2 +- test/mkdir.test.js | 107 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 193 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2eec9ed8..d927968f 100644 --- a/README.md +++ b/README.md @@ -95,17 +95,18 @@ fs.createFile(file, function(err) { -### mkdirs(dir, callback) +### mkdirs(dir, [limit], callback) -Creates a directory. If the parent hierarchy doesn't exist, it's created. Like `mkdir -p`. +Creates a directory. If the parent hierarchy doesn't exist, it's created. Like `mkdir -p`. If `limit` is provided, `mkdirs` will create at most the specified number of parent directories (0 or more.) -Alias: `mkdirp()` +Alias: `mkdirp()` (but no "`limit`" support) Sync: `mkdirsSync()` / `mkdirpSync()` Examples: +Equivalent to mkdir -p ```javascript var fs = require('fs-extra'); @@ -121,6 +122,39 @@ fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function(err){ fs.mkdirsSync('/tmp/another/path'); ``` +Using the limit: +```javascript +var fs = require('fs-extra'); + +var root = path.join('usr', 'local', 'lib'); // forgot the initial '/' +var outdir = path.join(root, 'mylib', 'base'); +// Okay to make 'mylib', but fail if we try to recreate the root +fs.mkdirs(outdir, 1, function(err) { + if (err) { + console.error(err); + } + else { + console.log('success!'); + } +}); +``` + +Concise logic to ensure a directory exists +```javascript +var fs = require('fs-extra'); + +fs.mkdirsSync('mydir', 0); + +// Equivalent logic: +try { + fs.mkdirSync('mydir'); +} catch (err) { + if (err !== 'EEXIST') { + throw err; + } +} +``` + ### outputFile(file, data, callback) diff --git a/lib/mkdir.js b/lib/mkdir.js index fb8ac3ad..38572f8d 100644 --- a/lib/mkdir.js +++ b/lib/mkdir.js @@ -1,6 +1,55 @@ var mkdirp = require('mkdirp'); +var fs = require('fs'); +var path = require('path'); +var R = path.resolve; -module.exports.mkdirs = mkdirp; -module.exports.mkdirsSync = mkdirp.sync; +// mkdirs(dir, [limit], cb) +// limit: maximum number of parent directories to make +var mkdirs = function (dir, cb) { + var limit = -1; + if (arguments.length > 2) { + limit = cb; + cb = arguments[2]; + } + if (limit < 0 || limit === null) { mkdirp(dir, cb); } + else { + var components = R(dir).split(path.sep); + if (components.length && components[components.length - 1] === '') + { components.pop(); } + var parent_must_exist = components.slice(0, components.length-limit-1).join(path.sep); + if (parent_must_exist == '') { mkdirp(dir, cb); } + else { + fs.stat(parent_must_exist, function (err, st) { + if (err) { cb(err); } + else if (!st.isDirectory()) + { cb(new Error('not a directory: ' + parent_must_exist)); } + else { mkdirp(dir, cb); } + }); + } + } +} + +// mkdirsSync(dir, [limit]) +var mkdirsSync = function (dir) { + var limit = -1; + if (arguments.length > 1) { limit = arguments[1]; } + if (limit < 0 || limit === null) { mkdirp.sync(dir); } + else { + var components = R(dir).split(path.sep); + if (components.length && components[components.length - 1] === '') + { components.pop(); } + var parent_must_exist = components.slice(0, components.length-limit-1).join(path.sep); + if (parent_must_exist == '') { mkdirp.sync(dir); } + else { + var st = fs.statSync(parent_must_exist); + if (!st.isDirectory()) + { throw new Error('not a directory: ' + parent_must_exist); } + mkdirp.sync(dir); + } + } +} + +module.exports.mkdirs = mkdirs; +module.exports.mkdirsSync = mkdirsSync; diff --git a/package.json b/package.json index 53cd7878..e8970c9f 100755 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "text", "output" ], - "author": "JP Richardson ", + "author": "JP Richardson , Joshua Richardson ", "licenses": [ { "type": "MIT", diff --git a/test/mkdir.test.js b/test/mkdir.test.js index b6111a8a..f4da95cb 100644 --- a/test/mkdir.test.js +++ b/test/mkdir.test.js @@ -4,6 +4,67 @@ var fs = require('../lib') var TEST_DIR = '' +var testMkdirsWithLimit = function(limit, should_pass, done) { + var newDir = path.join(TEST_DIR, 'dfdf', 'ffff', 'aaa'); + // should work the same way with dangling seperators + var another = path.join(TEST_DIR, 'dfdf', 'ffff', 'bbb', ''); + + F (fs.existsSync(newDir)); + F (fs.existsSync(another)); + + fs.mkdirs(newDir, limit, function(err) { + if (should_pass) { + if (err !== null) { throw new Error('unexpected error: ' + err); } + T (fs.existsSync(newDir)); + } else { + F (err === null); + F (fs.existsSync(newDir)); + } + fs.mkdirs(another, limit, function(err) { + if (should_pass) { + if (err !== null) { throw new Error('unexpected error: ' + err); } + T (fs.existsSync(another)); + } else { + F (err === null); + F (fs.existsSync(another)); + } + done(); + }); + }); +}; + +var testMkdirsSyncWithLimit = function(limit, should_pass, done) { + var newDir = path.join(TEST_DIR, 'dfdf', 'ffff', 'aaa'); + // should work the same way with dangling seperators + var another = path.join(TEST_DIR, 'dfdf', 'ffff', 'bbb', ''); + + F (fs.existsSync(newDir)); + F (fs.existsSync(another)); + + try { + fs.mkdirsSync(newDir, limit); + } catch (err) { + if (should_pass) { throw new Error('unexpected error: ' + err); } + } + if (should_pass) { + T (fs.existsSync(newDir)); + } else { + F (fs.existsSync(newDir)); + } + try { + fs.mkdirsSync(another, limit); + } catch (err) { + if (should_pass) { throw new Error('unexpected error: ' + err); } + } + if (should_pass) { + T (fs.existsSync(another)); + } else { + F (fs.existsSync(another)); + } + + done(); +} + describe('fs-extra', function() { beforeEach(function() { TEST_DIR = testutil.createTestDir('fs-extra') @@ -24,10 +85,9 @@ describe('fs-extra', function() { }) it('should make the entire directory path', function(done) { - var dir = path.join(path.tempdir(), 'tmp-' + Date.now() + Math.random()) - , newDir = path.join(TEST_DIR, 'dfdf', 'ffff', 'aaa'); + var newDir = path.join(TEST_DIR, 'dfdf', 'ffff', 'aaa'); - F (fs.existsSync(dir)); + F (fs.existsSync(newDir)); fs.mkdirs(newDir, function(err) { T (err === null); @@ -36,6 +96,27 @@ describe('fs-extra', function() { done(); }); }) + + it('should make the entire directory path with limit 2', function(done) { + testMkdirsWithLimit(2, true, done); + }) + + it('should make the entire directory path with limit -1', function(done) { + testMkdirsWithLimit(-1, true, done); + }) + + it('should make the entire directory path with limit null', function(done) { + testMkdirsWithLimit(null, true, done); + }) + + it('should refuse to make the entire directory path with limit 0', function(done) { + testMkdirsWithLimit(0, false, done); + }) + + it('should refuse to make the entire directory path with limit 1', function(done) { + testMkdirsWithLimit(1, false, done); + }) + }) describe('+ mkdirsSync()', function() { @@ -59,6 +140,26 @@ describe('fs-extra', function() { done(); }) + + it('should make the entire directory path with limit 2', function(done) { + testMkdirsSyncWithLimit(2, true, done); + }) + + it('should make the entire directory path with limit -1', function(done) { + testMkdirsSyncWithLimit(-1, true, done); + }) + + it('should make the entire directory path with limit null', function(done) { + testMkdirsSyncWithLimit(null, true, done); + }) + + it('should refuse to make the entire directory path with limit 0', function(done) { + testMkdirsSyncWithLimit(0, false, done); + }) + + it('should refuse to make the entire directory path with limit 1', function(done) { + testMkdirsSyncWithLimit(1, false, done); + }) }) }) From 841f6bd733972fb757ec79ae952b27af9e783d46 Mon Sep 17 00:00:00 2001 From: Joshua Richardson Date: Fri, 29 Mar 2013 14:47:54 -0700 Subject: [PATCH 2/2] Better attribution on last commit. --- README.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d927968f..cf96ef7a 100644 --- a/README.md +++ b/README.md @@ -288,6 +288,7 @@ Contributors - [JP Richardson](https://github.com/jprichardson) - [Mike McNeil](https://github.com/mikermcneil) - [Ian Crowther](https://github.com/iancrowther) +- [Joshua Richardson](https://github.com/jric) - `` diff --git a/package.json b/package.json index e8970c9f..53cd7878 100755 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "text", "output" ], - "author": "JP Richardson , Joshua Richardson ", + "author": "JP Richardson ", "licenses": [ { "type": "MIT",