1 | const path = require('path');
|
2 | const fs = require('fs');
|
3 | const request = require('request');
|
4 | const zlib = require('zlib');
|
5 | const tar = require('tar');
|
6 | const ora = require('ora');
|
7 | const existsSync = require('fs').existsSync;
|
8 | const rimraf = require('rimraf');
|
9 | const mkdirp = require('mkdirp');
|
10 | const {
|
11 | getLatestVersion,
|
12 | getNpmRegistry,
|
13 | } = require('ice-npm-utils');
|
14 |
|
15 | const logger = require('./logger');
|
16 | const getPkgJSON = require('./pkg-json').getPkgJSON;
|
17 |
|
18 | const Parser = tar.Parse;
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | function isLocalPath(aPath) {
|
25 | return /^[./]|(^[a-zA-Z]:)/.test(aPath);
|
26 | }
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | async function getTemplate(cwd, type, template) {
|
36 |
|
37 | if (template && isLocalPath(template)) {
|
38 | logger.verbose('getTemplate -> local', template, type);
|
39 |
|
40 | const templatePath = path.join(template, type === 'material' ? 'template' : `template/${type}`);
|
41 | if (existsSync(templatePath)) {
|
42 | const pkgJson = getPkgJSON(template);
|
43 | return {
|
44 | templatePath,
|
45 | config: pkgJson.materialConfig || {},
|
46 | };
|
47 | }
|
48 | logger.fatal(`template is not found in ${templatePath}`);
|
49 | }
|
50 |
|
51 |
|
52 | logger.verbose('getTemplate -> start download npm', template, type);
|
53 |
|
54 | const downloadDir = path.join(cwd, '.ice-template');
|
55 | const tmp = await downloadTemplate(template, downloadDir);
|
56 | return {
|
57 | downloadPath: downloadDir,
|
58 | templatePath: path.join(tmp, type === 'material' ? 'template' : `template/${type}`),
|
59 | config: getPkgJSON(tmp).materialConfig || {},
|
60 | };
|
61 | }
|
62 |
|
63 | async function downloadTemplate(template, downloadDir) {
|
64 | downloadDir = path.join(downloadDir, template);
|
65 |
|
66 | logger.verbose('downloadTemplate', template, downloadDir);
|
67 | const spinner = ora('downloading template...').start();
|
68 |
|
69 | try {
|
70 | deleteDir(downloadDir);
|
71 | const npmVersion = await getLatestVersion(template);
|
72 |
|
73 | await downloadAndFilterNpmFiles(
|
74 | template,
|
75 | npmVersion,
|
76 | downloadDir
|
77 | );
|
78 | spinner.succeed('Download success.');
|
79 | return downloadDir;
|
80 | } catch (err) {
|
81 | spinner.fail(`Failed to download repo ${template}.`);
|
82 | logger.fatal(err);
|
83 | }
|
84 | }
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 | function deleteDir(destDir) {
|
91 | rimraf.sync(destDir);
|
92 | }
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 | function downloadAndFilterNpmFiles(npm, version, destDir) {
|
100 | return new Promise((resolve, reject) => {
|
101 | const taskComplete = {
|
102 |
|
103 | };
|
104 | function end() {
|
105 | const isDone = Object.values(taskComplete).every((done) => done === true);
|
106 |
|
107 | if (isDone) {
|
108 | resolve(destDir);
|
109 | }
|
110 | }
|
111 |
|
112 | const npmTarball = `${getNpmRegistry(npm)}/${npm}/-/${npm}-${version}.tgz`;
|
113 | logger.info('npmtra', npmTarball);
|
114 |
|
115 | request
|
116 | .get(npmTarball)
|
117 | .on('error', (err) => {
|
118 | reject(err);
|
119 | })
|
120 | .pipe(zlib.createGunzip())
|
121 | .pipe(new Parser())
|
122 | .on('entry', (entry) => {
|
123 |
|
124 | const templatePathReg = new RegExp('(package\/template\/)');
|
125 |
|
126 | let realPath;
|
127 | let destPath;
|
128 |
|
129 | if (templatePathReg.test(entry.path)) {
|
130 | realPath = entry.path.replace(templatePathReg, '');
|
131 | destPath = path.join(destDir, 'template', realPath);
|
132 | } else {
|
133 | realPath = entry.path.replace('package/', '');
|
134 | destPath = path.join(destDir, realPath);
|
135 | }
|
136 |
|
137 | mkdirp.sync(path.dirname(destPath));
|
138 | taskComplete[destPath] = false;
|
139 | entry.pipe(fs.createWriteStream(destPath)).on('close', () => {
|
140 | taskComplete[destPath] = true;
|
141 | end();
|
142 | });
|
143 | })
|
144 | .on('end', () => {
|
145 | end();
|
146 | });
|
147 | });
|
148 | }
|
149 |
|
150 | module.exports = getTemplate;
|