UNPKG

10.2 kBJavaScriptView Raw
1/**
2 * Detects the Windows Phone SDKs.
3 *
4 * @module windowsphone
5 *
6 * @copyright
7 * Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved.
8 *
9 * @license
10 * Licensed under the terms of the Apache Public License
11 * Please see the LICENSE included with this distribution for details.
12 */
13
14const
15 appc = require('node-appc'),
16 async = require('async'),
17 fs = require('fs'),
18 magik = require('./utilities').magik,
19 mix = require('./utilities').mix,
20 path = require('path'),
21 __ = appc.i18n(__dirname).__;
22
23var detectCache,
24 deviceCache = {};
25
26exports.detect = detect;
27
28/**
29 * Detects Windows Phone SDKs 8.0/8.1.
30 * @param {Object} [options] - An object containing various settings.
31 * @param {Boolean} [options.bypassCache=false] - When true, re-detects the Windows Phone SDKs.
32 * @param {String} [options.preferredWindowsPhoneSDK] - The preferred version of the Windows Phone SDK to use by default. Example "8.0".
33 * @param {String} [options.supportedWindowsPhoneSDKVersions] - A string with a version number or range to check if a Windows Phone SDK is supported.
34 * @param {Function} [callback(err, results)] - A function to call with the Windows Phone SDK information.
35 */
36function detectLegacy(options, callback) {
37 var results = {
38 windowsphone: {},
39 issues: []
40 },
41 searchPaths = [
42 'HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Microsoft SDKs\\WindowsPhone', // probably nothing here
43 'HKEY_LOCAL_MACHINE\\Software\\Wow6432Node\\Microsoft\\Microsoft SDKs\\WindowsPhone' // this is most likely where WPSDK will be found
44 ];
45
46 async.each(searchPaths, function (keyPath, next) {
47 appc.subprocess.run('reg', ['query', keyPath], function (code, out, err) {
48 var keyRegExp = /.+\\(v\d+\.\d)$/;
49 if (!code) {
50 out.trim().split(/\r\n|\n/).forEach(function (key) {
51 key = key.trim();
52 var m = key.match(keyRegExp),
53 version = m[1].replace(/^v/, '');
54 if (m) {
55 results.windowsphone || (results.windowsphone = {});
56 results.windowsphone[version] = {
57 version: version,
58 registryKey: keyPath + '\\' + m[1],
59 supported: !options.supportedWindowsPhoneSDKVersions || appc.version.satisfies(version, options.supportedWindowsPhoneSDKVersions, false), // no maybes
60 path: null,
61 deployCmd: null,
62 xapSignTool: null,
63 selected: false,
64 sdks: []
65 };
66 }
67 });
68 }
69 next();
70 });
71 }, function () {
72 // check if we didn't find any Windows Phone SDKs, then we're done
73 if (!Object.keys(results.windowsphone).length) {
74 return callback(null, results);
75 }
76
77 // fetch Windows Phone SDK install information
78 async.each(Object.keys(results.windowsphone), function (ver, next) {
79 appc.subprocess.run('reg', ['query', results.windowsphone[ver].registryKey + '\\Install Path', '/v', '*'], function (code, out, err) {
80 if (code) {
81 // bad key? either way, remove this version
82 delete results.windowsphone[ver];
83 } else {
84 // get only the values we are interested in
85 out.trim().split(/\r\n|\n/).forEach(function (line) {
86 var parts = line.trim().split(' ').map(function (p) { return p.trim(); });
87 if (parts.length == 3) {
88 if (parts[0] == 'Install Path') {
89 results.windowsphone[ver].path = parts[2];
90
91 var deployCmd = path.join(parts[2], 'Tools', 'XAP Deployment', 'XapDeployCmd.exe');
92 // check the old WP8 location
93 if (fs.existsSync(deployCmd)) {
94 results.windowsphone[ver].deployCmd = deployCmd;
95 // check the new WP8.1 location
96 } else if (fs.existsSync(deployCmd = path.join(parts[2], 'Tools', 'AppDeploy', 'AppDeployCmd.exe'))) {
97 results.windowsphone[ver].deployCmd = deployCmd;
98 } else {
99 // no deploy command! For now, mark unsupported!
100 results.windowsphone[ver].supported = false;
101 }
102
103 var xapSignTool = path.join(parts[2], 'Tools', 'XapSignTool', 'XapSignTool.exe');
104 if (fs.existsSync(xapSignTool)) {
105 results.windowsphone[ver].xapSignTool = xapSignTool;
106 }
107 }
108 }
109 });
110 }
111 next();
112 });
113 }, function () {
114 callback(null, results);
115 });
116 });
117};
118
119/**
120 * Detects Windows 10 SDK.
121 * @param {Object} [options] - An object containing various settings.
122 * @param {Boolean} [options.bypassCache=false] - When true, re-detects the Windows Phone SDKs.
123 * @param {String} [options.preferredWindowsPhoneSDK] - The preferred version of the Windows Phone SDK to use by default. Example "8.0".
124 * @param {String} [options.supportedWindowsPhoneSDKVersions] - A string with a version number or range to check if a Windows Phone SDK is supported.
125 * @param {Function} [callback(err, results)] - A function to call with the Windows Phone SDK information.
126 */
127function detectWin10(options, callback) {
128 var results = {
129 windowsphone: {},
130 issues: []
131 },
132 win10SearchPaths = [
133 'HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Microsoft SDKs\\Windows\\v10.0', // probably nothing here
134 'HKEY_LOCAL_MACHINE\\Software\\Wow6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0' // this is most likely where Windows SDK will be found
135 ];
136
137 async.each(win10SearchPaths, function (keyPath, next) {
138 appc.subprocess.run('reg', ['query', keyPath], function (code, out, err) {
139 if (!code) {
140 var version = '10.0';
141 // get only the values we are interested in
142 out.trim().split(/\r\n|\n/).forEach(function (line) {
143 var parts = line.trim().split(' ').map(function (p) { return p.trim(); });
144 if (parts.length == 3) {
145 if (parts[0] == 'InstallationFolder') {
146 results.windowsphone || (results.windowsphone = {});
147 results.windowsphone[version] = {
148 version: version,
149 registryKey: keyPath,
150 supported: !options.supportedWindowsPhoneSDKVersions || appc.version.satisfies(version, options.supportedWindowsPhoneSDKVersions, false), // no maybes
151 path: parts[2],
152 deployCmd: null,
153 xapSignTool: null,
154 selected: false,
155 sdks: []
156 };
157
158 var binDir = path.join(parts[2], 'bin'),
159 deployCmd = path.join(binDir, 'x86', 'WinAppDeployCmd.exe'),
160 signTool = path.join(binDir, 'x86', 'signtool.exe');
161 if (fs.existsSync(deployCmd)) {
162 results.windowsphone[version].deployCmd = deployCmd;
163 }
164 var dirs = fs.readdirSync(binDir).filter(dirname => /(\d+\.\d+\.\d+)\.\d+/.test(dirname));
165 for (var i = 0; i < dirs.length; i++) {
166 var sdk = dirs[i];
167 deployCmd = path.join(binDir, sdk, 'x86', 'WinAppDeployCmd.exe')
168 if (fs.existsSync(deployCmd)) {
169 results.windowsphone[version].deployCmd = deployCmd;
170 }
171 }
172 if (fs.existsSync(signTool)) {
173 results.windowsphone[version].xapSignTool = signTool;
174 }
175 }
176 }
177 });
178 }
179 next();
180 });
181 }, function () {
182 // fetch all Windows 10 SDK install information
183 var win10 = '10.0'
184 if (results.windowsphone[win10] && results.windowsphone[win10].path) {
185 var sdks_path = path.join(results.windowsphone[win10].path, 'Extension SDKs', 'WindowsMobile');
186 if (fs.existsSync(sdks_path)) {
187 results.windowsphone[win10].sdks = fs.readdirSync(sdks_path);
188 }
189 }
190 callback(null, results);
191 });
192};
193
194/**
195 * Detects Windows Phone SDKs.
196 *
197 * @param {Object} [options] - An object containing various settings.
198 * @param {Boolean} [options.bypassCache=false] - When true, re-detects the Windows Phone SDKs.
199 * @param {String} [options.preferredWindowsPhoneSDK] - The preferred version of the Windows Phone SDK to use by default. Example "8.0".
200 * @param {String} [options.supportedWindowsPhoneSDKVersions] - A string with a version number or range to check if a Windows Phone SDK is supported.
201 * @param {Function} [callback(err, results)] - A function to call with the Windows Phone SDK information.
202 *
203 * @emits module:windowsphone#detected
204 * @emits module:windowsphone#error
205 *
206 * @returns {EventEmitter}
207 */
208function detect(options, callback) {
209 return magik(options, callback, function (emitter, options, callback) {
210 if (detectCache && !options.bypassCache) {
211 emitter.emit('detected', detectCache);
212 return callback(null, detectCache);
213 }
214
215 var results = {
216 windowsphone: {},
217 issues: []
218 };
219
220 function finalize() {
221 detectCache = results;
222 emitter.emit('detected', results);
223 callback(null, results);
224 }
225
226 // Detect 8.0/8.1 and 10.0 in parallel
227 async.parallel([
228 function (next) {
229 detectLegacy(options, next);
230 },
231 function (next) {
232 detectWin10(options, next);
233 }
234 ], function (err, detectResults) {
235 // combine the results objects from 8.0/8.1 and 10.0!
236 mix(detectResults[0], results);
237 mix(detectResults[1], results);
238
239 // double check if we didn't find any Windows Phone SDKs, then we're done
240 if (Object.keys(results.windowsphone).every(function (v) { return !results.windowsphone[v].path; })) {
241 results.issues.push({
242 id: 'WINDOWS_PHONE_SDK_NOT_INSTALLED',
243 type: 'error',
244 message: __('Microsoft Windows Phone SDK not found.') + '\n' +
245 __('You will be unable to build Windows Phone apps.')
246 });
247 return finalize();
248 }
249
250 if (Object.keys(results.windowsphone).every(function (v) { return !results.windowsphone[v].deployCmd; })) {
251 results.issues.push({
252 id: 'WINDOWS_PHONE_SDK_MISSING_DEPLOY_CMD',
253 type: 'error',
254 message: __('Microsoft Windows Phone SDK is missing the deploy command.') + '\n' +
255 __('You will be unable to build Windows Phone apps.')
256 });
257 return finalize();
258 }
259
260 var preferred = options.preferredWindowsPhoneSDK;
261 if (!results.windowsphone[preferred] || !results.windowsphone[preferred].supported) {
262 preferred = Object.keys(results.windowsphone).filter(function (v) { return results.windowsphone[v].supported; }).sort().pop();
263 }
264 if (preferred) {
265 results.windowsphone[preferred].selected = true;
266 }
267
268 finalize();
269 }
270 );
271 });
272};