UNPKG

7.01 kBPlain TextView Raw
1/* eslint-disable @typescript-eslint/camelcase */
2// 更新依赖
3import semver from 'semver';
4import fs from 'fs';
5import path from 'path';
6import osenv from 'osenv';
7import DBInstance from '../../shared/db';
8import { install } from '../../shared/npm';
9import {
10 UPDATE_COLLECTION,
11 FEFLOW_ROOT,
12 UNIVERSAL_PKG_JSON,
13 UNIVERSAL_MODULES,
14 FEFLOW_BIN,
15 FEFLOW_LIB
16} from '../../shared/constant';
17import { setServerUrl } from '../../shared/git';
18import { parseYaml } from '../../shared/yaml';
19import loggerInstance from '../logger';
20import { UniversalPkg } from '../universal-pkg/dep/pkg';
21import { loadPlugin } from '../plugin/loadUniversalPlugin';
22import {
23 getInstalledPlugins,
24 getLatestVersion,
25 updatePluginsVersion,
26 getUniversalPluginVersion,
27 promisify
28} from './utils';
29
30// 设置特殊的进程名字
31process.title = 'feflow-update-proccess';
32
33interface VersionObj {
34 name: string;
35 localVersion: any;
36 latestVersion: any;
37 repoPath: string;
38 installVersion: any;
39}
40interface ErrorInstance {
41 name: string;
42 message: string;
43}
44
45const { updateCli } = require('../native/upgrade');
46const pkg = require('../../../package.json');
47const { getPkgInfo, updateUniversalPlugin } = require('../native/install');
48const version = pkg.version;
49
50const { cacheValidate, debug, silent, latestVersion } = process.env;
51const root = path.join(osenv.home(), FEFLOW_ROOT);
52const rootPkg = path.join(root, 'package.json');
53const configPath = path.join(root, '.feflowrc.yml');
54const universalPkgPath = path.join(root, UNIVERSAL_PKG_JSON);
55const universalModules = path.join(root, UNIVERSAL_MODULES);
56const config: any = parseYaml(configPath);
57const bin = path.join(root, FEFLOW_BIN);
58const lib = path.join(root, FEFLOW_LIB);
59const dbFile = path.join(root, UPDATE_COLLECTION);
60const universalPkg = new UniversalPkg(universalPkgPath);
61const db = new DBInstance(dbFile);
62
63const logger = loggerInstance({
64 debug: Boolean(debug),
65 silent: Boolean(silent)
66});
67
68if (!config) {
69 process.exit();
70}
71
72const packageManager = config.packageManager;
73const ctx = {
74 root,
75 universalPkg,
76 logger,
77 universalModules,
78 bin,
79 lib,
80 config
81};
82let updateData: any;
83
84const 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
94function 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
109async 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
132function 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
182function 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 // eslint-disable-next-line
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 // eslint-disable-next-line
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
244db.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 });