Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
Contra committed Sep 10, 2015
2 parents 7ca959e + b9b9469 commit 27983ef
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 26 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ fs.src(['*.js', '!b*.js'])
- sourcemaps - `true` or `false` if you want files to have sourcemaps enabled.
- Default is `false`.

- followSymlinks - `true` if you want to recursively resolve symlinks to their targets; set to `false` to preserve them as symlinks.
- Default is `true`.
- `false` will make `file.symlink` equal the original symlink's target path.

- Any glob-related options are documented in [glob-stream] and [node-glob].

- Returns a Readable stream by default, or a Duplex stream if the `passthrough` option is set to `true`.
Expand Down Expand Up @@ -99,6 +103,7 @@ _Note:_ UTF-8 BOM will be stripped from all UTF-8 files read with `.src`.
- Returns a Readable/Writable stream.
- On write the stream will save the [vinyl] File to disk at the folder/cwd specified.
- After writing the file to disk, it will be emitted from the stream so you can keep piping these around.
- If the file has a `symlink` attribute specifying a target path, then a symlink will be created.
- The file will be modified after being written to this stream:
- `cwd`, `base`, and `path` will be overwritten to match the folder.
- `stat.mode` will be overwritten if you used a mode parameter.
Expand All @@ -113,6 +118,7 @@ _Note:_ UTF-8 BOM will be stripped from all UTF-8 files read with `.src`.

- base - Specify the folder relative to the cwd. This is used to determine the file names when saving in `.dest()`.
- Default is the `cwd` resolves to the folder path.
- Can also be a function that takes in a file and returns a folder path.

- dirMode - Specify the mode the directory should be created with.
- Default is the process mode.
Expand Down
8 changes: 7 additions & 1 deletion lib/dest/writeContents/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var fs = require('fs');
var writeDir = require('./writeDir');
var writeStream = require('./writeStream');
var writeBuffer = require('./writeBuffer');
var writeSymbolicLink = require('./writeSymbolicLink');

