1 |
|
2 | import fs from 'fs';
|
3 | import path from 'path';
|
4 | import semver from 'semver';
|
5 | import osenv from 'osenv';
|
6 | import spawn from 'cross-spawn';
|
7 | import _ from 'lodash';
|
8 | import DBInstance from '../../shared/db';
|
9 | import packageJson from '../../shared/packageJson';
|
10 | import { parseYaml } from '../../shared/yaml';
|
11 | import { setServerUrl } from '../../shared/git';
|
12 | import { UniversalPkg } from '../universal-pkg/dep/pkg';
|
13 | import {
|
14 | HEART_BEAT_COLLECTION,
|
15 | UPDATE_COLLECTION,
|
16 | BEAT_GAP,
|
17 | CHECK_UPDATE_GAP,
|
18 | FEFLOW_ROOT,
|
19 | UNIVERSAL_PKG_JSON
|
20 | } from '../../shared/constant';
|
21 | import loggerInstance from '../logger';
|
22 | import {
|
23 | getInstalledPlugins,
|
24 | getLatestVersion,
|
25 | getUniversalPluginVersion
|
26 | } from './utils';
|
27 |
|
28 | const pkg = require('../../../package.json');
|
29 | const { getPkgInfo } = require('../native/install');
|
30 | const version = pkg.version;
|
31 |
|
32 | const { debug, silent } = process.env;
|
33 | const root = path.join(osenv.home(), FEFLOW_ROOT);
|
34 | const configPath = path.join(root, '.feflowrc.yml');
|
35 | const universalPkgPath = path.join(root, UNIVERSAL_PKG_JSON);
|
36 | const dbFile = path.join(root, UPDATE_COLLECTION);
|
37 | const db = new DBInstance(dbFile);
|
38 | const heartDBFile = path.join(root, HEART_BEAT_COLLECTION);
|
39 | const heartDB = new DBInstance(heartDBFile);
|
40 | heartDB.setAutoCompact(BEAT_GAP * 1000);
|
41 | const logger = loggerInstance({
|
42 | debug: Boolean(debug),
|
43 | silent: Boolean(silent)
|
44 | });
|
45 |
|
46 |
|
47 | process.title = 'feflow-update-beat-proccess';
|
48 |
|
49 | const heartBeat = () => {
|
50 | heartDB.update('beat_time', String(new Date().getTime()));
|
51 | };
|
52 |
|
53 | const queryCliUpdate = async () => {
|
54 | const config = parseYaml(configPath);
|
55 |
|
56 | if (!config) {
|
57 | return;
|
58 | }
|
59 | if (
|
60 | config['lastUpdateCheck'] &&
|
61 | +new Date() - parseInt(config['lastUpdateCheck'], 10) <= 1000 * 3600 * 24
|
62 | ) {
|
63 | return;
|
64 | }
|
65 |
|
66 | if (config['autoUpdate'] !== 'true') {
|
67 | return;
|
68 | }
|
69 |
|
70 | const latestVersion: any = await getLatestVersion(
|
71 | '@feflow/cli',
|
72 | config['packageManager']
|
73 | );
|
74 | if (latestVersion && semver.gt(latestVersion, version)) {
|
75 | let updateData: any = await db.read('update_data');
|
76 | updateData = updateData?.['value'];
|
77 | if (updateData.latest_cli_version !== latestVersion) {
|
78 | const newUpdateData = {
|
79 | ...updateData,
|
80 | latest_cli_version: latestVersion
|
81 | };
|
82 | await db.update('update_data', newUpdateData);
|
83 | }
|
84 | }
|
85 | };
|
86 |
|
87 | const queryPluginsUpdate = async () => {
|
88 | const config = parseYaml(configPath);
|
89 | if (!config) {
|
90 | return;
|
91 | }
|
92 |
|
93 | Promise.all(
|
94 | getInstalledPlugins().map(async (name: any) => {
|
95 | const pluginPath = path.join(root, 'node_modules', name, 'package.json');
|
96 | const content: any = fs.readFileSync(pluginPath);
|
97 | const pkg: any = JSON.parse(content);
|
98 | const localVersion = pkg.version;
|
99 | const registryUrl = spawn
|
100 | .sync(config['packageManager'], ['config', 'get', 'registry'], {
|
101 | windowsHide: true
|
102 | })
|
103 | .stdout.toString()
|
104 | .replace(/\n/, '')
|
105 | .replace(/\/$/, '');
|
106 | const latestVersion = await packageJson(name, registryUrl).catch(
|
107 | (err: any) => {
|
108 | logger.debug('Check plugin update error', err);
|
109 | }
|
110 | );
|
111 |
|
112 | if (latestVersion && semver.gt(latestVersion, localVersion)) {
|
113 | return {
|
114 | name,
|
115 | latestVersion,
|
116 | localVersion
|
117 | };
|
118 | } else {
|
119 | logger.debug('All plugins is in latest version');
|
120 | }
|
121 | })
|
122 | ).then(async (plugins: any) => {
|
123 | plugins = plugins.filter((plugin: any) => {
|
124 | return plugin && plugin.name;
|
125 | });
|
126 | logger.debug('tnpm plugins update infomation', plugins);
|
127 | if (plugins.length) {
|
128 | let updateData: any = await db.read('update_data');
|
129 | updateData = updateData?.['value'];
|
130 | if (!_.isEqual(updateData.latest_plugins, plugins)) {
|
131 | const newUpdateData = {
|
132 | ...updateData,
|
133 | latest_plugins: plugins
|
134 | };
|
135 | await db.update('update_data', newUpdateData);
|
136 | }
|
137 | }
|
138 | });
|
139 | };
|
140 |
|
141 | const queryUniversalPluginsUpdate = async () => {
|
142 | const config = parseYaml(configPath);
|
143 | if (!config || !config['serverUrl']) {
|
144 | return;
|
145 | }
|
146 | setServerUrl(config['serverUrl']);
|
147 |
|
148 | const universalPkg = new UniversalPkg(universalPkgPath);
|
149 | const latestUniversalPlugins: any[] = [];
|
150 |
|
151 |
|
152 | for (const [pkg, version] of universalPkg.getInstalled()) {
|
153 | const pkgInfo = await getPkgInfo(
|
154 | { root, config, logger },
|
155 | `${pkg}@${version}`
|
156 | );
|
157 | if (!pkgInfo) {
|
158 | continue;
|
159 | }
|
160 | const versionObj = await getUniversalPluginVersion(pkgInfo, universalPkg);
|
161 | if (versionObj.latestVersion) {
|
162 | latestUniversalPlugins.push(versionObj);
|
163 | }
|
164 | }
|
165 |
|
166 | logger.debug('universal plugins update infomation', latestUniversalPlugins);
|
167 | if (latestUniversalPlugins.length) {
|
168 | let updateData: any = await db.read('update_data');
|
169 | updateData = updateData?.['value'];
|
170 | if (
|
171 | !_.isEqual(updateData.latest_universal_plugins, latestUniversalPlugins)
|
172 | ) {
|
173 | const newUpdateData = {
|
174 | ...updateData,
|
175 | latest_universal_plugins: latestUniversalPlugins
|
176 | };
|
177 | await db.update('update_data', newUpdateData);
|
178 | }
|
179 | }
|
180 | };
|
181 |
|
182 |
|
183 | setInterval(heartBeat, BEAT_GAP);
|
184 |
|
185 |
|
186 | setInterval(queryCliUpdate, CHECK_UPDATE_GAP);
|
187 |
|
188 |
|
189 | setInterval(queryPluginsUpdate, CHECK_UPDATE_GAP);
|
190 |
|
191 |
|
192 | setInterval(queryUniversalPluginsUpdate, CHECK_UPDATE_GAP);
|