1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | var Q = require('q');
|
21 | var os = require('os');
|
22 | var path = require('path');
|
23 | var shell = require('shelljs');
|
24 | var spawn = require('cordova-common').superspawn.spawn;
|
25 | var CordovaError = require('cordova-common').CordovaError;
|
26 |
|
27 | var ConfigParser, MSBuildTools, Version;
|
28 | try {
|
29 | ConfigParser = require('../../template/cordova/lib/ConfigParser');
|
30 | MSBuildTools = require('../../template/cordova/lib/MSBuildTools');
|
31 | Version = require('../../template/cordova/lib/Version');
|
32 | } catch (ex) {
|
33 |
|
34 |
|
35 | ConfigParser = require('./ConfigParser');
|
36 | MSBuildTools = require('./MSBuildTools');
|
37 | Version = require('./Version');
|
38 | }
|
39 |
|
40 |
|
41 |
|
42 | var VS2013_UPDATE2_RC = new Version(12, 0, 30324);
|
43 | var REQUIRED_VERSIONS = {
|
44 | '8.1': {
|
45 | os: '6.3',
|
46 | msbuild: '12.0',
|
47 | visualstudio: '12.0',
|
48 | windowssdk: '8.1',
|
49 | phonesdk: '8.1'
|
50 | },
|
51 | '10.0': {
|
52 |
|
53 |
|
54 |
|
55 | os: '6.3',
|
56 | msbuild: '14.0',
|
57 | visualstudio: '14.0',
|
58 | windowssdk: '10.0',
|
59 | phonesdk: '10.0'
|
60 | }
|
61 | };
|
62 |
|
63 | function getMinimalRequiredVersionFor (requirement, windowsTargetVersion, windowsPhoneTargetVersion) {
|
64 | if (windowsTargetVersion === '8' || windowsTargetVersion === '8.0') {
|
65 | throw new CordovaError('windows8 platform is deprecated. To use windows-target-version=8.0 you may downgrade to cordova-windows@4.');
|
66 | }
|
67 |
|
68 | if (windowsPhoneTargetVersion === '8' || windowsPhoneTargetVersion === '8.0') {
|
69 | throw new CordovaError('8.0 is not a valid version for windows-phone-target-version (use the wp8 Cordova platform instead)');
|
70 | }
|
71 | var windowsReqVersion = Version.tryParse(REQUIRED_VERSIONS[windowsTargetVersion][requirement]);
|
72 | var phoneReqVersion = Version.tryParse(REQUIRED_VERSIONS[windowsPhoneTargetVersion][requirement]);
|
73 |
|
74 |
|
75 |
|
76 | if (requirement === 'windowssdk') return windowsReqVersion;
|
77 | if (requirement === 'phonesdk') return phoneReqVersion;
|
78 |
|
79 |
|
80 | if (windowsReqVersion && phoneReqVersion) {
|
81 | return windowsReqVersion.gt(phoneReqVersion)
|
82 | ? windowsReqVersion
|
83 | : phoneReqVersion;
|
84 | }
|
85 |
|
86 |
|
87 | return windowsReqVersion || phoneReqVersion;
|
88 | }
|
89 |
|
90 | function getHighestAppropriateVersion (versions, requiredVersion) {
|
91 | return versions.map(function (version) {
|
92 | return Version.tryParse(version);
|
93 | })
|
94 | .sort(Version.comparer)
|
95 | .filter(function (toolVersion) {
|
96 | return toolVersion.gte(requiredVersion);
|
97 | }).reverse()[0];
|
98 | }
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 | function getWindowsVersion () {
|
107 | return spawn('ver').then(function (output) {
|
108 | var match = /\[Version (.*)\]\s*$/.exec(output);
|
109 | return Version.fromString(match[1]);
|
110 | }).fail(function () {
|
111 | return Version.fromString(os.release());
|
112 | });
|
113 | }
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 | function getInstalledVSVersions () {
|
122 |
|
123 |
|
124 | return spawn('reg', ['query', 'HKLM\\SOFTWARE\\Microsoft\\DevDiv\\vs\\Servicing', '/s', '/v', 'Install', '/f', '1', '/d', '/e', '/reg:32'])
|
125 | .fail(function () { return ''; })
|
126 | .then(function (output) {
|
127 | return output.split('\n')
|
128 | .reduce(function (installedVersions, line) {
|
129 | var match = /(\d+\.\d+)\\(ultimate|professional|premium|community)/.exec(line);
|
130 | if (match && match[1] && installedVersions.indexOf(match[1]) === -1) { installedVersions.push(match[1]); }
|
131 | return installedVersions;
|
132 | }, []);
|
133 | }).then(function (installedVersions) {
|
134 |
|
135 | if (installedVersions.indexOf('12.0') === -1) return installedVersions;
|
136 |
|
137 |
|
138 | return spawn('reg', ['query', 'HKLM\\SOFTWARE\\Microsoft\\Updates\\Microsoft Visual Studio 2013\\vsupdate_KB2829760', '/v', 'PackageVersion', '/reg:32'])
|
139 | .then(function (output) {
|
140 | var updateVer = Version.fromString(/PackageVersion\s+REG_SZ\s+(.*)/i.exec(output)[1]);
|
141 |
|
142 | if (VS2013_UPDATE2_RC.gte(updateVer)) return Q.reject();
|
143 | return installedVersions;
|
144 | }).fail(function () {
|
145 |
|
146 |
|
147 | installedVersions.splice(installedVersions.indexOf('12.0'), 1);
|
148 | return installedVersions;
|
149 | });
|
150 | })
|
151 | .then(function (installedVersions) {
|
152 | var willowVersions = MSBuildTools.getWillowInstallations().map(function (installation) {
|
153 | return installation.version;
|
154 | });
|
155 | return installedVersions.concat(willowVersions);
|
156 | });
|
157 | }
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 | function getInstalledWindowsSdks () {
|
165 | var installedSdks = [];
|
166 | return spawn('reg', ['query', 'HKLM\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows', '/s', '/v', 'InstallationFolder', '/reg:32'])
|
167 | .fail(function () { return ''; })
|
168 | .then(function (output) {
|
169 | var re = /\\Microsoft SDKs\\Windows\\v(\d+\.\d+)\s*InstallationFolder\s+REG_SZ\s+(.*)/gim;
|
170 | var match;
|
171 | while ((match = re.exec(output))) {
|
172 | var sdkPath = match[2];
|
173 |
|
174 | if (shell.test('-e', path.join(sdkPath, 'SDKManifest.xml'))) {
|
175 | installedSdks.push(Version.tryParse(match[1]));
|
176 | }
|
177 | }
|
178 | }).thenResolve(installedSdks);
|
179 | }
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 | function getInstalledPhoneSdks () {
|
189 | var installedSdks = [];
|
190 | return spawn('reg', ['query', 'HKLM\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows Phone\\v8.1', '/v', 'InstallationFolder', '/reg:32'])
|
191 | .fail(function () { return ''; })
|
192 | .then(function (output) {
|
193 | var match = /\\Microsoft SDKs\\Windows Phone\\v(\d+\.\d+)\s*InstallationFolder\s+REG_SZ\s+(.*)/gim.exec(output);
|
194 | if (match && shell.test('-e', path.join(match[2], 'SDKManifest.xml'))) {
|
195 | installedSdks.push(Version.tryParse(match[1]));
|
196 | }
|
197 | }).then(function () {
|
198 | return spawn('reg', ['query', 'HKLM\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v10.0', '/v', 'InstallationFolder', '/reg:32']);
|
199 | }).fail(function () {
|
200 | return '';
|
201 | }).then(function (output) {
|
202 | var match = /\\Microsoft SDKs\\Windows\\v(\d+\.\d+)\s*InstallationFolder\s+REG_SZ\s+(.*)/gim.exec(output);
|
203 | if (match && shell.test('-e', path.join(match[2], 'SDKManifest.xml'))) {
|
204 | installedSdks.push(Version.tryParse(match[1]));
|
205 | }
|
206 | }).thenResolve(installedSdks);
|
207 | }
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 | function shortenVersion (version) {
|
218 | return /^(\d+(?:\.\d+)?)/.exec(version.toString())[1];
|
219 | }
|
220 |
|
221 | function mapWindowsVersionToName (version) {
|
222 | var map = {
|
223 | '6.2': 'Windows 8',
|
224 | '6.3': 'Windows 8.1',
|
225 | '10.0': 'Windows 10'
|
226 | };
|
227 | var majorMinor = shortenVersion(version);
|
228 | return map[majorMinor];
|
229 | }
|
230 |
|
231 | function mapVSVersionToName (version) {
|
232 | var map = {
|
233 | '11.0': '2012 Express for Windows',
|
234 | '12.0': '2013 Express for Windows Update2',
|
235 | '14.0': '2015 Community'
|
236 | };
|
237 | var majorMinor = shortenVersion(version);
|
238 | return map[majorMinor];
|
239 | }
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 | var checkOS = function (windowsTargetVersion, windowsPhoneTargetVersion) {
|
246 | if (process.platform !== 'win32') {
|
247 |
|
248 | return Q.reject('Cordova tooling for Windows requires Windows OS to build project');
|
249 | }
|
250 |
|
251 | return getWindowsVersion().then(function (actualVersion) {
|
252 | var requiredOsVersion = getMinimalRequiredVersionFor('os', windowsTargetVersion, windowsPhoneTargetVersion);
|
253 | if ((actualVersion.gte(requiredOsVersion)) ||
|
254 |
|
255 | (actualVersion.major === 6 && actualVersion.minor === 1 && getConfig().getWindowsTargetVersion() === '10.0')) {
|
256 | return mapWindowsVersionToName(actualVersion);
|
257 | }
|
258 |
|
259 | return Q.reject('Current Windows version doesn\'t support building this project. ' +
|
260 | 'Consider upgrading your OS to ' + mapWindowsVersionToName(requiredOsVersion));
|
261 | });
|
262 | };
|
263 |
|
264 |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 | var checkMSBuild = function (windowsTargetVersion, windowsPhoneTargetVersion) {
|
270 | return MSBuildTools.findAllAvailableVersions()
|
271 | .then(function (msbuildToolsVersions) {
|
272 |
|
273 | var msbuildRequiredVersion = getMinimalRequiredVersionFor('msbuild', windowsTargetVersion, windowsPhoneTargetVersion);
|
274 |
|
275 | msbuildToolsVersions = msbuildToolsVersions.map(function (msbuildToolsVersion) {
|
276 | return msbuildToolsVersion.version;
|
277 | });
|
278 |
|
279 |
|
280 | var appropriateVersion = getHighestAppropriateVersion(msbuildToolsVersions, msbuildRequiredVersion);
|
281 |
|
282 | return appropriateVersion
|
283 | ? shortenVersion(appropriateVersion)
|
284 | : Q.reject('MSBuild tools v.' + shortenVersion(msbuildRequiredVersion) + ' not found. ' +
|
285 | 'Please install Visual Studio ' + mapVSVersionToName(getMinimalRequiredVersionFor('visualstudio', windowsTargetVersion, windowsPhoneTargetVersion)) +
|
286 | ' or higher from https://www.visualstudio.com/downloads/download-visual-studio-vs');
|
287 | });
|
288 | };
|
289 |
|
290 | var checkVS = function (windowsTargetVersion, windowsPhoneTargetVersion) {
|
291 | var vsRequiredVersion = getMinimalRequiredVersionFor('visualstudio', windowsTargetVersion, windowsPhoneTargetVersion);
|
292 |
|
293 | if (process.env.VSINSTALLDIR) {
|
294 | return Q('(user-specified via VSINSTALLDIR)');
|
295 | }
|
296 | return getInstalledVSVersions()
|
297 | .then(function (installedVersions) {
|
298 | var appropriateVersion = getHighestAppropriateVersion(installedVersions, vsRequiredVersion);
|
299 | return appropriateVersion
|
300 | ? shortenVersion(appropriateVersion)
|
301 | : Q.reject('Required version of Visual Studio not found. Please install Visual Studio ' +
|
302 | mapVSVersionToName(vsRequiredVersion) +
|
303 | ' or higher from https://www.visualstudio.com/downloads/download-visual-studio-vs');
|
304 | });
|
305 | };
|
306 |
|
307 | var checkWinSdk = function (windowsTargetVersion, windowsPhoneTargetVersion) {
|
308 | return getInstalledWindowsSdks()
|
309 | .then(function (installedSdks) {
|
310 | var requiredVersion = getMinimalRequiredVersionFor('windowssdk', windowsTargetVersion, windowsPhoneTargetVersion);
|
311 | var hasSdkInstalled = installedSdks.some(function (installedSdk) {
|
312 | return installedSdk.eq(requiredVersion);
|
313 | });
|
314 | if (!hasSdkInstalled) {
|
315 | return Q.reject('Windows SDK not found. Ensure that you have installed ' +
|
316 | 'Windows ' + shortenVersion(requiredVersion) + ' SDK along with Visual Studio or install ' +
|
317 | 'Windows ' + shortenVersion(requiredVersion) + ' SDK separately from ' +
|
318 | 'https://dev.windows.com/en-us/downloads');
|
319 | }
|
320 |
|
321 | return shortenVersion(requiredVersion);
|
322 | });
|
323 | };
|
324 |
|
325 | var checkPhoneSdk = function (windowsTargetVersion, windowsPhoneTargetVersion) {
|
326 | var requiredVersion = getMinimalRequiredVersionFor('phonesdk', windowsTargetVersion, windowsPhoneTargetVersion);
|
327 | return getInstalledPhoneSdks()
|
328 | .then(function (installedSdks) {
|
329 | var hasSdkInstalled = installedSdks.some(function (installedSdk) {
|
330 | return installedSdk.eq(requiredVersion);
|
331 | });
|
332 |
|
333 | return hasSdkInstalled
|
334 | ? shortenVersion(requiredVersion)
|
335 | : Q.reject();
|
336 | })
|
337 | .fail(function () {
|
338 | return Q.reject('Windows Phone SDK not found. Ensure that you have installed ' +
|
339 | 'Windows Phone ' + shortenVersion(requiredVersion) + ' SDK along with Visual Studio or install ' +
|
340 | 'Windows Phone ' + shortenVersion(requiredVersion) + ' SDK separately from ' +
|
341 | 'https://dev.windows.com/develop/download-phone-sdk');
|
342 | });
|
343 | };
|
344 |
|
345 | module.exports.run = function () {
|
346 | return checkOS('10.0', '10.0').then(function () {
|
347 | return MSBuildTools.findAvailableVersion();
|
348 | });
|
349 | };
|
350 |
|
351 |
|
352 |
|
353 |
|
354 | module.exports.isWinSDKPresent = function (target_platform) {
|
355 | return checkWinSdk(target_platform, '8.1');
|
356 | };
|
357 |
|
358 |
|
359 | module.exports.isPhoneSDKPresent = function () {
|
360 | return checkPhoneSdk('8.1', '8.1');
|
361 | };
|
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 |
|
368 |
|
369 |
|
370 | var Requirement = function (id, name, isFatal) {
|
371 | this.id = id;
|
372 | this.name = name;
|
373 | this.installed = false;
|
374 | this.metadata = {};
|
375 | this.isFatal = isFatal || false;
|
376 | };
|
377 |
|
378 | var requirements = [
|
379 | new Requirement('os', 'Windows OS', true),
|
380 | new Requirement('msbuild', 'MSBuild Tools'),
|
381 | new Requirement('visualstudio', 'Visual Studio'),
|
382 | new Requirement('windowssdk', 'Windows SDK'),
|
383 | new Requirement('phonesdk', 'Windows Phone SDK')
|
384 | ];
|
385 |
|
386 |
|
387 | var checkFns = [checkOS, checkMSBuild, checkVS, checkWinSdk, checkPhoneSdk];
|
388 |
|
389 | var config = null;
|
390 | function getConfig () {
|
391 | try {
|
392 | config = config || new ConfigParser(path.join(__dirname, '../../config.xml'));
|
393 | return Q(config);
|
394 | } catch (e) {
|
395 |
|
396 | try {
|
397 | config = config || new ConfigParser(path.join(__dirname, '../../template/config.xml'));
|
398 | return Q(config);
|
399 | } catch (e) {
|
400 |
|
401 | return Q.reject(new CordovaError('Can\'t check requirements for Windows platform.' +
|
402 | 'The config.xml file is either missing or malformed.'));
|
403 | }
|
404 | }
|
405 | }
|
406 |
|
407 |
|
408 |
|
409 |
|
410 |
|
411 |
|
412 | module.exports.check_all = function () {
|
413 | var result = [];
|
414 | var fatalIsHit = false;
|
415 |
|
416 |
|
417 | return checkFns.reduce(function (promise, checkFn, idx) {
|
418 | return promise.then(function () {
|
419 |
|
420 |
|
421 | if (fatalIsHit) return Q();
|
422 | var requirement = requirements[idx];
|
423 | return getConfig()
|
424 | .then(function (config) {
|
425 | return checkFn(config.getWindowsTargetVersion(), config.getWindowsPhoneTargetVersion())
|
426 | .then(function (version) {
|
427 | requirement.installed = true;
|
428 | requirement.metadata.version = version;
|
429 | result.push(requirement);
|
430 | }).catch(function (err) {
|
431 | if (requirement.isFatal) fatalIsHit = true;
|
432 | requirement.metadata.reason = err;
|
433 | result.push(requirement);
|
434 | });
|
435 | });
|
436 | });
|
437 | }, Q())
|
438 | .then(function () {
|
439 |
|
440 | return result;
|
441 | });
|
442 | };
|
443 |
|
444 | module.exports.help = function () {
|
445 | console.log('Usage: check_reqs or node check_reqs');
|
446 | };
|