symlink-paths.js 3.3 KB

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