symlink-paths.js 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. var path = require('path')
  2. // path.isAbsolute shim for Node.js 0.10 support
  3. path.isAbsolute = (path.isAbsolute) ? path.isAbsolute : require('path-is-absolute')
  4. var fs = require('graceful-fs')
  5. /**
  6. * Function that returns two types of paths, one relative to symlink, and one
  7. * relative to the current working directory. Checks if path is absolute or
  8. * relative. If the path is relative, this function checks if the path is
  9. * relative to symlink or relative to current working directory. This is an
  10. * initiative to find a smarter `srcpath` to supply when building symlinks.
  11. * This allows you to determine which path to use out of one of three possible
  12. * types of source paths. The first is an absolute path. This is detected by
  13. * `path.isAbsolute()`. When an absolute path is provided, it is checked to
  14. * see if it exists. If it does it's used, if not an error is returned
  15. * (callback)/ thrown (sync). The other two options for `srcpath` are a
  16. * relative url. By default Node's `fs.symlink` works by creating a symlink
  17. * using `dstpath` and expects the `srcpath` to be relative to the newly
  18. * created symlink. If you provide a `srcpath` that does not exist on the file
  19. * system it results in a broken symlink. To minimize this, the function
  20. * checks to see if the 'relative to symlink' source file exists, and if it
  21. * does it will use it. If it does not, it checks if there's a file that
  22. * exists that is relative to the current working directory, if does its used.
  23. * This preserves the expectations of the original fs.symlink spec and adds
  24. * the ability to pass in `relative to current working direcotry` paths.
  25. */
  26. function symlinkPaths (srcpath, dstpath, callback) {
  27. if (path.isAbsolute(srcpath)) {
  28. return fs.lstat(srcpath, function (err, stat) {
  29. if (err) {
  30. err.message = err.message.replace('lstat', 'ensureSymlink')
  31. return callback(err)
  32. }
  33. return callback(null, {
  34. 'toCwd': srcpath,
  35. 'toDst': srcpath
  36. })
  37. })
  38. } else {
  39. var dstdir = path.dirname(dstpath)
  40. var relativeToDst = path.join(dstdir, srcpath)
  41. return fs.exists(relativeToDst, function (exists) {
  42. if (exists) {
  43. return callback(null, {
  44. 'toCwd': relativeToDst,
  45. 'toDst': srcpath
  46. })
  47. } else {
  48. return fs.lstat(srcpath, function (err, stat) {
  49. if (err) {
  50. err.message = err.message.replace('lstat', 'ensureSymlink')
  51. return callback(err)
  52. }
  53. return callback(null, {
  54. 'toCwd': srcpath,
  55. 'toDst': path.relative(dstdir, srcpath)
  56. })
  57. })
  58. }
  59. })
  60. }
  61. }
  62. function symlinkPathsSync (srcpath, dstpath) {
  63. var exists
  64. if (path.isAbsolute(srcpath)) {
  65. exists = fs.existsSync(srcpath)
  66. if (!exists) throw new Error('absolute srcpath does not exist')
  67. return {
  68. 'toCwd': srcpath,
  69. 'toDst': srcpath
  70. }
  71. } else {
  72. var dstdir = path.dirname(dstpath)
  73. var relativeToDst = path.join(dstdir, srcpath)
  74. exists = fs.existsSync(relativeToDst)
  75. if (exists) {
  76. return {
  77. 'toCwd': relativeToDst,
  78. 'toDst': srcpath
  79. }
  80. } else {
  81. exists = fs.existsSync(srcpath)
  82. if (!exists) throw new Error('relative srcpath does not exist')
  83. return {
  84. 'toCwd': srcpath,
  85. 'toDst': path.relative(dstdir, srcpath)
  86. }
  87. }
  88. }
  89. }
  90. module.exports = {
  91. 'symlinkPaths': symlinkPaths,
  92. 'symlinkPathsSync': symlinkPathsSync
  93. }