broccoli-kitchen-sink-helpers
Advanced tools
Comparing version 0.2.4 to 0.2.5
# master | ||
# 0.2.5 | ||
* Follow symlinks in `copyRecursivelySync`, `copyPreserveSync`, and `hashTree` | ||
* Update `node-glob` to latest (4.0.5). | ||
# 0.2.4 | ||
@@ -4,0 +9,0 @@ |
127
index.js
@@ -7,25 +7,23 @@ var fs = require('fs') | ||
var isWindows = /^win/.test(process.platform) | ||
var isWindows = process.platform === 'win32' | ||
var pathSep = path.sep | ||
var keysForTreeWarningPrinted = false | ||
exports.hashTree = hashTree | ||
// This function is used by the watcher. It makes the following guarantees: | ||
// | ||
// (1) It never throws an exception. | ||
// | ||
// (2) It does not miss changes. In other words, if after this function returns, | ||
// any part of the directory hierarchy changes, a subsequent call must | ||
// return a different hash. | ||
// | ||
// (1) and (2) hold even in the face of a constantly-changing file system. | ||
function hashTree (fullPath) { | ||
// This function is used by the watcher. It makes the following guarantees: | ||
// | ||
// (1) It never throws an exception. | ||
// | ||
// (2) It does not miss changes. In other words, if after this function returns, | ||
// any part of the directory hierarchy changes, a subsequent call must | ||
// return a different hash. | ||
// | ||
// (1) and (2) hold even in the face of a constantly-changing file system. | ||
return hashStrings(keysForTree(fullPath)) | ||
} | ||
function keysForTree (fullPath, options) { | ||
options = options || {} | ||
var _stack = options._stack | ||
var _followSymlink = options._followSymlink | ||
var relativePath = options.relativePath || '.' | ||
function keysForTree (fullPath, initialRelativePath) { | ||
var relativePath = initialRelativePath || '.' | ||
var stats | ||
@@ -35,9 +33,8 @@ var statKeys | ||
try { | ||
if (_followSymlink) { | ||
stats = fs.statSync(fullPath) | ||
} else { | ||
stats = fs.lstatSync(fullPath) | ||
stats = fs.statSync(fullPath) | ||
} catch (err) { | ||
if (!keysForTreeWarningPrinted) { | ||
console.warn('Warning: failed to stat ' + fullPath) | ||
keysForTreeWarningPrinted = true | ||
} | ||
} catch (err) { | ||
console.warn('Warning: failed to stat ' + fullPath) | ||
// fullPath has probably ceased to exist. Leave `stats` undefined and | ||
@@ -54,37 +51,20 @@ // proceed hashing. | ||
var fileIdentity = stats.dev + '\x00' + stats.ino | ||
if (_stack != null && _stack.indexOf(fileIdentity) !== -1) { | ||
console.warn('Symlink directory loop detected at ' + fullPath + ' (note: loop detection may have false positives on Windows)') | ||
} else { | ||
if (_stack != null) _stack = _stack.concat([fileIdentity]) | ||
var entries | ||
try { | ||
entries = fs.readdirSync(fullPath).sort() | ||
} catch (err) { | ||
console.warn('Warning: Failed to read directory ' + fullPath) | ||
console.warn(err.stack) | ||
childKeys = ['readdir failed'] | ||
// That's all there is to say about this directory. | ||
var entries | ||
try { | ||
entries = fs.readdirSync(fullPath).sort() | ||
} catch (err) { | ||
console.warn('Warning: Failed to read directory ' + fullPath) | ||
console.warn(err.stack) | ||
childKeys = ['readdir failed'] | ||
// That's all there is to say about this directory. | ||
} | ||
if (entries != null) { | ||
for (var i = 0; i < entries.length; i++) { | ||
var keys = keysForTree( | ||
path.join(fullPath, entries[i]), | ||
path.join(relativePath, entries[i]) | ||
) | ||
childKeys = childKeys.concat(keys) | ||
} | ||
if (entries != null) { | ||
for (var i = 0; i < entries.length; i++) { | ||
var keys = keysForTree(path.join(fullPath, entries[i]), { | ||
_stack: _stack, | ||
relativePath: path.join(relativePath, entries[i]) | ||
}) | ||
childKeys = childKeys.concat(keys) | ||
} | ||
} | ||
} | ||
} else if (stats && stats.isSymbolicLink()) { | ||
if (_stack == null) { | ||
// From here on in the traversal, we need to guard against symlink | ||
// directory loops. _stack is kept null in the absence of symlinks to we | ||
// don't have to deal with Windows for now, as long as it doesn't use | ||
// symlinks. | ||
_stack = [] | ||
} | ||
childKeys = keysForTree(fullPath, {_stack: _stack, relativePath: relativePath, _followSymlink: true}) // follow symlink | ||
statKeys.push(stats.mtime.getTime()) | ||
statKeys.push(stats.size) | ||
} else if (stats && stats.isFile()) { | ||
@@ -95,3 +75,2 @@ statKeys.push(stats.mtime.getTime()) | ||
// Perhaps we should not use basename to infer the file name | ||
return ['path', relativePath] | ||
@@ -130,3 +109,3 @@ .concat(statKeys) | ||
// | ||
// This does not resolve symlinks. It is not clear whether it should. | ||
// This function dereferences symlinks. | ||
// | ||
@@ -137,7 +116,10 @@ // Note that unlike cp(1), we do not special-case if dest is an existing | ||
// | ||
// We would like to use wrench.copyDirSyncRecursive, but it has the following | ||
// problems: | ||
// * Returns(!) an error when the target directory exists; only alternative | ||
// is { forceDelete: true }, which does `rm -rf dest` (not what we want) | ||
// * Resolves symlinks, rather than copying them verbatim | ||
// This function is deprecated in favor of | ||
// https://github.com/broccolijs/node-copy-dereference | ||
// | ||
// copy-dereference differs from copyRecursivelySync in that it won't call | ||
// mkdirp to create the target directory (or the parent directory of the | ||
// target file), which makes it stricter: (1) It's not OK for the target | ||
// directory to exist already, and (2) missing parent directories will not | ||
// automatically be created. | ||
exports.copyRecursivelySync = copyRecursivelySync | ||
@@ -148,3 +130,3 @@ function copyRecursivelySync (src, dest, _mkdirp) { | ||
// is 3x slower than stat'ing in the common case that we have a file. | ||
var srcStats = fs.lstatSync(src) | ||
var srcStats = fs.statSync(src) | ||
if (srcStats.isDirectory()) { | ||
@@ -165,2 +147,5 @@ mkdirp.sync(dest) | ||
// This function is deprecated in favor of | ||
// https://github.com/broccolijs/node-copy-dereference | ||
// | ||
// srcStats is optional; use it as an optimization to avoid double stats | ||
@@ -170,3 +155,3 @@ // This function refuses to overwrite files. | ||
function copyPreserveSync (src, dest, srcStats) { | ||
if (srcStats == null) srcStats = fs.lstatSync(src) | ||
if (srcStats == null) srcStats = fs.statSync(src) | ||
if (srcStats.isFile()) { | ||
@@ -176,6 +161,2 @@ var content = fs.readFileSync(src) | ||
fs.utimesSync(dest, srcStats.atime, srcStats.mtime) | ||
} else if (srcStats.isSymbolicLink()) { | ||
fs.symlinkSync(fs.readlinkSync(src), dest) | ||
// We cannot update the atime/mtime of a symlink yet: | ||
// https://github.com/joyent/node/issues/2142 | ||
} else { | ||
@@ -243,2 +224,5 @@ throw new Error('Unexpected file type for ' + src) | ||
// This function is deprecated in favor of | ||
// https://github.com/broccolijs/node-symlink-or-copy | ||
exports.symlinkOrCopyPreserveSync = symlinkOrCopyPreserveSync | ||
@@ -249,3 +233,8 @@ function symlinkOrCopyPreserveSync (sourcePath, destPath) { | ||
} else { | ||
if (sourcePath[0] != pathSep) { | ||
if (fs.lstatSync(sourcePath).isSymbolicLink()) { | ||
// When we encounter symlinks, follow them. This prevents indirection | ||
// from growing out of control. Note: At the moment `realpath` on Node | ||
// is 70x slower than native: https://github.com/joyent/node/issues/7902 | ||
sourcePath = fs.realpathSync(sourcePath) | ||
} else if (sourcePath[0] !== pathSep) { | ||
sourcePath = process.cwd() + pathSep + sourcePath | ||
@@ -252,0 +241,0 @@ } |
{ | ||
"name": "broccoli-kitchen-sink-helpers", | ||
"description": "Collection of helpers that need to be extracted into separate packages", | ||
"version": "0.2.4", | ||
"version": "0.2.5", | ||
"author": "Jo Liss <joliss42@gmail.com>", | ||
@@ -14,4 +14,4 @@ "main": "index.js", | ||
"mkdirp": "^0.3.5", | ||
"glob": "^3.2.9" | ||
"glob": "^4.0.5" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
11247
210
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedglob@4.5.3(transitive)
+ Addedinflight@1.0.6(transitive)
+ Addedminimatch@2.0.10(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedwrappy@1.0.2(transitive)
- Removedglob@3.2.11(transitive)
- Removedlru-cache@2.7.3(transitive)
- Removedminimatch@0.3.0(transitive)
- Removedsigmund@1.0.1(transitive)
Updatedglob@^4.0.5