1 |
|
2 |
|
3 | import semver from 'semver';
|
4 | import fs from 'fs';
|
5 | import path from 'path';
|
6 | import osenv from 'osenv';
|
7 | import DBInstance from '../../shared/db';
|
8 | import { install } from '../../shared/npm';
|
9 | import {
|
10 | UPDATE_COLLECTION,
|
11 | FEFLOW_ROOT,
|
12 | UNIVERSAL_PKG_JSON,
|
13 | UNIVERSAL_MODULES,
|
14 | FEFLOW_BIN,
|
15 | FEFLOW_LIB
|
16 | } from '../../shared/constant';
|
17 | import { setServerUrl } from '../../shared/git';
|
18 | import { parseYaml } from '../../shared/yaml';
|
19 | import loggerInstance from '../logger';
|
20 | import { UniversalPkg } from '../universal-pkg/dep/pkg';
|
21 | import { loadPlugin } from '../plugin/loadUniversalPlugin';
|
22 | import {
|
23 | getInstalledPlugins,
|
24 | getLatestVersion,
|
25 | updatePluginsVersion,
|
26 | getUniversalPluginVersion,
|
27 | promisify
|
28 | } from './utils';
|
29 |
|
30 |
|
31 | process.title = 'feflow-update-proccess';
|
32 |
|
33 | interface VersionObj {
|
34 | name: string;
|
35 | localVersion: any;
|
36 | latestVersion: any;
|
37 | repoPath: string;
|
38 | installVersion: any;
|
39 | }
|
40 | interface ErrorInstance {
|
41 | name: string;
|
42 | message: string;
|
43 | }
|
44 |
|
45 | const { updateCli } = require('../native/upgrade');
|
46 | const pkg = require('../../../package.json');
|
47 | const { getPkgInfo, updateUniversalPlugin } = require('../native/install');
|
48 | const version = pkg.version;
|
49 |
|
50 | const { cacheValidate, debug, silent, latestVersion } = process.env;
|
51 | const root = path.join(osenv.home(), FEFLOW_ROOT);
|
52 | const rootPkg = path.join(root, 'package.json');
|
53 | const configPath = path.join(root, '.feflowrc.yml');
|
54 | const universalPkgPath = path.join(root, UNIVERSAL_PKG_JSON);
|
55 | const universalModules = path.join(root, UNIVERSAL_MODULES);
|
56 | const config: any = parseYaml(configPath);
|
57 | const bin = path.join(root, FEFLOW_BIN);
|
58 | const lib = path.join(root, FEFLOW_LIB);
|
59 | const dbFile = path.join(root, UPDATE_COLLECTION);
|
60 | const universalPkg = new UniversalPkg(universalPkgPath);
|
61 | const db = new DBInstance(dbFile);
|
62 |
|
63 | const logger = loggerInstance({
|
64 | debug: Boolean(debug),
|
65 | silent: Boolean(silent)
|
66 | });
|
67 |
|
68 | if (!config) {
|
69 | process.exit();
|
70 | }
|
71 |
|
72 | const packageManager = config.packageManager;
|
73 | const ctx = {
|
74 | root,
|
75 | universalPkg,
|
76 | logger,
|
77 | universalModules,
|
78 | bin,
|
79 | lib,
|
80 | config
|
81 | };
|
82 | let updateData: any;
|
83 |
|
84 | const handleException = (e: ErrorInstance): void => {
|
85 | db.update('exception', `${e.name}: ${e.message}`).then(() => {
|
86 | process.exit(1);
|
87 | });
|
88 | };
|
89 |
|
90 | (process as NodeJS.EventEmitter).on('uncaughtException', handleException);
|
91 |
|
92 | (process as NodeJS.EventEmitter).on('unhandledRejection', handleException);
|
93 |
|
94 | function startUpdateCli() {
|
95 | return new Promise(async resolve => {
|
96 | if (latestVersion) {
|
97 | await updateCli(packageManager);
|
98 |
|
99 | updateData['cli_update_msg'] = {
|
100 | version,
|
101 | latestVersion
|
102 | };
|
103 | updateData['latest_cli_version'] = '';
|
104 | }
|
105 | resolve();
|
106 | });
|
107 | }
|
108 |
|
109 | async function startPluginsUpdate(plugins: string[]) {
|
110 | updatePluginsVersion(rootPkg, plugins);
|
111 |
|
112 | const needUpdatePlugins: any = [];
|
113 | plugins.forEach((plugin: any) => {
|
114 | needUpdatePlugins.push(plugin.name);
|
115 | });
|
116 |
|
117 | return install(
|
118 | packageManager,
|
119 | root,
|
120 | packageManager === 'yarn' ? 'add' : 'install',
|
121 | needUpdatePlugins,
|
122 | false,
|
123 | true
|
124 | ).then(() => {
|
125 | updateData['plugins_update_msg'] = plugins;
|
126 | updateData['latest_plugins'] = '';
|
127 |
|
128 | logger.info('Plugin update success');
|
129 | });
|
130 | }
|
131 |
|
132 | function checkPluginsUpdate() {
|
133 | return new Promise(async (resolve, reject) => {
|
134 | if (String(cacheValidate) === 'true') {
|
135 |
|
136 | const updatePkg = updateData['latest_plugins'];
|
137 | if (updatePkg.length) {
|
138 | await startPluginsUpdate(updatePkg);
|
139 | }
|
140 | resolve();
|
141 | } else {
|
142 |
|
143 | Promise.all(
|
144 | getInstalledPlugins().map(async (name: any) => {
|
145 | try {
|
146 | const pluginPath = path.join(
|
147 | root,
|
148 | 'node_modules',
|
149 | name,
|
150 | 'package.json'
|
151 | );
|
152 | const content: any = fs.readFileSync(pluginPath);
|
153 | const pkg: any = JSON.parse(content);
|
154 | const localVersion = pkg.version;
|
155 | const latestVersion = await getLatestVersion(name, packageManager);
|
156 | if (latestVersion && semver.gt(latestVersion, localVersion)) {
|
157 | return {
|
158 | name,
|
159 | latestVersion
|
160 | };
|
161 | } else {
|
162 | logger.debug('All plugins is in latest version');
|
163 | }
|
164 | } catch (e) {
|
165 | logger.debug(e);
|
166 | reject(e);
|
167 | }
|
168 | })
|
169 | ).then(async (plugins: any) => {
|
170 | plugins = plugins.filter((plugin: any) => {
|
171 | return plugin && plugin.name;
|
172 | });
|
173 | if (plugins.length) {
|
174 | await startPluginsUpdate(plugins);
|
175 | }
|
176 | resolve();
|
177 | });
|
178 | }
|
179 | });
|
180 | }
|
181 |
|
182 | function checkUniversalPluginsUpdate() {
|
183 | return new Promise(async resolve => {
|
184 | let updatePkg: any[] = [];
|
185 | const { serverUrl } = config;
|
186 | if (!serverUrl) {
|
187 | return;
|
188 | }
|
189 | setServerUrl(serverUrl);
|
190 | if (String(cacheValidate) === 'true') {
|
191 |
|
192 | updatePkg = updateData['latest_universal_plugins'];
|
193 | } else {
|
194 |
|
195 |
|
196 |
|
197 | for (const [pkg, version] of universalPkg.getInstalled()) {
|
198 |
|
199 | const pkgInfo = await getPkgInfo(ctx, `${pkg}@${version}`).catch(
|
200 | (e: string) => {
|
201 | db.insertOnce('update_error', `${pkg}@${version}`, e);
|
202 | }
|
203 | );
|
204 | if (!pkgInfo) {
|
205 | continue;
|
206 | }
|
207 | const versionObj = await getUniversalPluginVersion(
|
208 | pkgInfo,
|
209 | universalPkg
|
210 | );
|
211 | if (versionObj.latestVersion) {
|
212 | updatePkg.push(versionObj);
|
213 | }
|
214 | }
|
215 | }
|
216 |
|
217 | if (updatePkg.length) {
|
218 | const updateTasks = updatePkg.map(async (item: VersionObj) => {
|
219 | const { name, installVersion } = item;
|
220 |
|
221 | const plugin = loadPlugin(ctx, name, installVersion);
|
222 | return promisify(
|
223 | updateUniversalPlugin,
|
224 | ctx,
|
225 | name,
|
226 | installVersion,
|
227 | plugin
|
228 | );
|
229 | });
|
230 |
|
231 |
|
232 |
|
233 | for (const updateTask of updateTasks) {
|
234 | await (await updateTask)();
|
235 | }
|
236 |
|
237 | updateData['universal_plugins_update_msg'] = updatePkg;
|
238 | updateData['latest_universal_plugins'] = '';
|
239 | }
|
240 | resolve();
|
241 | });
|
242 | }
|
243 |
|
244 | db.read('update_data')
|
245 | .then(data => {
|
246 | updateData = data?.['value'];
|
247 | return Promise.all([
|
248 | startUpdateCli(),
|
249 | checkPluginsUpdate(),
|
250 | checkUniversalPluginsUpdate()
|
251 | ]).catch(handleException);
|
252 | })
|
253 | .then(() => {
|
254 | updateData['update_lock'] = '';
|
255 | db.update('update_data', updateData);
|
256 | })
|
257 | .catch((reason: any) => {
|
258 | updateData['update_lock'] = '';
|
259 | db.update('update_data', updateData);
|
260 |
|
261 | logger.debug(reason);
|
262 | handleException(reason);
|
263 | });
|