symlink-paths.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. 'use strict'
  2. const path = require('path')
  3. const fs = require('graceful-fs')
  4. const pathExists = require('../path-exists').pathExists
  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, (err) => {
  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. const dstdir = path.dirname(dstpath)
  40. const relativeToDst = path.join(dstdir, srcpath)
  41. return pathExists(relativeToDst, (err, exists) => {
  42. if (err) return callback(err)
  43. if (exists) {
  44. return callback(null, {
  45. toCwd: relativeToDst,
  46. toDst: srcpath
  47. })
  48. } else {
  49. return fs.lstat(srcpath, (err) => {
  50. if (err) {
  51. err.message = err.message.replace('lstat', 'ensureSymlink')
  52. return callback(err)
  53. }
  54. return callback(null, {
  55. toCwd: srcpath,
  56. toDst: path.relative(dstdir, srcpath)
  57. })
  58. })
  59. }
  60. })
  61. }
  62. }
  63. function symlinkPathsSync (srcpath, dstpath) {
  64. let exists
  65. if (path.isAbsolute(srcpath)) {
  66. exists = fs.existsSync(srcpath)
  67. if (!exists) throw new Error('absolute srcpath does not exist')
  68. return {
  69. toCwd: srcpath,
  70. toDst: srcpath
  71. }
  72. } else {
  73. const dstdir = path.dirname(dstpath)
  74. const relativeToDst = path.join(dstdir, srcpath)
  75. exists = fs.existsSync(relativeToDst)
  76. if (exists) {
  77. return {
  78. toCwd: relativeToDst,
  79. toDst: srcpath
  80. }
  81. } else {
  82. exists = fs.existsSync(srcpath)
  83. if (!exists) throw new Error('relative srcpath does not exist')
  84. return {
  85. toCwd: srcpath,
  86. toDst: path.relative(dstdir, srcpath)
  87. }
  88. }
  89. }
  90. }
  91. module.exports = {
  92. symlinkPaths,
  93. symlinkPathsSync
  94. }