Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

258 lignes
8.8 KiB

  1. const fs = require('fs-extra');
  2. const { join, dirname, basename, extname } = require('path');
  3. const { toSystemPath, toAppPath, toSiteUrl, getUniqFile, parseTemplate } = require('../core/path');
  4. const { map } = require('../core/async');
  5. module.exports = {
  6. download: async function(options) {
  7. let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.download: path is required.'));
  8. let filename = this.parseOptional(options.filename, 'string', basename(path));
  9. if (fs.existsSync(path)) {
  10. this.res.download(path, filename);
  11. this.noOutput = true;
  12. } else {
  13. this.res.sendStatus(404);
  14. }
  15. },
  16. exists: async function(options) {
  17. let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.exists: path is required.'));
  18. if (await isFile(path)) {
  19. if (options.then) {
  20. await this.exec(options.then, true);
  21. }
  22. return true;
  23. } else {
  24. if (options.else) {
  25. await this.exec(options.else, true);
  26. }
  27. return false;
  28. }
  29. },
  30. direxists: async function(options) {
  31. let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.direxists: path is required.'));
  32. if (await isDirectory(path)) {
  33. if (options.then) {
  34. await this.exec(options.then, true);
  35. }
  36. return true;
  37. } else {
  38. if (options.else) {
  39. await this.exec(options.else, true);
  40. }
  41. return false;
  42. }
  43. },
  44. createdir: async function(options) {
  45. let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.createdir: path is required.'));
  46. await fs.ensureDir(path);
  47. return toAppPath(path);
  48. },
  49. removedir: async function(options) {
  50. let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.removedir: path is required.'));
  51. await fs.remove(path);
  52. return toAppPath(path);
  53. },
  54. emptydir: async function(options) {
  55. let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.emptydir: path is required.'));
  56. await fs.emptyDir(path)
  57. return toAppPath(path);
  58. },
  59. move: async function(options) {
  60. let from = toSystemPath(this.parseRequired(options.from, 'string', 'fs.move: from is required.'));
  61. let to = toSystemPath(this.parseRequired(options.to, 'string', 'fs.move: to is required.'));
  62. let overwrite = this.parseOptional(options.overwrite, 'boolean', false);
  63. let createdir = this.parseOptional(options.createdir, 'boolean', true);
  64. if (!fs.existsSync(to)) {
  65. if (createdir) {
  66. await fs.ensureDir(to);
  67. } else {
  68. throw new Error(`Destination path doesn't exists.`);
  69. }
  70. }
  71. to = join(to, basename(from));
  72. if (!overwrite) {
  73. to = getUniqFile(to);
  74. }
  75. await fs.move(from, to, { overwrite: true });
  76. return toAppPath(to);
  77. },
  78. rename: async function(options) {
  79. let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.rename: path is required.'));
  80. let template = this.parseRequired(options.template, 'string', 'fs.rename: template is required.');
  81. let overwrite = this.parseOptional(options.overwrite, 'boolean', false);
  82. let to = parseTemplate(path, template);
  83. if (!overwrite && fs.existsSync(to)) {
  84. throw new Error(`fs.rename: file "${to}" already exists.`);
  85. }
  86. await fs.rename(path, to);
  87. return toAppPath(to);
  88. },
  89. copy: async function(options) {
  90. let from = toSystemPath(this.parseRequired(options.from, 'string', 'fs.copy: from is required.'));
  91. let to = toSystemPath(this.parseRequired(options.to, 'string', 'fs.copy: to is required.'));
  92. let overwrite = this.parseOptional(options.overwrite, 'boolean', false);
  93. let createdir = this.parseOptional(options.createdir, 'boolean', true);
  94. if (!fs.existsSync(to)) {
  95. if (createdir) {
  96. await fs.ensureDir(to);
  97. } else {
  98. throw new Error(`Destination path doesn't exist.`);
  99. }
  100. }
  101. to = join(to, basename(from));
  102. if (!overwrite && fs.existsSync(to)) {
  103. to = getUniqFile(to);
  104. }
  105. await fs.copy(from, to);
  106. return toAppPath(to);
  107. },
  108. remove: async function(options) {
  109. let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.remove: path is required.'));
  110. await fs.unlink(path);
  111. return true;
  112. },
  113. dir: async function(options) {
  114. let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.dir: path is required.'));
  115. let allowedExtensions = this.parseOptional(options.allowedExtensions, 'string', '');
  116. let showHidden = this.parseOptional(options.showHidden, 'boolean', false);
  117. let includeFolders = this.parseOptional(options.includeFolders, 'boolean', false);
  118. let folderSize = this.parseOptional(options.folderSize, 'string', 'none');
  119. let concurrency = this.parseOptional(options.concurrency, 'number', 4);
  120. folderSize = ['none', 'files', 'recursive'].includes(folderSize) ? folderSize : 'none';
  121. allowedExtensions = allowedExtensions ? allowedExtensions.split(/\s*,\s*/).map(ext => lowercase(ext[0] == '.' ? ext : '.' + ext)) : [];
  122. let files = await fs.readdir(path, { withFileTypes: true });
  123. files = files.filter(entry => {
  124. if (!includeFolders && entry.isDirectory()) return false;
  125. if (!showHidden && entry.name[0] == '.') return false;
  126. if (allowedExtensions.length && entry.isFile() && !allowedExtensions.includes(lowercase(extname(entry.name)))) return false;
  127. return entry.isFile() || entry.isDirectory();
  128. });
  129. // Fast parallel map
  130. return map(files, async (entry) => {
  131. let curr = join(path, entry.name);
  132. let stat = await fs.stat(curr);
  133. if (folderSize != 'none' && entry.isDirectory()) {
  134. stat.size = await calcSize(curr, folderSize == 'recursive', concurrency);
  135. }
  136. return {
  137. type: entry.isFile() ? 'file' : 'dir',
  138. name: entry.name,
  139. folder: toAppPath(dirname(curr)),
  140. basename: basename(curr, extname(curr)),
  141. extension: extname(curr),
  142. path: toAppPath(curr),
  143. url: toSiteUrl(curr),
  144. size: stat.size,
  145. created: stat.ctime,
  146. accessed: stat.atime,
  147. modified: stat.mtime
  148. };
  149. }, concurrency);
  150. },
  151. stat: async function(options) {
  152. let path = toSystemPath(this.parseRequired(options.path, 'string', 'fs.stat: path is required.'));
  153. let folderSize = this.parseOptional(options.folderSize, 'string', 'none');
  154. let concurrency = this.parseOptional(options.concurrency, 'number', 4);
  155. folderSize = ['none', 'files', 'recursive'].includes(folderSize) ? folderSize : 'none';
  156. let stat = await fs.stat(path);
  157. if (folderSize != 'none' && stat.isDirectory()) {
  158. stat.size = await calcSize(path, folderSize == 'recursive', concurrency);
  159. }
  160. return {
  161. type: stat.isFile() ? 'file' : 'dir',
  162. name: basename(path),
  163. folder: toAppPath(dirname(path)),
  164. basename: basename(path, extname(path)),
  165. extension: extname(path),
  166. path: toAppPath(path),
  167. url: toSiteUrl(path),
  168. size: stat.size,
  169. created: stat.ctime,
  170. accessed: stat.atime,
  171. modified: stat.mtime
  172. };
  173. },
  174. };
  175. function lowercase(str) {
  176. return str.toLowerCase();
  177. }
  178. async function calcSize(folder, recursive, concurrency) {
  179. let entries = await fs.readdir(folder);
  180. return map(entries, async (entry) => {
  181. let stat = await fs.stat(join(folder, entry));
  182. if (stat.isDirectory() && recursive) {
  183. return calcSize(join(folder, entry), recursive, concurrency);
  184. }
  185. return stat.size;
  186. }, concurrency).then(arr => arr.reduce((size, curr) => size + curr, 0));
  187. };
  188. async function isFile(path) {
  189. try {
  190. let stats = await fs.stat(path);
  191. return stats.isFile();
  192. } catch (err) {
  193. return false;
  194. }
  195. }
  196. async function isDirectory(path) {
  197. try {
  198. let stats = await fs.stat(path);
  199. return stats.isDirectory();
  200. } catch (err) {
  201. return false;
  202. }
  203. }