| 'use strict' |
| |
| const path = require('path') |
| const fs = require('graceful-fs') |
| const pathExists = require('../path-exists').pathExists |
| |
| /** |
| * Function that returns two types of paths, one relative to symlink, and one |
| * relative to the current working directory. Checks if path is absolute or |
| * relative. If the path is relative, this function checks if the path is |
| * relative to symlink or relative to current working directory. This is an |
| * initiative to find a smarter `srcpath` to supply when building symlinks. |
| * This allows you to determine which path to use out of one of three possible |
| * types of source paths. The first is an absolute path. This is detected by |
| * `path.isAbsolute()`. When an absolute path is provided, it is checked to |
| * see if it exists. If it does it's used, if not an error is returned |
| * (callback)/ thrown (sync). The other two options for `srcpath` are a |
| * relative url. By default Node's `fs.symlink` works by creating a symlink |
| * using `dstpath` and expects the `srcpath` to be relative to the newly |
| * created symlink. If you provide a `srcpath` that does not exist on the file |
| * system it results in a broken symlink. To minimize this, the function |
| * checks to see if the 'relative to symlink' source file exists, and if it |
| * does it will use it. If it does not, it checks if there's a file that |
| * exists that is relative to the current working directory, if does its used. |
| * This preserves the expectations of the original fs.symlink spec and adds |
| * the ability to pass in `relative to current working direcotry` paths. |
| */ |
| |
| function symlinkPaths (srcpath, dstpath, callback) { |
| if (path.isAbsolute(srcpath)) { |
| return fs.lstat(srcpath, (err) => { |
| if (err) { |
| err.message = err.message.replace('lstat', 'ensureSymlink') |
| return callback(err) |
| } |
| return callback(null, { |
| 'toCwd': srcpath, |
| 'toDst': srcpath |
| }) |
| }) |
| } else { |
| const dstdir = path.dirname(dstpath) |
| const relativeToDst = path.join(dstdir, srcpath) |
| return pathExists(relativeToDst, (err, exists) => { |
| if (err) return callback(err) |
| if (exists) { |
| return callback(null, { |
| 'toCwd': relativeToDst, |
| 'toDst': srcpath |
| }) |
| } else { |
| return fs.lstat(srcpath, (err) => { |
| if (err) { |
| err.message = err.message.replace('lstat', 'ensureSymlink') |
| return callback(err) |
| } |
| return callback(null, { |
| 'toCwd': srcpath, |
| 'toDst': path.relative(dstdir, srcpath) |
| }) |
| }) |
| } |
| }) |
| } |
| } |
| |
| function symlinkPathsSync (srcpath, dstpath) { |
| let exists |
| if (path.isAbsolute(srcpath)) { |
| exists = fs.existsSync(srcpath) |
| if (!exists) throw new Error('absolute srcpath does not exist') |
| return { |
| 'toCwd': srcpath, |
| 'toDst': srcpath |
| } |
| } else { |
| const dstdir = path.dirname(dstpath) |
| const relativeToDst = path.join(dstdir, srcpath) |
| exists = fs.existsSync(relativeToDst) |
| if (exists) { |
| return { |
| 'toCwd': relativeToDst, |
| 'toDst': srcpath |
| } |
| } else { |
| exists = fs.existsSync(srcpath) |
| if (!exists) throw new Error('relative srcpath does not exist') |
| return { |
| 'toCwd': srcpath, |
| 'toDst': path.relative(dstdir, srcpath) |
| } |
| } |
| } |
| } |
| |
| module.exports = { |
| symlinkPaths, |
| symlinkPathsSync |
| } |