1 | 'use strict';
|
2 |
|
3 | var assert = require('assert');
|
4 | var fs = require('fs');
|
5 | var fsPromises = require('fs').promises;
|
6 | var path = require('path');
|
7 | var globby = require('globby');
|
8 | var multimatch = require('multimatch');
|
9 | var ejs = require('ejs');
|
10 | var util = require('../util');
|
11 | var normalize = require('normalize-path');
|
12 |
|
13 | async 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 |
|
18 | function renderFilepath(filepath, context, tplSettings) {
|
19 | if (!context) {
|
20 | return filepath;
|
21 | }
|
22 |
|
23 | return ejs.render(filepath, context, tplSettings);
|
24 | }
|
25 |
|
26 | async 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 |
|
45 | exports.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 |
|
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 |
|
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 |
|
93 | exports._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 | };
|