function writeContents(writePath, file, cb) {
// if directory then mkdirp it
Expand All @@ -16,6 +17,11 @@ function writeContents(writePath, file, cb) {
return writeStream(writePath, file, written);
}

// write it as a symlink
if (file.symlink) {
return writeSymbolicLink(writePath, file, written);
}

// write it like normal
if (file.isBuffer()) {
return writeBuffer(writePath, file, written);
Expand All @@ -36,7 +42,7 @@ function writeContents(writePath, file, cb) {
return complete(err);
}

if (!file.stat || typeof file.stat.mode !== 'number') {
if (!file.stat || typeof file.stat.mode !== 'number' || file.symlink) {
return complete();
}

Expand Down
15 changes: 15 additions & 0 deletions lib/dest/writeContents/writeSymbolicLink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

var fs = require('graceful-fs');

function writeSymbolicLink(writePath, file, cb) {
fs.symlink(file.symlink, writePath, function (err) {
if (err && err.code !== 'EEXIST') {
return cb(err);
}

cb(null, file);
});
}

module.exports = writeSymbolicLink;
6 changes: 6 additions & 0 deletions lib/src/getContents/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

var through2 = require('through2');
var readDir = require('./readDir');
var readSymbolicLink = require('./readSymbolicLink');
var bufferFile = require('./bufferFile');
var streamFile = require('./streamFile');

Expand All @@ -12,6 +13,11 @@ function getContents(opt) {
return readDir(file, opt, cb);
}

// process symbolic links included with `followSymlinks` option
if (file.stat && file.stat.isSymbolicLink()) {
return readSymbolicLink(file, opt, cb);
}

// read and pass full contents
if (opt.buffer !== false) {
return bufferFile(file, opt, cb);
Expand Down
18 changes: 18 additions & 0 deletions lib/src/getContents/readSymbolicLink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';

var fs = require('graceful-fs');

function readLink(file, opt, cb) {
fs.readlink(file.path, function (err, target) {
if (err) {
return cb(err);
}

// store the link target path
file.symlink = target;

return cb(null, file);
});
}

module.exports = readLink;
5 changes: 3 additions & 2 deletions lib/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ function src(glob, opt) {
read: true,
buffer: true,
sourcemaps: false,
passthrough: false
passthrough: false,
followSymlinks: true
}, opt);

var inputPass;
Expand All @@ -34,7 +35,7 @@ function src(glob, opt) {
var globStream = gs.create(glob, options);

var outputStream = globStream
.pipe(resolveSymlinks())
.pipe(resolveSymlinks(options))
.pipe(through.obj(createFile));

if (options.since != null) {
Expand Down
45 changes: 23 additions & 22 deletions lib/src/resolveSymlinks.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,36 @@ var through2 = require('through2');
var fs = require('graceful-fs');
var path = require('path');

function resolveSymlinks() {
return through2.obj(resolveFile);
}

// a stat property is exposed on file objects as a (wanted) side effect
function resolveFile(globFile, enc, cb) {
fs.lstat(globFile.path, function (err, stat) {
if (err) {
return cb(err);
}
function resolveSymlinks(options) {

globFile.stat = stat;

if (!stat.isSymbolicLink()) {
return cb(null, globFile);
}

fs.realpath(globFile.path, function (err, filePath) {
// a stat property is exposed on file objects as a (wanted) side effect
function resolveFile(globFile, enc, cb) {
fs.lstat(globFile.path, function (err, stat) {
if (err) {
return cb(err);
}

globFile.base = path.dirname(filePath);
globFile.path = filePath;
globFile.stat = stat;

// recurse to get real file stat
resolveFile(globFile, enc, cb);
if (!stat.isSymbolicLink() || !options.followSymlinks) {
return cb(null, globFile);
}

fs.realpath(globFile.path, function (err, filePath) {
if (err) {
return cb(err);
}

globFile.base = path.dirname(filePath);
globFile.path = filePath;

// recurse to get real file stat
resolveFile(globFile, enc, cb);
});
});
});
}

return through2.obj(resolveFile);
}

module.exports = resolveSymlinks;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"graceful-fs": "^4.0.0",
"gulp-sourcemaps": "^1.5.2",
"is-valid-glob": "^0.3.0",
"merge-stream": "^0.1.7",
"merge-stream": "^1.0.0",
"mkdirp": "^0.5.0",
"object-assign": "^3.0.0",
"strip-bom": "^2.0.0",
Expand Down
34 changes: 34 additions & 0 deletions test/dest.js
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,40 @@ describe('dest stream', function() {
stream.end();
});

it('should create symlinks when the `symlink` attribute is set on the file', function (done) {
var inputPath = path.join(__dirname, './fixtures/test-create-dir-symlink');
var inputBase = path.join(__dirname, './fixtures/');
var inputRelativeSymlinkPath = 'wow';

var expectedPath = path.join(__dirname, './out-fixtures/test-create-dir-symlink');

var inputFile = new File({
base: inputBase,
cwd: __dirname,
path: inputPath,
contents: null, //''
});

// `src()` adds this side-effect with `keepSymlinks` option set to false
inputFile.symlink = inputRelativeSymlinkPath;

var onEnd = function(){
fs.readlink(buffered[0].path, function (err, link) {
buffered[0].symlink.should.equal(inputFile.symlink);
buffered[0].path.should.equal(expectedPath);
done();
});
};

var stream = vfs.dest('./out-fixtures/', {cwd: __dirname});

var buffered = [];
bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
stream.pipe(bufferStream);
stream.write(inputFile);
stream.end();
});

it('should emit finish event', function(done) {
var srcPath = path.join(__dirname, './fixtures/test.coffee');
var stream = vfs.dest('./out-fixtures/', {cwd: __dirname});
Expand Down
36 changes: 36 additions & 0 deletions test/src.js
Original file line number Diff line number Diff line change
Expand Up @@ -383,4 +383,40 @@ describe('source stream', function() {
});
});

it('should preserve file symlinks with followSymlinks option set to false', function (done) {
var sourcePath = path.join(__dirname, './fixtures/test-symlink');
var expectedPath = sourcePath;

fs.readlink(sourcePath, function (err, expectedRelativeSymlinkPath) {
if (err) {
throw err;
}

var stream = vfs.src('./fixtures/test-symlink', {cwd: __dirname, followSymlinks: false});
stream.on('data', function(file) {
file.path.should.equal(expectedPath);
file.symlink.should.equal(expectedRelativeSymlinkPath);
done();
});
});
});

it('should preserve dir symlinks with followSymlinks option set to false', function (done) {
var sourcePath = path.join(__dirname, './fixtures/test-symlink-dir');
var expectedPath = sourcePath;

fs.readlink(sourcePath, function (err, expectedRelativeSymlinkPath) {
if (err) {
throw err;
}

var stream = vfs.src(sourcePath, {cwd: __dirname, followSymlinks: false});
stream.on('data', function (file) {
file.path.should.equal(expectedPath);
file.symlink.should.equal(expectedRelativeSymlinkPath);
done();
});
});
});

});

0 comments on commit 27983ef

Please sign in to comment.