From 5dea3a99ced89882d70b8ae34674c28455217d36 Mon Sep 17 00:00:00 2001 From: Chris Barber Date: Tue, 2 Jul 2019 18:06:06 -0500 Subject: [PATCH] refactor(windows): Work on windowslib refactor. --- package.json | 3 +- packages/plugin-windows/CHANGELOG.md | 2 + packages/plugin-windows/conf/config.js | 40 +-- packages/plugin-windows/src/version.js | 77 ++++++ .../src/windows-info-service.js | 245 ++++++------------ 5 files changed, 168 insertions(+), 199 deletions(-) create mode 100644 packages/plugin-windows/src/version.js diff --git a/package.json b/package.json index b825dcc..ec78bb1 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ }, "scripts": { "build": "lerna exec gulp build", - "link": "lerna exec yarn link" + "link": "lerna exec yarn link", + "unlink": "lerna exec yarn unlink" }, "workspaces": { "packages": [ diff --git a/packages/plugin-windows/CHANGELOG.md b/packages/plugin-windows/CHANGELOG.md index d1108dc..a53a361 100644 --- a/packages/plugin-windows/CHANGELOG.md +++ b/packages/plugin-windows/CHANGELOG.md @@ -1,6 +1,8 @@ # v2.0.0 * BREAKING CHANGE: Removed all Windows Phone related code. + * BREAKING CHANGE: Renamed `windows` to `sdks` and `visualstudio` to `vs`in info results. + * BREAKING CHANGE: Removed `selectedVisualStudio` from info results. * fix: Updated config to remove redundant `windows` namespace. * chore: Update dependencies. diff --git a/packages/plugin-windows/conf/config.js b/packages/plugin-windows/conf/config.js index dc14bc9..36482cf 100644 --- a/packages/plugin-windows/conf/config.js +++ b/packages/plugin-windows/conf/config.js @@ -1,41 +1,25 @@ module.exports = { - device: { + sdk: { /** - * The number of milliseconds to rescan for connected devices. - * @type {Number} + * A list of paths to search for Windows SDKs. + * @type {Array.} */ - pollInterval: null + searchPaths: null }, - emulators: { + vs: { /** - * The number of milliseconds to rescan for emulators. - * @type {Number} + * A list of paths to search for Visual Studio installations. + * @type {Array.} */ - pollInterval: null + searchPaths: null }, - visualstudio: { + vswhere: { /** - * The number of milliseconds to rescan for Visual Studio installations. - * @type {Number} + * A list of paths to search for the `vswhere.exe` utility. + * @type {Array.} */ - pollInterval: null - }, - - windowsPhone: { - /** - * The number of milliseconds to rescan for Windows Phone SDKs. - * @type {Number} - */ - pollInterval: null - }, - - windowsSDK: { - /** - * The number of milliseconds to rescan for Windows SDKs. - * @type {Number} - */ - pollInterval: null + searchPaths: null } }; diff --git a/packages/plugin-windows/src/version.js b/packages/plugin-windows/src/version.js new file mode 100644 index 0000000..4038de7 --- /dev/null +++ b/packages/plugin-windows/src/version.js @@ -0,0 +1,77 @@ +import semver from 'semver'; + +function format(ver, min, max, chopDash) { + ver = ('' + (ver || 0)); + if (chopDash) { + ver = ver.replace(/(-.*)?$/, ''); + } + ver = ver.split('.'); + if (min !== undefined) { + while (ver.length < min) { + ver.push('0'); + } + } + if (max !== undefined) { + ver = ver.slice(0, max); + } + return ver.join('.'); +} + +function eq(v1, v2) { + return semver.eq(format(v1, 3, 3), format(v2, 3, 3)); +} + +function gte(v1, v2) { + return semver.gte(format(v1, 3, 3), format(v2, 3, 3)); +} + +function gt(v1, v2) { + return semver.gt(format(v1, 3, 3), format(v2, 3, 3)); +} + +function lte(v1, v2) { + return semver.lte(format(v1, 3, 3), format(v2, 3, 3)); +} + +function lt(v1, v2) { + return semver.lt(format(v1, 3, 3), format(v2, 3, 3)); +} + +function compare(v1, v2) { + return eq(v1, v2) ? 0 : lt(v1, v2) ? -1 : 1; +} + +function rcompare(v1, v2) { + return eq(v1, v2) ? 0 : lt(v1, v2) ? 1 : -1; +} + +function satisfies(ver, str) { + ver = format(ver, 3, 3, true); + str = str.replace(/(<=?\d+(\.\d+)*?)\.x/g, '$1.99999999').replace(/(>=?\d+(\.\d+)*?)\.x/g, '$1.0'); + try { + if (str === '*' || eq(ver, str)) { + return true; + } + } catch (ex) { + // squelch + } + + return str.split(/\s*\|\|\s*/).some(function (range) { + // semver is picky with the '-' in comparisons and it just so happens when it + // parses versions in the range, it will add '-0' and cause '1.0.0' != '1.0.0-0', + // so we test our version with and without the '-9' + return range === '*' || semver.satisfies(ver, range) || (ver.indexOf('-') === -1 && semver.satisfies(ver + '-0', range)); + }); +} + +export default { + format, + eq, + gte, + gt, + lte, + lt, + compare, + rcompare, + satisfies +}; diff --git a/packages/plugin-windows/src/windows-info-service.js b/packages/plugin-windows/src/windows-info-service.js index 19eb43e..b085927 100644 --- a/packages/plugin-windows/src/windows-info-service.js +++ b/packages/plugin-windows/src/windows-info-service.js @@ -1,8 +1,11 @@ +import DetectEngine from 'appcd-detect'; import gawk from 'gawk'; -import windowslib from 'windowslib'; +import version from './version'; + +import * as windowslib from 'windowslib'; import { DataServiceDispatcher } from 'appcd-dispatcher'; -import { get } from 'appcd-util'; +import { arrayify, get, mergeDeep } from 'appcd-util'; /** * The Windows info service. @@ -17,201 +20,103 @@ export default class WindowsInfoService extends DataServiceDispatcher { * @access public */ async activate(cfg) { + this.config = cfg; + if (cfg.windows) { + mergeDeep(windowslib.options, cfg.windows); + } + this.data = gawk({ - windows: {}, - visualstudio: {}, - selectedVisualStudio: {} + sdks: {}, + vs: {} }); - this.timers = {}; - - // wire up Visual Studio detection first so that we can use its result to know if we should query the other thing - await this.wireupDetection('visualstudio', get(cfg, 'windows.visualstudio.pollInterval') || 60000 * 10, () => this.detectVisualStudios()); - await this.wireupDetection('windows', get(cfg, 'windows.windowsSDK.pollInterval') || 60000 / 2, () => this.detectWindowsSDKs()); + /** + * A map of buckets to a list of active fs watch subscription ids. + * @type {Object} + */ + this.subscriptions = {}; + + /** + * ? + */ + // this.winregWatchHandles = {}; + + await Promise.all([ + this.initSDKs() // , + // this.initVisualStudios() + ]); } /** - * Stops all active timers. + * Shutsdown the Windows info service. * + * @returns {Promise} * @access public */ - deactivate() { - for (const timer of Object.values(this.timers)) { - clearTimeout(timer); + async deactivate() { + // for (const handle of Object.values(this.winregWatchHandles)) { + // handle.stop(); + // } + + if (this.sdkDetectEngine) { + await this.sdkDetectEngine.stop(); + this.sdkDetectEngine = null; } - this.timers = {}; } /** - * Executes a detect function, then stores the result and schedules the next check. + * Detect Windows SDKs. * - * @param {String} type - The bucket name for the detected results. - * @param {Number} interval - The amount of milliseconds until the next check. - * @param {Function} callback - A function to call that performs the detection. * @returns {Promise} * @access private */ - async wireupDetection(type, interval, callback) { - try { - const result = await callback(); - if (result) { - console.log(`Updating data for ${type}`); - gawk.set(this.data[type], result); - } - } catch (err) { - console.log(err); - } - - this.timers[type] = setTimeout(() => { - this.wireupDetection(type, interval, callback); - }, interval); - } - - /** - * Checks if there are any Visual Studios installed. - * - * @returns {Boolean} - * @access private - */ - haveVisualStudio() { - return Object.keys(this.data.visualstudio).length > 0; - } - - /** - * Detect Windows Phone devices. - * - * @returns {Promise>} - * @access private - */ - detectDevices() { - return new Promise((resolve, reject) => { - if (!this.haveVisualStudio()) { - return resolve(); - } - - console.log('Detecting devices info'); - windowslib.device.detect({ bypassCache: true }, (err, results) => { - if (err) { - reject(err); - } else { - const devices = results.devices; - let wpsdkIndex = -1; - let realDeviceIndex = -1; - for (let i = 0; i < devices.length; i++) { - const device = devices[i]; - if (device.udid === 0 && device.wpsdk) { - wpsdkIndex = i; - } else if (device.udid !== 0 && !device.wpsdk) { - // now find with "real" device - realDeviceIndex = i; - } - if (wpsdkIndex !== -1 && realDeviceIndex !== -1) { - break; - } - } - if (wpsdkIndex !== -1 && realDeviceIndex !== -1) { - // set 'real' device wpsdk to the value we got from wptool binary - devices[realDeviceIndex].wpsdk = devices[wpsdkIndex].wpsdk; - // remove the wptool binary entry - devices.splice(wpsdkIndex, 1); - } - resolve(devices); + async initSDKs() { + const paths = [ + ...arrayify(get(this.config, 'windows.sdk.searchPaths'), true), + windowslib.sdk.defaultPath + ]; + + this.sdkDetectEngine = new DetectEngine({ + checkDir(dir) { + try { + return windowslib.sdk.detectSDKs(dir); + } catch (e) { + // 'dir' is not an SDK } - }); + }, + depth: 1, + multiple: true, + name: 'windows:sdk', + paths, + recursive: true, + recursiveWatchDepth: 3, + redetect: true, + // registryKeys: windowslib.sdk.registryKeys.map(key => ({ + // key: new RegExp(key + ) + // })), + watch: true }); - } - /** - * Detect Windows Phone emulators. - * - * @returns {Promise} - * @access private - */ - detectEmulators() { - return new Promise((resolve, reject) => { - if (!this.haveVisualStudio()) { - return resolve(); + // listen for sdk results + this.sdkDetectEngine.on('results', results => { + const sdks = {}; + for (const sdk of results.sort((a, b) => version.compare(a.version, b.version))) { + sdks[sdk.version] = sdk; } - - console.log('Detecting emulator info'); - windowslib.emulator.detect({ bypassCache: true }, (err, results) => { - if (err) { - reject(err); - } else { - resolve(results.emulators); - } - }); + gawk.set(this.data.sdks, sdks); }); - } - - /** - * Detect Visual Studio installations. - * - * @returns {Promise} - * @access private - */ - detectVisualStudios() { - return new Promise((resolve, reject) => { - console.log('Detecting visualstudio info'); - windowslib.visualstudio.detect({ bypassCache: true }, (err, results) => { - if (err) { - return reject(err); - } - let found = false; - if (results.visualstudio) { - for (const visualstudio of Object.keys(results.visualstudio)) { - if (results.visualstudio[visualstudio].selected) { - found = true; - gawk.set(this.data.selectedVisualStudio, results.visualstudio[visualstudio]); - break; - } - } - } - if (!found) { - this.data.selectedVisualStudio = null; - } - - resolve(results.visualstudio); - }); - }); + await this.sdkDetectEngine.start(); } /** - * Detect Windows Store SDK information. - * - * @returns {Promise} - * @access private - */ - detectWindowsSDKs() { - return new Promise((resolve, reject) => { - console.log('Detecting windows store info'); - windowslib.winstore.detect({ bypassCache: true }, (err, results) => { - if (err) { - reject(err); - } else { - resolve(results.windows); - } - }); - }); - } - - /** - * Detect Windows Phone SDK information. + * Detect Visual Studio installations. * - * @returns {Promise} + * @returns {Promise} * @access private - */ - detectWindowsPhone() { - return new Promise((resolve, reject) => { - console.log('Detecting windowsphone info'); - windowslib.windowsphone.detect({ bypassCache: true }, (err, results) => { - if (err) { - reject(err); - } else { - resolve(results.windowsphone); - } - }); - }); + * / + initVisualStudios() { + // } + */ }