1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.getSharedAnalytics = exports.getWorkspaceAnalytics = exports.hasWorkspaceAnalyticsConfiguration = exports.getGlobalAnalytics = exports.hasGlobalAnalyticsConfiguration = exports.promptProjectAnalytics = exports.promptGlobalAnalytics = exports.setAnalyticsConfig = exports.UniversalAnalytics = exports.isPackageNameSafeForAnalytics = exports.analyticsPackageSafelist = exports.AnalyticsProperties = void 0;
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | const core_1 = require("@angular-devkit/core");
|
12 | const child_process = require("child_process");
|
13 | const debug = require("debug");
|
14 | const fs_1 = require("fs");
|
15 | const inquirer = require("inquirer");
|
16 | const os = require("os");
|
17 | const ua = require("universal-analytics");
|
18 | const uuid_1 = require("uuid");
|
19 | const color_1 = require("../utilities/color");
|
20 | const config_1 = require("../utilities/config");
|
21 | const tty_1 = require("../utilities/tty");
|
22 |
|
23 | const analyticsDebug = debug('ng:analytics');
|
24 | const analyticsLogDebug = debug('ng:analytics:log');
|
25 | const BYTES_PER_GIGABYTES = 1024 * 1024 * 1024;
|
26 | let _defaultAngularCliPropertyCache;
|
27 | exports.AnalyticsProperties = {
|
28 | AngularCliProd: 'UA-8594346-29',
|
29 | AngularCliStaging: 'UA-8594346-32',
|
30 | get AngularCliDefault() {
|
31 | if (_defaultAngularCliPropertyCache) {
|
32 | return _defaultAngularCliPropertyCache;
|
33 | }
|
34 | const v = require('../package.json').version;
|
35 |
|
36 | if (/^\d+\.\d+\.\d+$/.test(v) && v !== '0.0.0') {
|
37 | _defaultAngularCliPropertyCache = exports.AnalyticsProperties.AngularCliProd;
|
38 | }
|
39 | else {
|
40 | _defaultAngularCliPropertyCache = exports.AnalyticsProperties.AngularCliStaging;
|
41 | }
|
42 | return _defaultAngularCliPropertyCache;
|
43 | },
|
44 | };
|
45 |
|
46 |
|
47 |
|
48 | exports.analyticsPackageSafelist = [
|
49 | /^@angular\
|
50 | /^@angular-devkit\
|
51 | /^@ngtools\
|
52 | '@schematics/angular',
|
53 | '@schematics/schematics',
|
54 | '@schematics/update',
|
55 | ];
|
56 | function isPackageNameSafeForAnalytics(name) {
|
57 | return exports.analyticsPackageSafelist.some(pattern => {
|
58 | if (typeof pattern == 'string') {
|
59 | return pattern === name;
|
60 | }
|
61 | else {
|
62 | return pattern.test(name);
|
63 | }
|
64 | });
|
65 | }
|
66 | exports.isPackageNameSafeForAnalytics = isPackageNameSafeForAnalytics;
|
67 |
|
68 |
|
69 |
|
70 |
|
71 | function _getWindowsLanguageCode() {
|
72 | if (!os.platform().startsWith('win')) {
|
73 | return undefined;
|
74 | }
|
75 | try {
|
76 |
|
77 |
|
78 | return child_process
|
79 | .execSync('wmic.exe os get locale')
|
80 | .toString()
|
81 | .trim();
|
82 | }
|
83 | catch (_) { }
|
84 | return undefined;
|
85 | }
|
86 |
|
87 |
|
88 |
|
89 |
|
90 | function _getLanguage() {
|
91 |
|
92 | return (process.env.LANG ||
|
93 | process.env.LC_CTYPE ||
|
94 | process.env.LANGSPEC ||
|
95 | _getWindowsLanguageCode() ||
|
96 | '??');
|
97 | }
|
98 |
|
99 |
|
100 |
|
101 |
|
102 | function _getCpuCount() {
|
103 | const cpus = os.cpus();
|
104 |
|
105 | return cpus.length;
|
106 | }
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 | function _getCpuSpeed() {
|
113 | const cpus = os.cpus();
|
114 | return Math.floor(cpus[0].speed);
|
115 | }
|
116 |
|
117 |
|
118 |
|
119 |
|
120 | function _getRamSize() {
|
121 |
|
122 | return Math.round(os.totalmem() / BYTES_PER_GIGABYTES);
|
123 | }
|
124 |
|
125 |
|
126 |
|
127 |
|
128 | function _getNodeVersion() {
|
129 | const name = process.release.name || process.argv0;
|
130 | return name + ' ' + process.version;
|
131 | }
|
132 |
|
133 |
|
134 |
|
135 |
|
136 | function _getNumericNodeVersion() {
|
137 | const p = process.version;
|
138 | const m = p.match(/\d+\.\d+/);
|
139 | return (m && m[0] && parseFloat(m[0])) || 0;
|
140 | }
|
141 |
|
142 |
|
143 |
|
144 | const osVersionMap = {
|
145 | darwin: {
|
146 | '1.3.1': '10_0_4',
|
147 | '1.4.1': '10_1_0',
|
148 | '5.1': '10_1_1',
|
149 | '5.2': '10_1_5',
|
150 | '6.0.1': '10_2',
|
151 | '6.8': '10_2_8',
|
152 | '7.0': '10_3_0',
|
153 | '7.9': '10_3_9',
|
154 | '8.0': '10_4_0',
|
155 | '8.11': '10_4_11',
|
156 | '9.0': '10_5_0',
|
157 | '9.8': '10_5_8',
|
158 | '10.0': '10_6_0',
|
159 | '10.8': '10_6_8',
|
160 | },
|
161 | win32: {
|
162 | '6.3.9600': 'Windows 8.1',
|
163 | '6.2.9200': 'Windows 8',
|
164 | '6.1.7601': 'Windows 7 SP1',
|
165 | '6.1.7600': 'Windows 7',
|
166 | '6.0.6002': 'Windows Vista SP2',
|
167 | '6.0.6000': 'Windows Vista',
|
168 | '5.1.2600': 'Windows XP',
|
169 | },
|
170 | };
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 | function _buildUserAgentStringForOsx() {
|
177 | let v = osVersionMap.darwin[os.release()];
|
178 | if (!v) {
|
179 |
|
180 | const x = parseFloat(os.release());
|
181 | if (x > 10) {
|
182 | v = `10_` + (x - 4).toString().replace('.', '_');
|
183 | }
|
184 | }
|
185 | const cpuModel = os.cpus()[0].model.match(/^[a-z]+/i);
|
186 | const cpu = cpuModel ? cpuModel[0] : os.cpus()[0].model;
|
187 | return `(Macintosh; ${cpu} Mac OS X ${v || os.release()})`;
|
188 | }
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 | function _buildUserAgentStringForWindows() {
|
195 | return `(Windows NT ${os.release()})`;
|
196 | }
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 | function _buildUserAgentStringForLinux() {
|
203 | return `(X11; Linux i686; ${os.release()}; ${os.cpus()[0].model})`;
|
204 | }
|
205 |
|
206 |
|
207 |
|
208 |
|
209 | function _buildUserAgentString() {
|
210 | switch (os.platform()) {
|
211 | case 'darwin':
|
212 | return _buildUserAgentStringForOsx();
|
213 | case 'win32':
|
214 | return _buildUserAgentStringForWindows();
|
215 | case 'linux':
|
216 | return _buildUserAgentStringForLinux();
|
217 | default:
|
218 | return os.platform() + ' ' + os.release();
|
219 | }
|
220 | }
|
221 |
|
222 |
|
223 |
|
224 | class UniversalAnalytics {
|
225 | |
226 |
|
227 |
|
228 |
|
229 | constructor(trackingId, uid) {
|
230 | this._dirty = false;
|
231 | this._metrics = [];
|
232 | this._dimensions = [];
|
233 | this._ua = ua(trackingId, uid, {
|
234 | enableBatching: true,
|
235 | batchSize: 5,
|
236 | });
|
237 |
|
238 | this._ua.set('ds', 'cli');
|
239 | this._ua.set('ua', _buildUserAgentString());
|
240 | this._ua.set('ul', _getLanguage());
|
241 |
|
242 | this._ua.set('an', require('../package.json').name);
|
243 | this._ua.set('av', require('../package.json').version);
|
244 |
|
245 |
|
246 | this._ua.set('aid', _getNodeVersion());
|
247 |
|
248 | this._dimensions[core_1.analytics.NgCliAnalyticsDimensions.CpuCount] = _getCpuCount();
|
249 | this._dimensions[core_1.analytics.NgCliAnalyticsDimensions.CpuSpeed] = _getCpuSpeed();
|
250 | this._dimensions[core_1.analytics.NgCliAnalyticsDimensions.RamInGigabytes] = _getRamSize();
|
251 | this._dimensions[core_1.analytics.NgCliAnalyticsDimensions.NodeVersion] = _getNumericNodeVersion();
|
252 | }
|
253 | |
254 |
|
255 |
|
256 |
|
257 | _customVariables(options) {
|
258 | const additionals = {};
|
259 | this._dimensions.forEach((v, i) => (additionals['cd' + i] = v));
|
260 | (options.dimensions || []).forEach((v, i) => (additionals['cd' + i] = v));
|
261 | this._metrics.forEach((v, i) => (additionals['cm' + i] = v));
|
262 | (options.metrics || []).forEach((v, i) => (additionals['cm' + i] = v));
|
263 | return additionals;
|
264 | }
|
265 | event(ec, ea, options = {}) {
|
266 | const vars = this._customVariables(options);
|
267 | analyticsLogDebug('event ec=%j, ea=%j, %j', ec, ea, vars);
|
268 | const { label: el, value: ev } = options;
|
269 | this._dirty = true;
|
270 | this._ua.event({ ec, ea, el, ev, ...vars });
|
271 | }
|
272 | screenview(cd, an, options = {}) {
|
273 | const vars = this._customVariables(options);
|
274 | analyticsLogDebug('screenview cd=%j, an=%j, %j', cd, an, vars);
|
275 | const { appVersion: av, appId: aid, appInstallerId: aiid } = options;
|
276 | this._dirty = true;
|
277 | this._ua.screenview({ cd, an, av, aid, aiid, ...vars });
|
278 | }
|
279 | pageview(dp, options = {}) {
|
280 | const vars = this._customVariables(options);
|
281 | analyticsLogDebug('pageview dp=%j, %j', dp, vars);
|
282 | const { hostname: dh, title: dt } = options;
|
283 | this._dirty = true;
|
284 | this._ua.pageview({ dp, dh, dt, ...vars });
|
285 | }
|
286 | timing(utc, utv, utt, options = {}) {
|
287 | const vars = this._customVariables(options);
|
288 | analyticsLogDebug('timing utc=%j, utv=%j, utl=%j, %j', utc, utv, utt, vars);
|
289 | const { label: utl } = options;
|
290 | this._dirty = true;
|
291 | this._ua.timing({ utc, utv, utt, utl, ...vars });
|
292 | }
|
293 | flush() {
|
294 | if (!this._dirty) {
|
295 | return Promise.resolve();
|
296 | }
|
297 | this._dirty = false;
|
298 | return new Promise(resolve => this._ua.send(resolve));
|
299 | }
|
300 | }
|
301 | exports.UniversalAnalytics = UniversalAnalytics;
|
302 |
|
303 |
|
304 |
|
305 |
|
306 |
|
307 | function setAnalyticsConfig(level, value) {
|
308 | analyticsDebug('setting %s level analytics to: %s', level, value);
|
309 | const [config, configPath] = config_1.getWorkspaceRaw(level);
|
310 | if (!config || !configPath) {
|
311 | throw new Error(`Could not find ${level} workspace.`);
|
312 | }
|
313 | const configValue = config.value;
|
314 | const cli = configValue['cli'] || (configValue['cli'] = {});
|
315 | if (!core_1.json.isJsonObject(cli)) {
|
316 | throw new Error(`Invalid config found at ${configPath}. CLI should be an object.`);
|
317 | }
|
318 | if (value === true) {
|
319 | value = uuid_1.v4();
|
320 | }
|
321 | cli['analytics'] = value;
|
322 | const output = JSON.stringify(configValue, null, 2);
|
323 | fs_1.writeFileSync(configPath, output);
|
324 | analyticsDebug('done');
|
325 | }
|
326 | exports.setAnalyticsConfig = setAnalyticsConfig;
|
327 |
|
328 |
|
329 |
|
330 |
|
331 |
|
332 | async function promptGlobalAnalytics(force = false) {
|
333 | analyticsDebug('prompting global analytics.');
|
334 | if (force || tty_1.isTTY()) {
|
335 | const answers = await inquirer.prompt([
|
336 | {
|
337 | type: 'confirm',
|
338 | name: 'analytics',
|
339 | message: core_1.tags.stripIndents `
|
340 | Would you like to share anonymous usage data with the Angular Team at Google under
|
341 | Google’s Privacy Policy at https://policies.google.com/privacy? For more details and
|
342 | how to change this setting, see http://angular.io/analytics.
|
343 | `,
|
344 | default: false,
|
345 | },
|
346 | ]);
|
347 | setAnalyticsConfig('global', answers.analytics);
|
348 | if (answers.analytics) {
|
349 | console.log('');
|
350 | console.log(core_1.tags.stripIndent `
|
351 | Thank you for sharing anonymous usage data. If you change your mind, the following
|
352 | command will disable this feature entirely:
|
353 |
|
354 | ${color_1.colors.yellow('ng analytics off')}
|
355 | `);
|
356 | console.log('');
|
357 |
|
358 | const ua = new UniversalAnalytics(exports.AnalyticsProperties.AngularCliDefault, 'optin');
|
359 | ua.pageview('/telemetry/optin');
|
360 | await ua.flush();
|
361 | }
|
362 | else {
|
363 |
|
364 | const ua = new UniversalAnalytics(exports.AnalyticsProperties.AngularCliDefault, 'optout');
|
365 | ua.pageview('/telemetry/optout');
|
366 | await ua.flush();
|
367 | }
|
368 | return true;
|
369 | }
|
370 | else {
|
371 | analyticsDebug('Either STDOUT or STDIN are not TTY and we skipped the prompt.');
|
372 | }
|
373 | return false;
|
374 | }
|
375 | exports.promptGlobalAnalytics = promptGlobalAnalytics;
|
376 |
|
377 |
|
378 |
|
379 |
|
380 |
|
381 |
|
382 | async function promptProjectAnalytics(force = false) {
|
383 | analyticsDebug('prompting user');
|
384 | const [config, configPath] = config_1.getWorkspaceRaw('local');
|
385 | if (!config || !configPath) {
|
386 | throw new Error(`Could not find a local workspace. Are you in a project?`);
|
387 | }
|
388 | if (force || tty_1.isTTY()) {
|
389 | const answers = await inquirer.prompt([
|
390 | {
|
391 | type: 'confirm',
|
392 | name: 'analytics',
|
393 | message: core_1.tags.stripIndents `
|
394 | Would you like to share anonymous usage data about this project with the Angular Team at
|
395 | Google under Google’s Privacy Policy at https://policies.google.com/privacy? For more
|
396 | details and how to change this setting, see http://angular.io/analytics.
|
397 |
|
398 | `,
|
399 | default: false,
|
400 | },
|
401 | ]);
|
402 | setAnalyticsConfig('local', answers.analytics);
|
403 | if (answers.analytics) {
|
404 | console.log('');
|
405 | console.log(core_1.tags.stripIndent `
|
406 | Thank you for sharing anonymous usage data. Would you change your mind, the following
|
407 | command will disable this feature entirely:
|
408 |
|
409 | ${color_1.colors.yellow('ng analytics project off')}
|
410 | `);
|
411 | console.log('');
|
412 |
|
413 | const ua = new UniversalAnalytics(exports.AnalyticsProperties.AngularCliDefault, 'optin');
|
414 | ua.pageview('/telemetry/project/optin');
|
415 | await ua.flush();
|
416 | }
|
417 | else {
|
418 |
|
419 | const ua = new UniversalAnalytics(exports.AnalyticsProperties.AngularCliDefault, 'optout');
|
420 | ua.pageview('/telemetry/project/optout');
|
421 | await ua.flush();
|
422 | }
|
423 | return true;
|
424 | }
|
425 | return false;
|
426 | }
|
427 | exports.promptProjectAnalytics = promptProjectAnalytics;
|
428 | async function hasGlobalAnalyticsConfiguration() {
|
429 | try {
|
430 | const globalWorkspace = await config_1.getWorkspace('global');
|
431 | const analyticsConfig = globalWorkspace && globalWorkspace.getCli() && globalWorkspace.getCli()['analytics'];
|
432 | if (analyticsConfig !== null && analyticsConfig !== undefined) {
|
433 | return true;
|
434 | }
|
435 | }
|
436 | catch (_a) { }
|
437 | return false;
|
438 | }
|
439 | exports.hasGlobalAnalyticsConfiguration = hasGlobalAnalyticsConfiguration;
|
440 |
|
441 |
|
442 |
|
443 |
|
444 |
|
445 |
|
446 | async function getGlobalAnalytics() {
|
447 | analyticsDebug('getGlobalAnalytics');
|
448 | const propertyId = exports.AnalyticsProperties.AngularCliDefault;
|
449 | if ('NG_CLI_ANALYTICS' in process.env) {
|
450 | if (process.env['NG_CLI_ANALYTICS'] == 'false' || process.env['NG_CLI_ANALYTICS'] == '') {
|
451 | analyticsDebug('NG_CLI_ANALYTICS is false');
|
452 | return undefined;
|
453 | }
|
454 | if (process.env['NG_CLI_ANALYTICS'] === 'ci') {
|
455 | analyticsDebug('Running in CI mode');
|
456 | return new UniversalAnalytics(propertyId, 'ci');
|
457 | }
|
458 | }
|
459 |
|
460 | try {
|
461 | const globalWorkspace = await config_1.getWorkspace('global');
|
462 | const analyticsConfig = globalWorkspace && globalWorkspace.getCli() && globalWorkspace.getCli()['analytics'];
|
463 | analyticsDebug('Client Analytics config found: %j', analyticsConfig);
|
464 | if (analyticsConfig === false) {
|
465 | analyticsDebug('Analytics disabled. Ignoring all analytics.');
|
466 | return undefined;
|
467 | }
|
468 | else if (analyticsConfig === undefined || analyticsConfig === null) {
|
469 | analyticsDebug('Analytics settings not found. Ignoring all analytics.');
|
470 |
|
471 |
|
472 |
|
473 | return undefined;
|
474 | }
|
475 | else {
|
476 | let uid = undefined;
|
477 | if (typeof analyticsConfig == 'string') {
|
478 | uid = analyticsConfig;
|
479 | }
|
480 | else if (typeof analyticsConfig == 'object' && typeof analyticsConfig['uid'] == 'string') {
|
481 | uid = analyticsConfig['uid'];
|
482 | }
|
483 | analyticsDebug('client id: %j', uid);
|
484 | if (uid == undefined) {
|
485 | return undefined;
|
486 | }
|
487 | return new UniversalAnalytics(propertyId, uid);
|
488 | }
|
489 | }
|
490 | catch (err) {
|
491 | analyticsDebug('Error happened during reading of analytics config: %s', err.message);
|
492 | return undefined;
|
493 | }
|
494 | }
|
495 | exports.getGlobalAnalytics = getGlobalAnalytics;
|
496 | async function hasWorkspaceAnalyticsConfiguration() {
|
497 | try {
|
498 | const globalWorkspace = await config_1.getWorkspace('local');
|
499 | const analyticsConfig = globalWorkspace
|
500 | && globalWorkspace.getCli()
|
501 | && globalWorkspace.getCli()['analytics'];
|
502 | if (analyticsConfig !== undefined) {
|
503 | return true;
|
504 | }
|
505 | }
|
506 | catch (_a) { }
|
507 | return false;
|
508 | }
|
509 | exports.hasWorkspaceAnalyticsConfiguration = hasWorkspaceAnalyticsConfiguration;
|
510 |
|
511 |
|
512 |
|
513 |
|
514 |
|
515 |
|
516 | async function getWorkspaceAnalytics() {
|
517 | analyticsDebug('getWorkspaceAnalytics');
|
518 | try {
|
519 | const globalWorkspace = await config_1.getWorkspace('local');
|
520 | const analyticsConfig = globalWorkspace === null || globalWorkspace === void 0 ? void 0 : globalWorkspace.getCli()['analytics'];
|
521 | analyticsDebug('Workspace Analytics config found: %j', analyticsConfig);
|
522 | if (analyticsConfig === false) {
|
523 | analyticsDebug('Analytics disabled. Ignoring all analytics.');
|
524 | return undefined;
|
525 | }
|
526 | else if (analyticsConfig === undefined || analyticsConfig === null) {
|
527 | analyticsDebug('Analytics settings not found. Ignoring all analytics.');
|
528 | return undefined;
|
529 | }
|
530 | else {
|
531 | let uid = undefined;
|
532 | if (typeof analyticsConfig == 'string') {
|
533 | uid = analyticsConfig;
|
534 | }
|
535 | else if (typeof analyticsConfig == 'object' && typeof analyticsConfig['uid'] == 'string') {
|
536 | uid = analyticsConfig['uid'];
|
537 | }
|
538 | analyticsDebug('client id: %j', uid);
|
539 | if (uid == undefined) {
|
540 | return undefined;
|
541 | }
|
542 | return new UniversalAnalytics(exports.AnalyticsProperties.AngularCliDefault, uid);
|
543 | }
|
544 | }
|
545 | catch (err) {
|
546 | analyticsDebug('Error happened during reading of analytics config: %s', err.message);
|
547 | return undefined;
|
548 | }
|
549 | }
|
550 | exports.getWorkspaceAnalytics = getWorkspaceAnalytics;
|
551 |
|
552 |
|
553 |
|
554 |
|
555 | async function getSharedAnalytics() {
|
556 | analyticsDebug('getSharedAnalytics');
|
557 | const envVarName = 'NG_CLI_ANALYTICS_SHARE';
|
558 | if (envVarName in process.env) {
|
559 | if (process.env[envVarName] == 'false' || process.env[envVarName] == '') {
|
560 | analyticsDebug('NG_CLI_ANALYTICS is false');
|
561 | return undefined;
|
562 | }
|
563 | }
|
564 |
|
565 | try {
|
566 | const globalWorkspace = await config_1.getWorkspace('global');
|
567 | const analyticsConfig = globalWorkspace === null || globalWorkspace === void 0 ? void 0 : globalWorkspace.getCli()['analyticsSharing'];
|
568 | if (!analyticsConfig || !analyticsConfig.tracking || !analyticsConfig.uuid) {
|
569 | return undefined;
|
570 | }
|
571 | else {
|
572 | analyticsDebug('Analytics sharing info: %j', analyticsConfig);
|
573 | return new UniversalAnalytics(analyticsConfig.tracking, analyticsConfig.uuid);
|
574 | }
|
575 | }
|
576 | catch (err) {
|
577 | analyticsDebug('Error happened during reading of analytics sharing config: %s', err.message);
|
578 | return undefined;
|
579 | }
|
580 | }
|
581 | exports.getSharedAnalytics = getSharedAnalytics;
|