Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ensure symlink & link #162

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 45 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ Methods
- [ensureFileSync](#ensurefilefile-callback)
- [ensureDir](#ensuredirdir-callback)
- [ensureDirSync](#ensuredirdir-callback)
- [ensureLink](#ensurelinksrcpath-dstpath-callback)
- [ensureLinkSync](#ensurelinksrcpath-dstpath-callback)
- [ensureSymlink](#ensuresymlinksrcpath-dstpath-type-callback)
- [ensureSymlinkSync](#ensuresymlinksrcpath-dstpath-type-callback)
- [mkdirs](#mkdirsdir-callback)
- [mkdirsSync](#mkdirsdir-callback)
- [move](#movesrc-dest-options-callback)
Expand Down Expand Up @@ -137,7 +141,6 @@ word `output` to denote that if the containing directory does not exist, it shou
better succinct nomenclature for these methods, please open an issue for discussion. Thanks.



### emptyDir(dir, [callback])

Ensures that a directory is empty. If the directory does not exist, it is created. The directory itself is not deleted.
Expand All @@ -158,7 +161,6 @@ fs.emptyDir('/tmp/some/dir', function (err) {
```



### ensureFile(file, callback)

Ensures that the file exists. If the file that is requested to be created is in directories that do not exist, these directories are created. If the file already exists, it is **NOT MODIFIED**.
Expand Down Expand Up @@ -201,6 +203,47 @@ fs.ensureDir(dir, function (err) {
```


### ensureLink(srcpath, dstpath, callback)

Ensures that the link exists. If the directory structure does not exist, it is created.

Sync: `ensureLinkSync()`


Example:

```js
var fs = require('fs-extra')

var srcpath = '/tmp/file.txt'
var dstpath = '/tmp/this/path/does/not/exist/file.txt'
fs.ensureLink(srcpath, dstpath, function (err) {
console.log(err) // => null
// link has now been created, including the directory it is to be placed in
})
```


### ensureSymlink(srcpath, dstpath, [type], callback)

Ensures that the symlink exists. If the directory structure does not exist, it is created.

Sync: `ensureSymlinkSync()`


Example:

```js
var fs = require('fs-extra')

var srcpath = '/tmp/file.txt'
var dstpath = '/tmp/this/path/does/not/exist/file.txt'
fs.ensureSymlink(srcpath, dstpath, function (err) {
console.log(err) // => null
// symlink has now been created, including the directory it is to be placed in
})
```


### mkdirs(dir, callback)

Expand Down Expand Up @@ -473,11 +516,3 @@ Copyright (c) 2011-2015 [JP Richardson](https://github.com/jprichardson)


[jsonfile]: https://github.com/jprichardson/node-jsonfile








171 changes: 171 additions & 0 deletions lib/ensure/__tests__/link.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
var assert = require('assert')
var util = require('util')
var path = require('path')
var os = require('os')
var fs = require('graceful-fs')
var CWD = process.cwd()
var fse = require(CWD)
var ensureLink = fse.ensureLink
var ensureLinkSync = fse.ensureLinkSync

/* global afterEach, beforeEach, describe, it, after, before */

var TEST_DIR

describe('fse-ensure-link', function () {
TEST_DIR = path.join(os.tmpdir(), 'fs-extra', 'ensure-symlink')

var tests = [
// [[srcpath, dstpath], fs.link expect, ensureLink expect]
[['./foo.txt', './link.txt'], 'file-success', 'file-success'],
[['./foo.txt', './dir-foo/link.txt'], 'file-success', 'file-success'],
[['./foo.txt', './empty-dir/link.txt'], 'file-success', 'file-success'],
[['./foo.txt', './real-alpha/link.txt'], 'file-success', 'file-success'],
[['./foo.txt', './real-alpha/real-beta/link.txt'], 'file-success', 'file-success'],
[['./foo.txt', './real-alpha/real-beta/real-gamma/link.txt'], 'file-success', 'file-success'],
[['./foo.txt', './alpha/link.txt'], 'file-error', 'file-success'],
[['./foo.txt', './alpha/beta/link.txt'], 'file-error', 'file-success'],
[['./foo.txt', './alpha/beta/gamma/link.txt'], 'file-error', 'file-success'],
[['./missing.txt', './link.txt'], 'file-error', 'file-error'],
[[path.resolve(path.join(TEST_DIR, './foo.txt')), './link.txt'], 'file-success', 'file-success'],
[[path.resolve(path.join(TEST_DIR, './dir-foo/foo.txt')), './link.txt'], 'file-success', 'file-success'],
[[path.resolve(path.join(TEST_DIR, './missing.txt')), './link.txt'], 'file-error', 'file-error'],
[[path.resolve(path.join(TEST_DIR, '../foo.txt')), './link.txt'], 'file-error', 'file-error'],
[[path.resolve(path.join(TEST_DIR, '../dir-foo/foo.txt')), './link.txt'], 'file-error', 'file-error']
]

before(function () {
fse.emptyDirSync(TEST_DIR)
process.chdir(TEST_DIR)
})

beforeEach(function () {
fs.writeFileSync('./foo.txt', 'foo\n')
fse.mkdirsSync('empty-dir')
fse.mkdirsSync('dir-foo')
fs.writeFileSync('dir-foo/foo.txt', 'dir-foo\n')
fse.mkdirsSync('dir-bar')
fs.writeFileSync('dir-bar/bar.txt', 'dir-bar\n')
fse.mkdirsSync('real-alpha/real-beta/real-gamma')
})

afterEach(function (done) {
fse.emptyDir(TEST_DIR, done)
})

after(function () {
process.chdir(CWD)
fse.removeSync(TEST_DIR)
})

function fileSuccess (args, fn) {
var srcpath = args[0]
var dstpath = args[1]
var should = util.format('should create link file using src `%s` and dst `%s`', srcpath, dstpath)
it(should, function (done) {
var callback = function (err) {
if (err) return done(err)
var srcContent = fs.readFileSync(srcpath, 'utf8')
var dstDir = path.dirname(dstpath)
var dstBasename = path.basename(dstpath)
var isSymlink = fs.lstatSync(dstpath).isFile()
var dstContent = fs.readFileSync(dstpath, 'utf8')
var dstDirContents = fs.readdirSync(dstDir)
assert.equal(isSymlink, true)
assert.equal(srcContent, dstContent)
assert(dstDirContents.indexOf(dstBasename) >= 0)
return done()
}
args.push(callback)
return fn.apply(null, args)
})
}

function fileError (args, fn) {
var srcpath = args[0]
var dstpath = args[1]
var should = util.format('should return error when creating link file using src `%s` and dst `%s`', srcpath, dstpath)
it(should, function (done) {
var callback = function (err) {
assert.equal(err instanceof Error, true)
return done()
}
args.push(callback)
return fn.apply(null, args)
})
}

function fileSuccessSync (args, fn) {
var srcpath = args[0]
var dstpath = args[1]
var should = util.format('should create link file using src `%s` and dst `%s`', srcpath, dstpath)
it(should, function () {
fn.apply(null, args)
var srcContent = fs.readFileSync(srcpath, 'utf8')
var dstDir = path.dirname(dstpath)
var dstBasename = path.basename(dstpath)
var isSymlink = fs.lstatSync(dstpath).isFile()
var dstContent = fs.readFileSync(dstpath, 'utf8')
var dstDirContents = fs.readdirSync(dstDir)
assert.equal(isSymlink, true)
assert.equal(srcContent, dstContent)
assert(dstDirContents.indexOf(dstBasename) >= 0)
})
}

function fileErrorSync (args, fn) {
var srcpath = args[0]
var dstpath = args[1]
var should = util.format('should throw error using` src `%s` and dst `%s`', srcpath, dstpath)
it(should, function () {
assert.throws(function () {
return fn.apply(null, args)
}, Error)
})
}

describe('fs.link()', function () {
var fn = fs.link
tests.forEach(function (test) {
var args = test[0].slice(0)
var nativeBehavior = test[1]
// var newBehavior = test[2]
if (nativeBehavior === 'file-success') fileSuccess(args, fn)
if (nativeBehavior === 'file-error') fileError(args, fn)
})
})

describe('ensureLink()', function () {
var fn = ensureLink
tests.forEach(function (test) {
var args = test[0].slice(0)
// var nativeBehavior = test[1]
var newBehavior = test[2]
if (newBehavior === 'file-success') fileSuccess(args, fn)
if (newBehavior === 'file-error') fileError(args, fn)
})
})

describe('fs.linkSync()', function () {
var fn = fs.linkSync
tests.forEach(function (test) {
var args = test[0].slice(0)
var nativeBehavior = test[1]
// var newBehavior = test[2]
if (nativeBehavior === 'file-success') fileSuccessSync(args, fn)
if (nativeBehavior === 'file-error') fileErrorSync(args, fn)
})
})

describe('ensureLinkSync()', function () {
var fn = ensureLinkSync
tests.forEach(function (test) {
var args = test[0].slice(0)
// var nativeBehavior = test[1]
var newBehavior = test[2]
if (newBehavior === 'file-success') fileSuccessSync(args, fn)
if (newBehavior === 'file-error') fileErrorSync(args, fn)
})
})

})
93 changes: 93 additions & 0 deletions lib/ensure/__tests__/symlink-paths.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
var assert = require('assert')
var util = require('util')
var path = require('path')
var os = require('os')
var fs = require('graceful-fs')
var CWD = process.cwd()
var fse = require(CWD)
var _symlinkPaths = require('../symlink-paths')
var symlinkPaths = _symlinkPaths.symlinkPaths
var symlinkPathsSync = _symlinkPaths.symlinkPathsSync
var TEST_DIR = path.join(os.tmpdir(), 'fs-extra', 'ensure-symlink')

/* global afterEach, beforeEach, describe, it, after, before */

describe('symlink-type', function () {

before(function () {
fse.emptyDirSync(TEST_DIR)
process.chdir(TEST_DIR)
})

beforeEach(function () {
fs.writeFileSync('./foo.txt', 'foo\n')
fse.mkdirsSync('./empty-dir')
fse.mkdirsSync('./dir-foo')
fs.writeFileSync('./dir-foo/foo.txt', 'dir-foo\n')
fse.mkdirsSync('./dir-bar')
fs.writeFileSync('./dir-bar/bar.txt', 'dir-bar\n')
fse.mkdirsSync('./real-alpha/real-beta/real-gamma')
})

afterEach(function (done) {
fse.emptyDir(TEST_DIR, done)
})

after(function () {
process.chdir(CWD)
fse.removeSync(TEST_DIR)
})

var tests = [
[['foo.txt', 'symlink.txt'], {toCwd: 'foo.txt', toDst: 'foo.txt'}], // smart && nodestyle
[['foo.txt', 'empty-dir/symlink.txt'], {toCwd: 'foo.txt', toDst: '../foo.txt'}], // smart
[['../foo.txt', 'empty-dir/symlink.txt'], {toCwd: 'foo.txt', toDst: '../foo.txt'}], // nodestyle
[['foo.txt', 'dir-bar/symlink.txt'], {toCwd: 'foo.txt', toDst: '../foo.txt'}], // smart
[['../foo.txt', 'dir-bar/symlink.txt'], {toCwd: 'foo.txt', toDst: '../foo.txt'}], // nodestyle
// this is to preserve node's symlink capability these arguments say create
// a link to 'dir-foo/foo.txt' this works because it exists this is unlike
// the previous example with 'empty-dir' because 'empty-dir/foo.txt' does not exist.
[['foo.txt', 'dir-foo/symlink.txt' ], {toCwd: 'dir-foo/foo.txt', toDst: 'foo.txt'}], // nodestyle
[['foo.txt', 'real-alpha/real-beta/real-gamma/symlink.txt' ], {toCwd: 'foo.txt', toDst: '../../../foo.txt'}]
]

// formats paths to pass on multiple operating systems
tests.forEach(function (test) {
test[0][0] = path.join(test[0][0])
test[0][1] = path.join(test[0][1])
test[1] = {
toCwd: path.join(test[1].toCwd),
toDst: path.join(test[1].toDst)
}
})

describe('symlinkPaths()', function () {
tests.forEach(function (test) {
var args = test[0].slice(0)
var expectedRelativePaths = test[1]
var should = util.format('should return \'%s\' when src \'%s\' and dst is \'%s\'', JSON.stringify(expectedRelativePaths), args[0], args[1])
it(should, function (done) {
var callback = function (err, relativePaths) {
if (err) done(err)
assert.deepEqual(relativePaths, expectedRelativePaths)
done()
}
args.push(callback)
return symlinkPaths.apply(null, args)
})
})
})

describe('symlinkPathsSync()', function () {
tests.forEach(function (test) {
var args = test[0].slice(0)
var expectedRelativePaths = test[1]
var should = util.format('should return \'%s\' when src \'%s\' and dst is \'%s\'', JSON.stringify(expectedRelativePaths), args[0], args[1])
it(should, function () {
var relativePaths = symlinkPathsSync.apply(null, args)
assert.deepEqual(relativePaths, expectedRelativePaths)
})
})
})

})
Loading