UNPKG

3.5 kBJavaScriptView Raw
1'use strict';
2
3var assert = require('assert');
4var fs = require('fs');
5var fsPromises = require('fs').promises;
6var path = require('path');
7var globby = require('globby');
8var multimatch = require('multimatch');
9var ejs = require('ejs');
10var util = require('../util');
11var normalize = require('normalize-path');
12
13async function applyProcessingFileFunc(processFile, filename, self) {
14 var output = await Promise.resolve(processFile.call(self, filename));
15 return output instanceof Buffer ? output : Buffer.from(output);
16}
17
18function renderFilepath(filepath, context, tplSettings) {
19 if (!context) {
20 return filepath;
21 }
22
23 return ejs.render(filepath, context, tplSettings);
24}
25
26async function getOneFile(from) {
27 var oneFile;
28 if (typeof from === 'string') {
29 oneFile = from;
30 } else {
31 return undefined;
32 }
33
34 var resolved = path.resolve(oneFile);
35 try {
36 if ((await fsPromises.stat(resolved)).isFile()) {
37 return resolved;
38 }
39 } catch (e) {
40 }
41
42 return undefined;
43}
44
45exports.copyAsync = async function (from, to, options, context, tplSettings) {
46 to = path.resolve(to);
47 options = options || {};
48 var oneFile = await getOneFile(from);
49 if (oneFile) {
50 return this._copySingleAsync(oneFile, renderFilepath(to, context, tplSettings), options);
51 }
52
53 var fromGlob = util.globify(from);
54
55 var globOptions = {...options.globOptions, nodir: true};
56 var diskFiles = globby.sync(fromGlob, globOptions).map(filepath => path.resolve(filepath));
57 var storeFiles = [];
58 this.store.each(file => {
59 // The store may have a glob path and when we try to copy it will fail because not real file
60 if (!globby.hasMagic(normalize(file.path)) && multimatch([file.path], fromGlob).length !== 0 && !diskFiles.includes(file.path)) {
61 storeFiles.push(file.path);
62 }
63 });
64
65 var generateDestination = () => to;
66 if (Array.isArray(from) || !this.exists(from) || globby.hasMagic(normalize(from))) {
67 assert(
68 !this.exists(to) || fs.statSync(to).isDirectory(),
69 'When copying multiple files, provide a directory as destination'
70 );
71
72 const processDestinationPath = options.processDestinationPath || (path => path);
73 var root = util.getCommonPath(from);
74 generateDestination = filepath => {
75 var toFile = path.relative(root, filepath);
76 return processDestinationPath(path.join(to, toFile));
77 };
78 }
79
80 // Sanity checks: Makes sure we copy at least one file.
81 assert(options.ignoreNoMatch || diskFiles.length > 0 || storeFiles.length > 0, 'Trying to copy from a source that does not exist: ' + from);
82
83 await Promise.all([
84 ...diskFiles.map(file => {
85 return this._copySingleAsync(file, renderFilepath(generateDestination(file), context, tplSettings), options);
86 }),
87 ...storeFiles.map(file => {
88 return Promise.resolve(this._copySingle(file, renderFilepath(generateDestination(file), context, tplSettings), options));
89 })
90 ]);
91};
92
93exports._copySingleAsync = async function (from, to, options = {}) {
94 if (!options.processFile) {
95 return this._copySingle(from, to, options);
96 }
97
98 var contents = await applyProcessingFileFunc(options.processFile, from, this);
99
100 if (options.append) {
101 if (!this.store.existsInMemory) {
102 throw new Error('Current mem-fs is not compatible with append');
103 }
104
105 if (this.store.existsInMemory(to)) {
106 this.append(to, contents, {create: true, ...options});
107 return;
108 }
109 }
110
111 var stat = await fsPromises.stat(from);
112 this.write(to, contents, stat);
113};