UNPKG

3.93 kBJavaScriptView Raw
1const path = require('path');
2const fs = require('fs');
3const request = require('request');
4const zlib = require('zlib');
5const tar = require('tar');
6const ora = require('ora');
7const existsSync = require('fs').existsSync;
8const rimraf = require('rimraf');
9const mkdirp = require('mkdirp');
10const {
11 getLatestVersion,
12 getNpmRegistry,
13} = require('ice-npm-utils');
14
15const logger = require('./logger');
16const getPkgJSON = require('./pkg-json').getPkgJSON;
17
18const Parser = tar.Parse;
19
20/**
21 * local path validator
22 * @param {string} aPath
23 */
24function isLocalPath(aPath) {
25 return /^[./]|(^[a-zA-Z]:)/.test(aPath);
26}
27
28/**
29 * get material template path
30 * download it if template is a npm package
31 *
32 * @param {string} type material type
33 * @param {string} template material template name
34 */
35async function getTemplate(cwd, type, template) {
36 // from local path
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 // form npm package
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
63async 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 * delete dir
88 * @param {String} destDir
89 */
90function deleteDir(destDir) {
91 rimraf.sync(destDir);
92}
93
94/**
95 * download and filter npm files
96 *
97 * @param {Object} options npm, version, destDir
98 */
99function downloadAndFilterNpmFiles(npm, version, destDir) {
100 return new Promise((resolve, reject) => {
101 const taskComplete = {
102 // foo: false
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 /* eslint-disable-next-line no-useless-escape */
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
150module.exports = getTemplate;