Commit d1460f9f authored by Bas Couwenberg's avatar Bas Couwenberg

Imported Upstream version 0.0.25

parent ba1f6ac9
......@@ -3,3 +3,4 @@ node_js:
- "0.6"
- "0.8"
- "0.10"
- "0.12"
The MIT License (MIT)
Copyright (c) 2014 KARASZI István
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
......@@ -11,8 +11,12 @@ aggressively checks for the existence of the newly created temporary file and
creates the new file with `O_EXCL` instead of simple `O_CREAT | O_RDRW`, so it
is safer.
The API is slightly different as well, Tmp does not yet provide synchronous
calls and all the parameters are optional.
Tmp offers both an asynchronous and a synchronous API. For all API calls, all
the parameters are optional.
Tmp uses crypto for determining random file names, or, when using templates,
a six letter random identifier. And just in case that you do not have that much
entropy left on your system, Tmp will fall back to pseudo random numbers.
You can set whether you want to remove the temporary file on process exit or
not, and the destination directory can also be set.
......@@ -25,22 +29,48 @@ npm install tmp
## Usage
### File creation
### Asynchronous file creation
Simple temporary file creation, the file will be unlinked on process exit.
Simple temporary file creation, the file will be closed and unlinked on process exit.
```javascript
var tmp = require('tmp');
tmp.file(function _tempFileCreated(err, path, fd) {
tmp.file(function _tempFileCreated(err, path, fd, cleanupCallback) {
if (err) throw err;
console.log("File: ", path);
console.log("Filedescriptor: ", fd);
// If we don't need the file anymore we could manually call the cleanupCallback
// But that is not necessary if we didn't pass the keep option because the library
// will clean after itself.
cleanupCallback();
});
```
### Directory creation
### Synchronous file creation
A synchronous version of the above.
```javascript
var tmp = require('tmp');
var tmpobj = tmp.fileSync();
console.log("File: ", tmpobj.name);
console.log("Filedescriptor: ", tmpobj.fd);
// If we don't need the file anymore we could manually call the removeCallback
// But that is not necessary if we didn't pass the keep option because the library
// will clean after itself.
tmpobj.removeCallback();
```
Note that this might throw an exception if either the maximum limit of retries
for creating a temporary name fails, or, in case that you do not have the permission
to write to the directory where the temporary file should be created in.
### Asynchronous directory creation
Simple temporary directory creation, it will be removed on process exit.
......@@ -49,17 +79,37 @@ If the directory still contains items on process exit, then it won't be removed.
```javascript
var tmp = require('tmp');
tmp.dir(function _tempDirCreated(err, path) {
tmp.dir(function _tempDirCreated(err, path, cleanupCallback) {
if (err) throw err;
console.log("Dir: ", path);
// Manual cleanup
cleanupCallback();
});
```
If you want to cleanup the directory even when there are entries in it, then
you can pass the `unsafeCleanup` option when creating it.
### Filename generation
### Synchronous directory creation
A synchronous version of the above.
```javascript
var tmp = require('tmp');
var tmpobj = tmp.dirSync();
console.log("Dir: ", tmpobj.name);
// Manual cleanup
tmpobj.removeCallback();
```
Note that this might throw an exception if either the maximum limit of retries
for creating a temporary name fails, or, in case that you do not have the permission
to write to the directory where the temporary directory should be created in.
### Asynchronous filename generation
It is possible with this library to generate a unique filename in the specified
directory.
......@@ -74,9 +124,20 @@ tmp.tmpName(function _tempNameGenerated(err, path) {
});
```
### Synchronous filename generation
A synchrounous version of the above.
```javascript
var tmp = require('tmp');
var name = tmp.tmpNameSync();
console.log("Created temporary filename: ", name);
```
## Advanced usage
### File creation
### Asynchronous file creation
Creates a file with mode `0644`, prefix will be `prefix-` and postfix will be `.txt`.
......@@ -91,7 +152,19 @@ tmp.file({ mode: 0644, prefix: 'prefix-', postfix: '.txt' }, function _tempFileC
});
```
### Directory creation
### Synchronous file creation
A synchronous version of the above.
```javascript
var tmp = require('tmp');
var tmpobj = tmp.fileSync({ mode: 0644, prefix: 'prefix-', postfix: '.txt' });
console.log("File: ", tmpobj.name);
console.log("Filedescriptor: ", tmpobj.fd);
```
### Asynchronous directory creation
Creates a directory with mode `0755`, prefix will be `myTmpDir_`.
......@@ -105,7 +178,18 @@ tmp.dir({ mode: 0750, prefix: 'myTmpDir_' }, function _tempDirCreated(err, path)
});
```
### mkstemps like
### Synchronous directory creation
Again, a synchronous version of the above.
```javascript
var tmp = require('tmp');
var tmpobj = tmp.dirSync({ mode: 0750, prefix: 'myTmpDir_' });
console.log("Dir: ", tmpobj.name);
```
### mkstemps like, asynchronously
Creates a new temporary directory with mode `0700` and filename like `/tmp/tmp-nk2J1u`.
......@@ -119,7 +203,18 @@ tmp.dir({ template: '/tmp/tmp-XXXXXX' }, function _tempDirCreated(err, path) {
});
```
### Filename generation
### mkstemps like, synchronously
This will behave similarly to the asynchronous version.
```javascript
var tmp = require('tmp');
var tmpobj = tmp.dirSync({ template: '/tmp/tmp-XXXXXX' });
console.log("Dir: ", tmpobj.name);
```
### Asynchronous filename generation
The `tmpName()` function accepts the `prefix`, `postfix`, `dir`, etc. parameters also:
......@@ -133,6 +228,16 @@ tmp.tmpName({ template: '/tmp/tmp-XXXXXX' }, function _tempNameGenerated(err, pa
});
```
### Synchronous filename generation
The `tmpNameSync()` function works similarly to `tmpName()`.
```javascript
var tmp = require('tmp');
var tmpname = tmp.tmpNameSync({ template: '/tmp/tmp-XXXXXX' });
console.log("Created temporary filename: ", tmpname);
```
## Graceful cleanup
One may want to cleanup the temporary files even when an uncaught exception
......@@ -155,6 +260,7 @@ All options are optional :)
* `dir`: the optional temporary directory, fallbacks to system default (guesses from environment)
* `tries`: how many times should the function try to get a unique filename before giving up, default `3`
* `keep`: signals that the temporary file or directory should not be deleted on exit, default is `false`, means delete
* Please keep in mind that it is recommended in this case to call the provided `cleanupCallback` function manually.
* `unsafeCleanup`: recursively removes the created temporary directory, even when it's not empty. default is `false`
[1]: http://nodejs.org/
......
This diff is collapsed.
{
"name": "tmp",
"version": "0.0.24",
"version": "0.0.25",
"description": "Temporary file and directory creator",
"author": "KARASZI István <github@spam.raszi.hu> (http://raszi.hu/)",
......
var
assert = require('assert'),
path = require('path'),
exec = require('child_process').exec;
exec = require('child_process').exec,
tmp = require('../lib/tmp');
// make sure that we do not test spam the global tmp
tmp.TMP_DIR = './tmp';
function _spawnTestWithError(testFile, params, cb) {
_spawnTest(true, testFile, params, cb);
......@@ -13,7 +18,6 @@ function _spawnTestWithoutError(testFile, params, cb) {
function _spawnTest(passError, testFile, params, cb) {
var
filename,
node_path = process.argv[0],
command = [ node_path, path.join(__dirname, testFile) ].concat(params).join(' ');
......@@ -37,38 +41,100 @@ function _testStat(stat, mode) {
}
function _testPrefix(prefix) {
return function _testPrefixGenerated(err, name, fd) {
return function _testPrefixGenerated(err, name) {
assert.equal(path.basename(name).slice(0, prefix.length), prefix, 'should have the provided prefix');
};
}
function _testPrefixSync(prefix) {
return function _testPrefixGeneratedSync(result) {
if (result instanceof Error) {
throw result;
}
_testPrefix(prefix)(null, result.name, result.fd);
};
}
function _testPostfix(postfix) {
return function _testPostfixGenerated(err, name, fd) {
return function _testPostfixGenerated(err, name) {
assert.equal(name.slice(name.length - postfix.length, name.length), postfix, 'should have the provided postfix');
};
}
function _testPostfixSync(postfix) {
return function _testPostfixGeneratedSync(result) {
if (result instanceof Error) {
throw result;
}
_testPostfix(postfix)(null, result.name, result.fd);
};
}
function _testKeep(type, keep, cb) {
_spawnTestWithError('keep.js', [ type, keep ], cb);
}
function _testKeepSync(type, keep, cb) {
_spawnTestWithError('keep-sync.js', [ type, keep ], cb);
}
function _testGraceful(type, graceful, cb) {
_spawnTestWithoutError('graceful.js', [ type, graceful ], cb);
}
function _testGracefulSync(type, graceful, cb) {
_spawnTestWithoutError('graceful-sync.js', [ type, graceful ], cb);
}
function _assertName(err, name) {
assert.isString(name);
assert.isNotZero(name.length);
}
function _assertNameSync(result) {
if (result instanceof Error) {
throw result;
}
var name = typeof(result) == 'string' ? result : result.name;
_assertName(null, name);
}
function _testName(expected){
return function _testNameGenerated(err, name) {
assert.equal(expected, name, 'should have the provided name');
};
}
function _testNameSync(expected){
return function _testNameGeneratedSync(result) {
if (result instanceof Error) {
throw result;
}
_testName(expected)(null, result.name, result.fd);
};
}
function _testUnsafeCleanup(unsafe, cb) {
_spawnTestWithoutError('unsafe.js', [ 'dir', unsafe ], cb);
}
function _testUnsafeCleanupSync(unsafe, cb) {
_spawnTestWithoutError('unsafe-sync.js', [ 'dir', unsafe ], cb);
}
module.exports.testStat = _testStat;
module.exports.testPrefix = _testPrefix;
module.exports.testPrefixSync = _testPrefixSync;
module.exports.testPostfix = _testPostfix;
module.exports.testPostfixSync = _testPostfixSync;
module.exports.testKeep = _testKeep;
module.exports.testKeepSync = _testKeepSync;
module.exports.testGraceful = _testGraceful;
module.exports.testGracefulSync = _testGracefulSync;
module.exports.assertName = _assertName;
module.exports.assertNameSync = _assertNameSync;
module.exports.testName = _testName;
module.exports.testNameSync = _testNameSync;
module.exports.testUnsafeCleanup = _testUnsafeCleanup;
module.exports.testUnsafeCleanupSync = _testUnsafeCleanupSync;
var
vows = require('vows'),
assert = require('assert'),
path = require('path'),
fs = require('fs'),
existsSync = fs.existsSync || path.existsSync,
tmp = require('../lib/tmp.js'),
Test = require('./base.js');
function _testDir(mode) {
return function _testDirGenerated(result) {
assert.ok(existsSync(result.name), 'should exist');
var stat = fs.statSync(result.name);
assert.ok(stat.isDirectory(), 'should be a directory');
Test.testStat(stat, mode);
};
}
vows.describe('Synchronous directory creation').addBatch({
'when using without parameters': {
topic: function () {
return tmp.dirSync();
},
'should return with a name': Test.assertNameSync,
'should be a directory': _testDir(040700),
'should have the default prefix': Test.testPrefixSync('tmp-')
},
'when using with prefix': {
topic: function () {
return tmp.dirSync({ prefix: 'something' });
},
'should return with a name': Test.assertNameSync,
'should be a directory': _testDir(040700),
'should have the provided prefix': Test.testPrefixSync('something')
},
'when using with postfix': {
topic: function () {
return tmp.dirSync({ postfix: '.txt' });
},
'should return with a name': Test.assertNameSync,
'should be a directory': _testDir(040700),
'should have the provided postfix': Test.testPostfixSync('.txt')
},
'when using template': {
topic: function () {
return tmp.dirSync({ template: path.join(tmp.tmpdir, 'clike-XXXXXX-postfix') });
},
'should return with a name': Test.assertNameSync,
'should be a directory': _testDir(040700),
'should have the provided prefix': Test.testPrefixSync('clike-'),
'should have the provided postfix': Test.testPostfixSync('-postfix')
},
'when using name': {
topic: function () {
return tmp.dirSync({ name: 'using-name' });
},
'should return with a name': Test.assertNameSync,
'should have the provided name': Test.testNameSync(path.join(tmp.tmpdir, 'using-name')),
'should be a directory': function (result) {
_testDir(040700)(result);
result.removeCallback();
assert.ok(!existsSync(result.name), 'Directory should be removed');
}
},
'when using multiple options': {
topic: function () {
return tmp.dirSync({ prefix: 'foo', postfix: 'bar', mode: 0750 });
},
'should return with a name': Test.assertNameSync,
'should be a directory': _testDir(040750),
'should have the provided prefix': Test.testPrefixSync('foo'),
'should have the provided postfix': Test.testPostfixSync('bar')
},
'when using multiple options and mode': {
topic: function () {
return tmp.dirSync({ prefix: 'complicated', postfix: 'options', mode: 0755 });
},
'should return with a name': Test.assertNameSync,
'should be a directory': _testDir(040755),
'should have the provided prefix': Test.testPrefixSync('complicated'),
'should have the provided postfix': Test.testPostfixSync('options')
},
'no tries': {
topic: function () {
try {
return tmp.dirSync({ tries: -1 });
}
catch (e) {
return e;
}
},
'should return with an error': function (topic) {
assert.instanceOf(topic, Error);
}
},
'keep testing': {
topic: function () {
Test.testKeepSync('dir', '1', this.callback);
},
'should not return with an error': assert.isNull,
'should return with a name': Test.assertName,
'should be a dir': function (err, name) {
_testDir(040700)({ name: name });
fs.rmdirSync(name);
}
},
'unlink testing': {
topic: function () {
Test.testKeepSync('dir', '0', this.callback);
},
'should not return with error': assert.isNull,
'should return with a name': Test.assertName,
'should not exist': function (err, name) {
assert.ok(!existsSync(name), 'Directory should be removed');
}
},
'non graceful testing': {
topic: function () {
Test.testGracefulSync('dir', '0', this.callback);
},
'should not return with error': assert.isNull,
'should return with a name': Test.assertName,
'should be a dir': function (err, name) {
_testDir(040700)({ name: name });
fs.rmdirSync(name);
}
},
'graceful testing': {
topic: function () {
Test.testGracefulSync('dir', '1', this.callback);
},
'should not return with an error': assert.isNull,
'should return with a name': Test.assertName,
'should not exist': function (err, name) {
assert.ok(!existsSync(name), 'Directory should be removed');
}
},
'unsafeCleanup === true': {
topic: function () {
Test.testUnsafeCleanupSync('1', this.callback);
},
'should not return with an error': assert.isNull,
'should return with a name': Test.assertName,
'should not exist': function (err, name) {
assert.ok(!existsSync(name), 'Directory should be removed');
},
'should remove symlinked dir': function(err, name) {
assert.ok(
!existsSync(name + '/symlinkme-target'),
'should remove target'
);
},
'should not remove contents of symlink dir': function(err, name) {
assert.ok(
existsSync(__dirname + '/symlinkme/file.js'),
'should not remove symlinked directory\'s content'
);
}
},
'unsafeCleanup === false': {
topic: function () {
Test.testUnsafeCleanupSync('0', this.callback);
},
'should not return with an error': assert.isNull,
'should return with a name': Test.assertName,
'should be a directory': function (err, name) {
_testDir(040700)({name:name});
}
},
'remove callback': {
topic: function () {
return tmp.dirSync();
},
'should return with a name': Test.assertNameSync,
'removeCallback should remove directory': function (result) {
result.removeCallback();
assert.ok(!existsSync(result.name), 'Directory should be removed');
}
}
}).exportTo(module);
......@@ -60,11 +60,22 @@ vows.describe('Directory creation').addBatch({
'should not return with error': assert.isNull,
'should return with a name': Test.assertName,
'should be a file': _testDir(040700),
'should be a directory': _testDir(040700),
'should have the provided prefix': Test.testPrefix('clike-'),
'should have the provided postfix': Test.testPostfix('-postfix')
},
'when using name': {
topic: function () {
tmp.dir({ name: 'using-name' }, this.callback);
},
'should not return with an error': assert.isNull,
'should return with a name': Test.assertName,
'should be a directory': _testDir(040700),
'should have the provided name': Test.testName(path.join(tmp.tmpdir, 'using-name'))
},
'when using multiple options': {
topic: function () {
tmp.dir({ prefix: 'foo', postfix: 'bar', mode: 0750 }, this.callback);
......@@ -118,7 +129,7 @@ vows.describe('Directory creation').addBatch({
'should not return with error': assert.isNull,
'should return with a name': Test.assertName,
'should not exist': function (err, name) {
assert.ok(!existsSync(name), "Directory should be removed");
assert.ok(!existsSync(name), 'Directory should be removed');
}
},
......@@ -143,7 +154,7 @@ vows.describe('Directory creation').addBatch({
'should not return with an error': assert.isNull,
'should return with a name': Test.assertName,
'should not exist': function (err, name) {
assert.ok(!existsSync(name), "Directory should be removed");
assert.ok(!existsSync(name), 'Directory should be removed');
}
},
......@@ -155,7 +166,7 @@ vows.describe('Directory creation').addBatch({
'should not return with an error': assert.isNull,
'should return with a name': Test.assertName,
'should not exist': function (err, name) {
assert.ok(!existsSync(name), "Directory should be removed");
assert.ok(!existsSync(name), 'Directory should be removed');
},
'should remove symlinked dir': function(err, name) {
assert.ok(
......@@ -190,7 +201,7 @@ vows.describe('Directory creation').addBatch({
'should return with a name': Test.assertName,
'removeCallback should remove directory': function (_err, name, removeCallback) {
removeCallback();
assert.ok(!existsSync(name), "Directory should be removed");
assert.ok(!existsSync(name), 'Directory should be removed');
}
}
}).exportTo(module);
var
vows = require('vows'),
assert = require('assert'),
path = require('path'),
fs = require('fs'),
existsSync = fs.existsSync || path.existsSync,
tmp = require('../lib/tmp.js'),
Test = require('./base.js');
function _testFile(mode, fdTest) {
return function _testFileGenerated(result) {
assert.ok(existsSync(result.name), 'should exist');
var stat = fs.statSync(result.name);
assert.equal(stat.size, 0, 'should have zero size');
assert.ok(stat.isFile(), 'should be a file');
Test.testStat(stat, mode);
// check with fstat as well (fd checking)
if (fdTest) {
var fstat = fs.fstatSync(result.fd);
assert.deepEqual(fstat, stat, 'fstat results should be the same');
var data = new Buffer('something');
assert.equal(fs.writeSync(result.fd, data, 0, data.length, 0), data.length, 'should be writable');
assert.ok(!fs.closeSync(result.fd), 'should not return with error');
}
};
}
vows.describe('Synchronous file creation').addBatch({
'when using without parameters': {
topic: function () {
return tmp.fileSync();
},
'should return with a name': Test.assertNameSync,
'should be a file': _testFile(0100600, true),
'should have the default prefix': Test.testPrefixSync('tmp-'),
'should have the default postfix': Test.testPostfixSync('.tmp')
},
'when using with prefix': {
topic: function () {
return tmp.fileSync({ prefix: 'something' });
},
'should return with a name': Test.assertNameSync,
'should be a file': _testFile(0100600, true),
'should have the provided prefix': Test.testPrefixSync('something')
},
'when using with postfix': {
topic: function () {
return tmp.fileSync({ postfix: '.txt' });
},
'should return with a name': Test.assertNameSync,
'should be a file': _testFile(0100600, true),
'should have the provided postfix': Test.testPostfixSync('.txt')
},
'when using template': {
topic: function () {
return tmp.fileSync({ template: path.join(tmp.tmpdir, 'clike-XXXXXX-postfix') });
},
'should return with a name': Test.assertNameSync,
'should be a file': _testFile(0100600, true),
'should have the provided prefix': Test.testPrefixSync('clike-'),
'should have the provided postfix': Test.testPostfixSync('-postfix')
},
'when using name': {
topic: function () {
return tmp.fileSync({ name: 'using-name.tmp' });
},
'should return with a name': Test.assertNameSync,
'should have the provided name': Test.testNameSync(path.join(tmp.tmpdir, 'using-name.tmp')),
'should be a file': function (result) {
_testFile(0100600, true);
fs.unlinkSync(result.name);
}
},
'when using multiple options': {
topic: