90 lines
2.7 KiB
JavaScript
90 lines
2.7 KiB
JavaScript
'use strict';
|
|
|
|
var os = require('os');
|
|
var path = require('path');
|
|
|
|
var through = require('through2');
|
|
|
|
var fo = require('../file-operations');
|
|
|
|
var isWindows = (os.platform() === 'win32');
|
|
|
|
function linkStream(optResolver) {
|
|
|
|
function linkFile(file, enc, callback) {
|
|
var isRelative = optResolver.resolve('relativeSymlinks', file);
|
|
var flags = fo.getFlags({
|
|
overwrite: optResolver.resolve('overwrite', file),
|
|
append: false,
|
|
});
|
|
|
|
if (!isWindows) {
|
|
// On non-Windows, just use 'file'
|
|
return createLinkWithType('file');
|
|
}
|
|
|
|
fo.reflectStat(file.symlink, file, onReflectTarget);
|
|
|
|
function onReflectTarget(statErr) {
|
|
if (statErr && statErr.code !== 'ENOENT') {
|
|
return callback(statErr);
|
|
}
|
|
// If target doesn't exist, the vinyl will still carry the target stats.
|
|
// Let's use those to determine which kind of dangling link to create.
|
|
|
|
// This option provides a way to create a Junction instead of a
|
|
// Directory symlink on Windows. This comes with the following caveats:
|
|
// * NTFS Junctions cannot be relative.
|
|
// * NTFS Junctions MUST be directories.
|
|
// * NTFS Junctions must be on the same file system.
|
|
// * Most products CANNOT detect a directory is a Junction:
|
|
// This has the side effect of possibly having a whole directory
|
|
// deleted when a product is deleting the Junction directory.
|
|
// For example, JetBrains product lines will delete the entire contents
|
|
// of the TARGET directory because the product does not realize it's
|
|
// a symlink as the JVM and Node return false for isSymlink.
|
|
|
|
// This function is Windows only, so we don't need to check again
|
|
var useJunctions = optResolver.resolve('useJunctions', file);
|
|
|
|
var dirType = useJunctions ? 'junction' : 'dir';
|
|
var type = !statErr && file.isDirectory() ? dirType : 'file';
|
|
|
|
createLinkWithType(type);
|
|
}
|
|
|
|
function createLinkWithType(type) {
|
|
// This is done after prepare() to use the adjusted file.base property
|
|
if (isRelative && type !== 'junction') {
|
|
file.symlink = path.relative(file.base, file.symlink);
|
|
}
|
|
|
|
var opts = {
|
|
flags: flags,
|
|
type: type,
|
|
};
|
|
fo.symlink(file.symlink, file.path, opts, onSymlink);
|
|
}
|
|
|
|
function onSymlink(symlinkErr) {
|
|
if (symlinkErr) {
|
|
return callback(symlinkErr);
|
|
}
|
|
|
|
fo.reflectLinkStat(file.path, file, onReflectLink);
|
|
}
|
|
|
|
function onReflectLink(reflectErr) {
|
|
if (reflectErr) {
|
|
return callback(reflectErr);
|
|
}
|
|
|
|
callback(null, file);
|
|
}
|
|
}
|
|
|
|
return through.obj(linkFile);
|
|
}
|
|
|
|
module.exports = linkStream;
|