UNPKG

15.8 kBJavaScriptView Raw
1'use strict';
2// @ts-check
3// ==================================================================================
4// utils.js
5// ----------------------------------------------------------------------------------
6// Description: System Information - library
7// for Node.js
8// Copyright: (c) 2014 - 2020
9// Author: Sebastian Hildebrandt
10// ----------------------------------------------------------------------------------
11// License: MIT
12// ==================================================================================
13// 0. helper functions
14// ----------------------------------------------------------------------------------
15
16const os = require('os');
17const fs = require('fs');
18const spawn = require('child_process').spawn;
19const exec = require('child_process').exec;
20const execSync = require('child_process').execSync;
21const util = require('util');
22
23let _platform = process.platform;
24const _linux = (_platform === 'linux');
25const _darwin = (_platform === 'darwin');
26const _windows = (_platform === 'win32');
27const _freebsd = (_platform === 'freebsd');
28const _openbsd = (_platform === 'openbsd');
29const _netbsd = (_platform === 'netbsd');
30// const _sunos = (_platform === 'sunos');
31
32let _cores = 0;
33let wmicPath = '';
34let codepage = '';
35
36const execOptsWin = {
37 windowsHide: true,
38 maxBuffer: 1024 * 20000,
39 encoding: 'UTF-8',
40 env: util._extend({}, process.env, { LANG: 'en_US.UTF-8' })
41};
42
43function toInt(value) {
44 let result = parseInt(value, 10);
45 if (isNaN(result)) {
46 result = 0;
47 }
48 return result;
49}
50
51function isFunction(functionToCheck) {
52 let getType = {};
53 return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
54}
55
56function unique(obj) {
57 let uniques = [];
58 let stringify = {};
59 for (let i = 0; i < obj.length; i++) {
60 let keys = Object.keys(obj[i]);
61 keys.sort(function (a, b) { return a - b; });
62 let str = '';
63 for (let j = 0; j < keys.length; j++) {
64 str += JSON.stringify(keys[j]);
65 str += JSON.stringify(obj[i][keys[j]]);
66 }
67 if (!{}.hasOwnProperty.call(stringify, str)) {
68 uniques.push(obj[i]);
69 stringify[str] = true;
70 }
71 }
72 return uniques;
73}
74
75function sortByKey(array, keys) {
76 return array.sort(function (a, b) {
77 let x = '';
78 let y = '';
79 keys.forEach(function (key) {
80 x = x + a[key]; y = y + b[key];
81 });
82 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
83 });
84}
85
86function cores() {
87 if (_cores === 0) {
88 _cores = os.cpus().length;
89 }
90 return _cores;
91}
92
93function getValue(lines, property, separator, trimmed) {
94 separator = separator || ':';
95 property = property.toLowerCase();
96 trimmed = trimmed || false;
97 for (let i = 0; i < lines.length; i++) {
98 let line = lines[i].toLowerCase().replace(/\t/g, '');
99 if (trimmed) {
100 line = line.trim();
101 }
102 if (line.startsWith(property)) {
103 const parts = lines[i].split(separator);
104 if (parts.length >= 2) {
105 parts.shift();
106 return parts.join(separator).trim();
107 } else {
108 return '';
109 }
110 }
111 }
112 return '';
113}
114
115function decodeEscapeSequence(str, base) {
116 base = base || 16;
117 return str.replace(/\\x([0-9A-Fa-f]{2})/g, function () {
118 return String.fromCharCode(parseInt(arguments[1], base));
119 });
120}
121
122function detectSplit(str) {
123 let seperator = '';
124 let part = 0;
125 str.split('').forEach(element => {
126 if (element >= '0' && element <= '9') {
127 if (part === 1) { part++; }
128 } else {
129 if (part === 0) { part++; }
130 if (part === 1) {
131 seperator += element;
132 }
133 }
134 });
135 return seperator;
136}
137
138function parseTime(t, pmDesignator) {
139 pmDesignator = pmDesignator || '';
140 t = t.toUpperCase();
141 let hour = 0;
142 let min = 0;
143 let splitter = detectSplit(t);
144 let parts = t.split(splitter);
145 if (parts.length >= 2) {
146 if (parts[2]) {
147 parts[1] += parts[2];
148 }
149 let isPM = (parts[1] && (parts[1].toLowerCase().indexOf('pm') > -1) || (parts[1].toLowerCase().indexOf('p.m.') > -1) || (parts[1].toLowerCase().indexOf('p. m.') > -1) || (parts[1].toLowerCase().indexOf('n') > -1) || (parts[1].toLowerCase().indexOf('ch') > -1) || (parts[1].toLowerCase().indexOf('ös') > -1) || (pmDesignator && parts[1].toLowerCase().indexOf(pmDesignator) > -1));
150 hour = parseInt(parts[0], 10);
151 min = parseInt(parts[1], 10);
152 hour = isPM && hour < 12 ? hour + 12 : hour;
153 return ('0' + hour).substr(-2) + ':' + ('0' + min).substr(-2);
154 }
155}
156
157function parseDateTime(dt, culture) {
158 const result = {
159 date: '',
160 time: ''
161 };
162 culture = culture || {};
163 let dateFormat = (culture.dateFormat || '').toLowerCase();
164 let pmDesignator = (culture.pmDesignator || '');
165
166 const parts = dt.split(' ');
167 if (parts[0]) {
168 if (parts[0].indexOf('/') >= 0) {
169 // Dateformat: mm/dd/yyyy or dd/mm/yyyy or dd/mm/yy or yyyy/mm/dd
170 const dtparts = parts[0].split('/');
171 if (dtparts.length === 3) {
172 if (dtparts[0].length === 4) {
173 // Dateformat: yyyy/mm/dd
174 result.date = dtparts[0] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[2]).substr(-2);
175 } else if (dtparts[2].length === 2) {
176 if ((dateFormat.indexOf('/d/') > -1 || dateFormat.indexOf('/dd/') > -1)) {
177 // Dateformat: mm/dd/yy
178 result.date = '20' + dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
179 } else {
180 // Dateformat: dd/mm/yy
181 result.date = '20' + dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
182 }
183 } else {
184 // Dateformat: mm/dd/yyyy or dd/mm/yyyy
185 const isEN = ((dt.toLowerCase().indexOf('pm') > -1) || (dt.toLowerCase().indexOf('p.m.') > -1) || (dt.toLowerCase().indexOf('p. m.') > -1) || (dt.toLowerCase().indexOf('am') > -1) || (dt.toLowerCase().indexOf('a.m.') > -1) || (dt.toLowerCase().indexOf('a. m.') > -1));
186 if ((isEN || dateFormat.indexOf('/d/') > -1 || dateFormat.indexOf('/dd/') > -1) && dateFormat.indexOf('dd/') !== 0) {
187 // Dateformat: mm/dd/yyyy
188 result.date = dtparts[2] + '-' + ('0' + dtparts[0]).substr(-2) + '-' + ('0' + dtparts[1]).substr(-2);
189 } else {
190 // Dateformat: dd/mm/yyyy
191 result.date = dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
192 }
193 }
194 }
195 }
196 if (parts[0].indexOf('.') >= 0) {
197 const dtparts = parts[0].split('.');
198 if (dtparts.length === 3) {
199 if (dateFormat.indexOf('.d.') > -1 || dateFormat.indexOf('.dd.') > -1) {
200 // Dateformat: mm.dd.yyyy
201 result.date = dtparts[2] + '-' + ('0' + dtparts[0]).substr(-2) + '-' + ('0' + dtparts[1]).substr(-2);
202 } else {
203 // Dateformat: dd.mm.yyyy
204 result.date = dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
205 }
206 }
207 }
208 if (parts[0].indexOf('-') >= 0) {
209 // Dateformat: yyyy-mm-dd
210 const dtparts = parts[0].split('-');
211 if (dtparts.length === 3) {
212 result.date = dtparts[0] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[2]).substr(-2);
213 }
214 }
215 }
216 if (parts[1]) {
217 parts.shift();
218 let time = parts.join(' ');
219 result.time = parseTime(time, pmDesignator);
220 }
221 return result;
222}
223
224function parseHead(head, rights) {
225 let space = (rights > 0);
226 let count = 1;
227 let from = 0;
228 let to = 0;
229 let result = [];
230 for (let i = 0; i < head.length; i++) {
231 if (count <= rights) {
232 // if (head[i] === ' ' && !space) {
233 if (/\s/.test(head[i]) && !space) {
234 to = i - 1;
235 result.push({
236 from: from,
237 to: to + 1,
238 cap: head.substring(from, to + 1)
239 });
240 from = to + 2;
241 count++;
242 }
243 space = head[i] === ' ';
244 } else {
245 if (!/\s/.test(head[i]) && space) {
246 to = i - 1;
247 if (from < to) {
248 result.push({
249 from: from,
250 to: to,
251 cap: head.substring(from, to)
252 });
253 }
254 from = to + 1;
255 count++;
256 }
257 space = head[i] === ' ';
258 }
259 }
260 to = 1000;
261 result.push({
262 from: from,
263 to: to,
264 cap: head.substring(from, to)
265 });
266 let len = result.length;
267 for (var i = 0; i < len; i++) {
268 if (result[i].cap.replace(/\s/g, '').length === 0) {
269 if (i + 1 < len) {
270 result[i].to = result[i + 1].to;
271 result[i].cap = result[i].cap + result[i + 1].cap;
272 result.splice(i + 1, 1);
273 len = len - 1;
274 }
275 }
276 }
277 return result;
278}
279
280function findObjectByKey(array, key, value) {
281 for (let i = 0; i < array.length; i++) {
282 if (array[i][key] === value) {
283 return i;
284 }
285 }
286 return -1;
287}
288
289function getWmic() {
290 if (os.type() === 'Windows_NT' && !wmicPath) {
291 wmicPath = process.env.WINDIR + '\\system32\\wbem\\wmic.exe';
292 if (!fs.existsSync(wmicPath)) {
293 try {
294 const wmicPathArray = execSync('WHERE WMIC').toString().split('\r\n');
295 if (wmicPathArray && wmicPathArray.length) {
296 wmicPath = wmicPathArray[0];
297 } else {
298 wmicPath = 'wmic';
299 }
300 } catch (e) {
301 wmicPath = 'wmic';
302 }
303 }
304 }
305 return wmicPath;
306}
307
308function wmic(command, options) {
309 options = options || execOptsWin;
310 return new Promise((resolve) => {
311 process.nextTick(() => {
312 try {
313 exec(process.env.WINDIR + '\\system32\\chcp.com 65001 | ' + getWmic() + ' ' + command, options, function (error, stdout) {
314 resolve(stdout, error);
315 }).stdin.end();
316 } catch (e) {
317 resolve('', e);
318 }
319 });
320 });
321}
322
323function getVboxmanage() {
324 return _windows ? process.env.VBOX_INSTALL_PATH || process.env.VBOX_MSI_INSTALL_PATH + '\\VBoxManage.exe' + '" ' : 'vboxmanage';
325}
326
327function powerShell(cmd) {
328
329 let result = '';
330
331 return new Promise((resolve) => {
332 process.nextTick(() => {
333 try {
334 const child = spawn('powershell.exe', ['-NoLogo', '-InputFormat', 'Text', '-NoExit', '-ExecutionPolicy', 'Unrestricted', '-Command', '-'], {
335 stdio: 'pipe',
336 windowsHide: true,
337 maxBuffer: 1024 * 20000,
338 encoding: 'UTF-8',
339 env: util._extend({}, process.env, { LANG: 'en_US.UTF-8' })
340 });
341
342 if (child && !child.pid) {
343 child.on('error', function () {
344 resolve(result);
345 });
346 }
347 if (child && child.pid) {
348 child.stdout.on('data', function (data) {
349 result = result + data.toString('utf8');
350 });
351 child.stderr.on('data', function () {
352 child.kill();
353 resolve(result);
354 });
355 child.on('close', function () {
356 child.kill();
357 resolve(result);
358 });
359 child.on('error', function () {
360 child.kill();
361 resolve(result);
362 });
363 try {
364 child.stdin.write(cmd + os.EOL);
365 child.stdin.write('exit' + os.EOL);
366 child.stdin.end();
367 } catch (e) {
368 child.kill();
369 resolve(result);
370 }
371 } else {
372 resolve(result);
373 }
374 } catch (e) {
375 resolve(result);
376 }
377 });
378 });
379}
380
381function getCodepage() {
382 if (_windows) {
383 if (!codepage) {
384 try {
385 const stdout = execSync('chcp');
386 const lines = stdout.toString().split('\r\n');
387 const parts = lines[0].split(':');
388 codepage = parts.length > 1 ? parts[1].replace('.', '') : '';
389 } catch (err) {
390 codepage = '437';
391 }
392 }
393 return codepage;
394 }
395 if (_linux || _darwin || _freebsd || _openbsd || _netbsd) {
396 if (!codepage) {
397 try {
398 const stdout = execSync('echo $LANG');
399 const lines = stdout.toString().split('\r\n');
400 const parts = lines[0].split('.');
401 codepage = parts.length > 1 ? parts[1].trim() : '';
402 if (!codepage) {
403 codepage = 'UTF-8';
404 }
405 } catch (err) {
406 codepage = 'UTF-8';
407 }
408 }
409 return codepage;
410 }
411}
412
413function isRaspberry() {
414 const PI_MODEL_NO = [
415 'BCM2708',
416 'BCM2709',
417 'BCM2710',
418 'BCM2835',
419 'BCM2837B0'
420 ];
421 let cpuinfo = [];
422 try {
423 cpuinfo = fs.readFileSync('/proc/cpuinfo', { encoding: 'utf8' }).split('\n');
424 } catch (e) {
425 return false;
426 }
427 const hardware = getValue(cpuinfo, 'hardware');
428 return (hardware && PI_MODEL_NO.indexOf(hardware) > -1);
429}
430
431function isRaspbian() {
432 let osrelease = [];
433 try {
434 osrelease = fs.readFileSync('/etc/os-release', { encoding: 'utf8' }).split('\n');
435 } catch (e) {
436 return false;
437 }
438 const id = getValue(osrelease, 'id');
439 return (id && id.indexOf('raspbian') > -1);
440}
441
442function execWin(cmd, opts, callback) {
443 if (!callback) {
444 callback = opts;
445 opts = execOptsWin;
446 }
447 let newCmd = 'chcp 65001 > nul && cmd /C ' + cmd + ' && chcp ' + codepage + ' > nul';
448 exec(newCmd, opts, function (error, stdout) {
449 callback(error, stdout);
450 });
451}
452
453function darwinXcodeExists() {
454 const cmdLineToolsExists = fs.existsSync('/Library/Developer/CommandLineTools/usr/bin/');
455 const xcodeAppExists = fs.existsSync('/Applications/Xcode.app/Contents/Developer/Tools');
456 const xcodeExists = fs.existsSync('/Library/Developer/Xcode/');
457 return (cmdLineToolsExists || xcodeExists || xcodeAppExists);
458}
459
460function nanoSeconds() {
461 const time = process.hrtime();
462 if (!Array.isArray(time) || time.length !== 2) {
463 return 0;
464 }
465 return +time[0] * 1e9 + +time[1];
466}
467
468function countUniqueLines(lines, startingWith) {
469 startingWith = startingWith || '';
470 const uniqueLines = [];
471 lines.forEach(line => {
472 if (line.startsWith(startingWith)) {
473 if (uniqueLines.indexOf(line) === -1) {
474 uniqueLines.push(line);
475 }
476 }
477 });
478 return uniqueLines.length;
479}
480
481function countLines(lines, startingWith) {
482 startingWith = startingWith || '';
483 const uniqueLines = [];
484 lines.forEach(line => {
485 if (line.startsWith(startingWith)) {
486 uniqueLines.push(line);
487 }
488 });
489 return uniqueLines.length;
490}
491
492function sanitizeShellString(str) {
493 let result = str;
494 result = result.replace(/>/g, '');
495 result = result.replace(/</g, '');
496 result = result.replace(/\*/g, '');
497 result = result.replace(/\?/g, '');
498 result = result.replace(/\[/g, '');
499 result = result.replace(/\]/g, '');
500 result = result.replace(/\|/g, '');
501 result = result.replace(/\`/g, '');
502 result = result.replace(/\$/g, '');
503 result = result.replace(/;/g, '');
504 result = result.replace(/&/g, '');
505 result = result.replace(/\)/g, '');
506 result = result.replace(/\(/g, '');
507 result = result.replace(/\$/g, '');
508 result = result.replace(/#/g, '');
509 result = result.replace(/\\/g, '');
510 result = result.replace(/\t/g, '');
511 result = result.replace(/\n/g, '');
512 result = result.replace(/\"/g, '');
513 return result;
514}
515
516function noop() { }
517
518exports.toInt = toInt;
519exports.execOptsWin = execOptsWin;
520exports.getCodepage = getCodepage;
521exports.execWin = execWin;
522exports.isFunction = isFunction;
523exports.unique = unique;
524exports.sortByKey = sortByKey;
525exports.cores = cores;
526exports.getValue = getValue;
527exports.decodeEscapeSequence = decodeEscapeSequence;
528exports.parseDateTime = parseDateTime;
529exports.parseHead = parseHead;
530exports.findObjectByKey = findObjectByKey;
531exports.getWmic = getWmic;
532exports.wmic = wmic;
533exports.darwinXcodeExists = darwinXcodeExists;
534exports.getVboxmanage = getVboxmanage;
535exports.powerShell = powerShell;
536exports.nanoSeconds = nanoSeconds;
537exports.countUniqueLines = countUniqueLines;
538exports.countLines = countLines;
539exports.noop = noop;
540exports.isRaspberry = isRaspberry;
541exports.isRaspbian = isRaspbian;
542exports.sanitizeShellString = sanitizeShellString;