io-util.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. "use strict";
  2. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  3. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  4. return new (P || (P = Promise))(function (resolve, reject) {
  5. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  6. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  7. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  8. step((generator = generator.apply(thisArg, _arguments || [])).next());
  9. });
  10. };
  11. var _a;
  12. Object.defineProperty(exports, "__esModule", { value: true });
  13. const assert_1 = require("assert");
  14. const fs = require("fs");
  15. const path = require("path");
  16. _a = fs.promises, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink;
  17. exports.IS_WINDOWS = process.platform === 'win32';
  18. function exists(fsPath) {
  19. return __awaiter(this, void 0, void 0, function* () {
  20. try {
  21. yield exports.stat(fsPath);
  22. }
  23. catch (err) {
  24. if (err.code === 'ENOENT') {
  25. return false;
  26. }
  27. throw err;
  28. }
  29. return true;
  30. });
  31. }
  32. exports.exists = exists;
  33. function isDirectory(fsPath, useStat = false) {
  34. return __awaiter(this, void 0, void 0, function* () {
  35. const stats = useStat ? yield exports.stat(fsPath) : yield exports.lstat(fsPath);
  36. return stats.isDirectory();
  37. });
  38. }
  39. exports.isDirectory = isDirectory;
  40. /**
  41. * On OSX/Linux, true if path starts with '/'. On Windows, true for paths like:
  42. * \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases).
  43. */
  44. function isRooted(p) {
  45. p = normalizeSeparators(p);
  46. if (!p) {
  47. throw new Error('isRooted() parameter "p" cannot be empty');
  48. }
  49. if (exports.IS_WINDOWS) {
  50. return (p.startsWith('\\') || /^[A-Z]:/i.test(p) // e.g. \ or \hello or \\hello
  51. ); // e.g. C: or C:\hello
  52. }
  53. return p.startsWith('/');
  54. }
  55. exports.isRooted = isRooted;
  56. /**
  57. * Recursively create a directory at `fsPath`.
  58. *
  59. * This implementation is optimistic, meaning it attempts to create the full
  60. * path first, and backs up the path stack from there.
  61. *
  62. * @param fsPath The path to create
  63. * @param maxDepth The maximum recursion depth
  64. * @param depth The current recursion depth
  65. */
  66. function mkdirP(fsPath, maxDepth = 1000, depth = 1) {
  67. return __awaiter(this, void 0, void 0, function* () {
  68. assert_1.ok(fsPath, 'a path argument must be provided');
  69. fsPath = path.resolve(fsPath);
  70. if (depth >= maxDepth)
  71. return exports.mkdir(fsPath);
  72. try {
  73. yield exports.mkdir(fsPath);
  74. return;
  75. }
  76. catch (err) {
  77. switch (err.code) {
  78. case 'ENOENT': {
  79. yield mkdirP(path.dirname(fsPath), maxDepth, depth + 1);
  80. yield exports.mkdir(fsPath);
  81. return;
  82. }
  83. default: {
  84. let stats;
  85. try {
  86. stats = yield exports.stat(fsPath);
  87. }
  88. catch (err2) {
  89. throw err;
  90. }
  91. if (!stats.isDirectory())
  92. throw err;
  93. }
  94. }
  95. }
  96. });
  97. }
  98. exports.mkdirP = mkdirP;
  99. /**
  100. * Best effort attempt to determine whether a file exists and is executable.
  101. * @param filePath file path to check
  102. * @param extensions additional file extensions to try
  103. * @return if file exists and is executable, returns the file path. otherwise empty string.
  104. */
  105. function tryGetExecutablePath(filePath, extensions) {
  106. return __awaiter(this, void 0, void 0, function* () {
  107. let stats = undefined;
  108. try {
  109. // test file exists
  110. stats = yield exports.stat(filePath);
  111. }
  112. catch (err) {
  113. if (err.code !== 'ENOENT') {
  114. // eslint-disable-next-line no-console
  115. console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`);
  116. }
  117. }
  118. if (stats && stats.isFile()) {
  119. if (exports.IS_WINDOWS) {
  120. // on Windows, test for valid extension
  121. const upperExt = path.extname(filePath).toUpperCase();
  122. if (extensions.some(validExt => validExt.toUpperCase() === upperExt)) {
  123. return filePath;
  124. }
  125. }
  126. else {
  127. if (isUnixExecutable(stats)) {
  128. return filePath;
  129. }
  130. }
  131. }
  132. // try each extension
  133. const originalFilePath = filePath;
  134. for (const extension of extensions) {
  135. filePath = originalFilePath + extension;
  136. stats = undefined;
  137. try {
  138. stats = yield exports.stat(filePath);
  139. }
  140. catch (err) {
  141. if (err.code !== 'ENOENT') {
  142. // eslint-disable-next-line no-console
  143. console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`);
  144. }
  145. }
  146. if (stats && stats.isFile()) {
  147. if (exports.IS_WINDOWS) {
  148. // preserve the case of the actual file (since an extension was appended)
  149. try {
  150. const directory = path.dirname(filePath);
  151. const upperName = path.basename(filePath).toUpperCase();
  152. for (const actualName of yield exports.readdir(directory)) {
  153. if (upperName === actualName.toUpperCase()) {
  154. filePath = path.join(directory, actualName);
  155. break;
  156. }
  157. }
  158. }
  159. catch (err) {
  160. // eslint-disable-next-line no-console
  161. console.log(`Unexpected error attempting to determine the actual case of the file '${filePath}': ${err}`);
  162. }
  163. return filePath;
  164. }
  165. else {
  166. if (isUnixExecutable(stats)) {
  167. return filePath;
  168. }
  169. }
  170. }
  171. }
  172. return '';
  173. });
  174. }
  175. exports.tryGetExecutablePath = tryGetExecutablePath;
  176. function normalizeSeparators(p) {
  177. p = p || '';
  178. if (exports.IS_WINDOWS) {
  179. // convert slashes on Windows
  180. p = p.replace(/\//g, '\\');
  181. // remove redundant slashes
  182. return p.replace(/\\\\+/g, '\\');
  183. }
  184. // remove redundant slashes
  185. return p.replace(/\/\/+/g, '/');
  186. }
  187. // on Mac/Linux, test the execute bit
  188. // R W X R W X R W X
  189. // 256 128 64 32 16 8 4 2 1
  190. function isUnixExecutable(stats) {
  191. return ((stats.mode & 1) > 0 ||
  192. ((stats.mode & 8) > 0 && stats.gid === process.getgid()) ||
  193. ((stats.mode & 64) > 0 && stats.uid === process.getuid()));
  194. }
  195. //# sourceMappingURL=io-util.js.map