diff --git a/README.md b/README.md index 1e98cee..6c1d046 100644 --- a/README.md +++ b/README.md @@ -329,6 +329,7 @@ var fs = new Filer.FileSystem(); * [fs.rmdir(path, callback)](#rmdir) * [fs.mkdir(path, [mode], callback)](#mkdir) * [fs.access(path, [mode], callback)](#access) +* [fs.mkdtemp(path, [options], callback)](#mkdtemp) * [fs.readdir(path, callback)](#readdir) * [fs.close(fd, callback)](#close) * [fs.open(path, flags, [mode], callback)](#open) @@ -731,6 +732,26 @@ fs.access(file, fs.constants.F_OK, function(err) { }); ``` +#### fs.mkdtemp(prefix, options, callback) + +Makes a temporary directory with prefix supplied in `path` argument. Method will append six random characters directly to the prefix. Asynchronous. Callback gets `(error, path)`, where path is the path to the created directory. + +NOTE: Filer allows for, but ignores the optional `options` argument used in node.js. + +Example: + +```javascript +// Create tmp directory with prefix foo +fs.mkdtemp("/foo-", function (error, path) { + // A new folder foo-xxxxxx will be created. Path contains a path to created folder. +}); + +fs.mkdtemp("/myDir/tmp", function (error, path) { + // Will create a new folder tmpxxxxxx inside myDir directory. + // Will throw error if myDir does not exist +}); +``` + #### fs.readdir(path, callback) Reads the contents of a directory. Asynchronous [readdir(3)](http://pubs.opengroup.org/onlinepubs/009695399/functions/readdir.html). diff --git a/src/filesystem/implementation.js b/src/filesystem/implementation.js index dc70c8f..586656c 100644 --- a/src/filesystem/implementation.js +++ b/src/filesystem/implementation.js @@ -4,6 +4,7 @@ var dirname = Path.dirname; var basename = Path.basename; var isAbsolutePath = Path.isAbsolute; var isNullPath = Path.isNull; +var shared = require('../shared.js'); var Constants = require('../constants.js'); var NODE_TYPE_FILE = Constants.NODE_TYPE_FILE; @@ -1693,6 +1694,21 @@ function access(fs, context, path, mode, callback) { access_file(context, path, mode, callback); } +function mkdtemp(fs, context, prefix, options, callback) { + callback = arguments[arguments.length - 1]; + if(!prefix) { + return callback(new Error('filename prefix is required')); + } + + let random = shared.randomChars(6); + var path = prefix + '-' + random; + + if(!pathCheck(path, callback)) return; + make_directory(context, path, function(error) { + callback(error, path); + }); +} + function rmdir(fs, context, path, callback) { if(!pathCheck(path, callback)) return; remove_directory(context, path, callback); @@ -2428,6 +2444,7 @@ module.exports = { close: close, mknod: mknod, mkdir: mkdir, + mkdtemp: mkdtemp, rmdir: rmdir, unlink: unlink, stat: stat, diff --git a/src/filesystem/interface.js b/src/filesystem/interface.js index bd21b9a..a1a0030 100644 --- a/src/filesystem/interface.js +++ b/src/filesystem/interface.js @@ -279,6 +279,7 @@ function FileSystem(options, callback) { { name: 'close' }, { name: 'mknod', promises: true }, { name: 'mkdir', promises: true }, + { name: 'mkdtemp', promises: true }, { name: 'rmdir', promises: true }, { name: 'stat', promises: true }, { name: 'fstat' }, diff --git a/src/shared.js b/src/shared.js index 5c3337b..e595420 100644 --- a/src/shared.js +++ b/src/shared.js @@ -1,13 +1,27 @@ -function guid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { +function generateRandom(template) { + return template.replace(/[xy]/g, function(c) { var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); return v.toString(16); - }).toUpperCase(); + }); +} + +function guid() { + return generateRandom('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx').toUpperCase(); +} + +/** + * Generate a string of n random characters. Defaults to n=6. + */ +function randomChars(n) { + n = n || 6; + var template = 'x'.repeat(n); + return generateRandom(template); } function nop() {} module.exports = { guid: guid, - nop: nop + nop: nop, + randomChars: randomChars }; diff --git a/tests/index.js b/tests/index.js index 1bf41a4..a459aa1 100644 --- a/tests/index.js +++ b/tests/index.js @@ -16,6 +16,7 @@ require('./spec/fs.lstat.spec'); require('./spec/fs.exists.spec'); require('./spec/fs.mknod.spec'); require('./spec/fs.mkdir.spec'); +require('./spec/fs.mkdtemp.spec'); require('./spec/fs.readdir.spec'); require('./spec/fs.rmdir.spec'); require('./spec/fs.open.spec'); diff --git a/tests/spec/fs.mkdtemp.spec.js b/tests/spec/fs.mkdtemp.spec.js new file mode 100644 index 0000000..3527e6d --- /dev/null +++ b/tests/spec/fs.mkdtemp.spec.js @@ -0,0 +1,52 @@ +var util = require('../lib/test-utils.js'); +var expect = require('chai').expect; + +describe('fs.mkdtemp', function() { + beforeEach(util.setup); + afterEach(util.cleanup); + + it('should be a function', function() { + var fs = util.fs(); + expect(fs.mkdtemp).to.be.a('function'); + }); + + it('should craete temp dir with specified prefix', function(done) { + var fs = util.fs(); + fs.mkdtemp('/foo', function(error, path) { + expect(error).not.to.exist; + expect(path).to.match(/foo-\w{6}/); + done(); + }); + }); + + it('should craete temp dir inside existing directory', function(done) { + var fs = util.fs(); + fs.mkdir('/myDir', (error) => { + expect(error).not.to.exist; + fs.mkdtemp('/myDir/foo', function(error, path) { + expect(error).not.to.exist; + expect(path).to.match(/foo.{6}/); + done(); + }); + }); + }); + + it('should not create temp dir without prefix', function(done) { + var fs = util.fs(); + fs.mkdtemp('', function(error, path) { + expect(error).to.exist; + expect(path).not.to.exist; + done(); + }); + }); + + it('should not create temp dir inside non existing dir', function(done) { + var fs = util.fs(); + fs.mkdtemp('/doesNotExists/foo', function(error, path) { + expect(error).to.exist; + expect(error.code).to.be.equal('ENOENT'); + expect(path).to.exist; + done(); + }); + }); +}); \ No newline at end of file