From 1fc845d4ebe6f8ac48743b2e1b7f14ebe828a2a7 Mon Sep 17 00:00:00 2001 From: Austin Burdine Date: Thu, 7 Nov 2019 16:09:04 +0700 Subject: [PATCH] feat(system): use systeminformation for os version information --- lib/command.js | 3 ++ lib/system.js | 18 ++++--- lib/ui/index.js | 2 +- lib/utils/get-os.js | 41 --------------- test/unit/command-spec.js | 42 ++++++++++----- test/unit/system-spec.js | 66 +++++++++++++---------- test/unit/ui/index-spec.js | 8 +-- test/unit/utils/get-os-spec.js | 95 ---------------------------------- 8 files changed, 86 insertions(+), 189 deletions(-) delete mode 100644 lib/utils/get-os.js delete mode 100644 test/unit/utils/get-os-spec.js diff --git a/lib/command.js b/lib/command.js index 09c68059b..f459356dd 100644 --- a/lib/command.js +++ b/lib/command.js @@ -169,6 +169,9 @@ class Command { } try { + debug('loading operating system information'); + await ui.run(() => system.loadOsInfo(), 'Inspecting operating system', {clear: true}); + if (this.runPreChecks) { const preChecks = require('./utils/pre-checks'); await preChecks(ui, system); diff --git a/lib/system.js b/lib/system.js index 43262ce68..d1f0397c1 100644 --- a/lib/system.js +++ b/lib/system.js @@ -81,14 +81,7 @@ class System { * @public */ get operatingSystem() { - if (!this._operatingSystem) { - const getOS = require('./utils/get-os'); - this._operatingSystem = getOS(this.platform); - - return this._operatingSystem; - } - - return this._operatingSystem; + return this._osInfo || {}; } /** @@ -346,6 +339,15 @@ class System { return available; } + async loadOsInfo() { + if (this._osInfo) { + return; + } + + const {osInfo} = require('systeminformation/lib/osinfo'); + this._osInfo = await osInfo(); + } + /** * Writes an error message to a global log file. * diff --git a/lib/ui/index.js b/lib/ui/index.js index 11d4194cb..036dedea7 100644 --- a/lib/ui/index.js +++ b/lib/ui/index.js @@ -490,7 +490,7 @@ class UI { const ghostVersion = version ? ` Ghost Version: ${version}\n` : ''; return 'Debug Information:\n' + - ` OS: ${system.operatingSystem.os}, v${system.operatingSystem.version}\n` + + ` OS: ${system.operatingSystem.distro}, v${system.operatingSystem.release}\n` + ` Node Version: ${process.version}\n` + ghostVersion + ` Ghost-CLI Version: ${system.cliVersion}\n` + diff --git a/lib/utils/get-os.js b/lib/utils/get-os.js deleted file mode 100644 index 90c2821d0..000000000 --- a/lib/utils/get-os.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -const os = require('os'); -const execa = require('execa'); - -module.exports = function getOS(platform) { - const osInfo = { - os: os.platform(), - version: os.release() - }; - - if (platform.linux) { - try { - osInfo.os = execa.shellSync('lsb_release -i -s').stdout; - osInfo.version = execa.shellSync('lsb_release -r -s').stdout; - } catch (e) { - return osInfo; - } - } else if (platform.macos) { - // Darwin is Mac OS, use `sw_vers` - try { - osInfo.os = execa.shellSync('sw_vers -productName').stdout; - osInfo.version = execa.shellSync('sw_vers -productVersion').stdout; - } catch (e) { - return osInfo; - } - } else if (platform.windows) { - // for windows run `ver` - // should output something like this: Microsoft Windows XP [Version 5.1.2600] - try { - const winOutput = execa.shellSync('ver').stdout.split(/\[/i); - - osInfo.os = winOutput[0].trim(); - osInfo.version = /[0-9]+\.[0-9]+\.[0-9]+/.exec(winOutput[1])[0]; - } catch (e) { - return osInfo; - } - } - - return osInfo; -}; diff --git a/test/unit/command-spec.js b/test/unit/command-spec.js index 45e3937ff..54741f620 100644 --- a/test/unit/command-spec.js +++ b/test/unit/command-spec.js @@ -283,9 +283,11 @@ describe('Unit: Command', function () { }); it('loads system and ui dependencies, calls run method', async function () { - const uiStub = sinon.stub().returns({ui: true}); + const run = sinon.stub().callsFake(fn => fn()); + const uiStub = sinon.stub().returns({ui: true, run}); const setEnvironmentStub = sinon.stub(); - const systemStub = sinon.stub().returns({setEnvironment: setEnvironmentStub}); + const loadOsInfo = sinon.stub().resolves(); + const systemStub = sinon.stub().returns({setEnvironment: setEnvironmentStub, loadOsInfo}); const Command = proxyquire(modulePath, { './ui': uiStub, @@ -312,15 +314,19 @@ describe('Unit: Command', function () { expect(setEnvironmentStub.calledOnce).to.be.true; expect(setEnvironmentStub.calledWithExactly(true, true)).to.be.true; expect(systemStub.calledOnce).to.be.true; - expect(systemStub.calledWithExactly({ui: true}, [{extensiona: true}])).to.be.true; + expect(systemStub.calledWithExactly({ui: true, run}, [{extensiona: true}])).to.be.true; + expect(run.calledOnce).to.be.true; + expect(loadOsInfo.calledOnce).to.be.true; expect(runStub.calledOnce).to.be.true; expect(runStub.calledWithExactly({verbose: true, prompt: true, development: true, auto: false})).to.be.true; }); it('binds cleanup handler if cleanup method is defined', async function () { - const uiStub = sinon.stub().returns({ui: true}); + const run = sinon.stub().callsFake(fn => fn()); + const uiStub = sinon.stub().returns({ui: true, run}); const setEnvironmentStub = sinon.stub(); - const systemStub = sinon.stub().returns({setEnvironment: setEnvironmentStub}); + const loadOsInfo = sinon.stub().resolves(); + const systemStub = sinon.stub().returns({setEnvironment: setEnvironmentStub, loadOsInfo}); const Command = proxyquire(modulePath, { './ui': uiStub, @@ -351,7 +357,9 @@ describe('Unit: Command', function () { expect(setEnvironmentStub.calledOnce).to.be.true; expect(setEnvironmentStub.calledWithExactly(true, true)).to.be.true; expect(systemStub.calledOnce).to.be.true; - expect(systemStub.calledWithExactly({ui: true}, [{extensiona: true}])).to.be.true; + expect(systemStub.calledWithExactly({ui: true, run}, [{extensiona: true}])).to.be.true; + expect(run.calledOnce).to.be.true; + expect(loadOsInfo.calledOnce).to.be.true; expect(runStub.calledOnce).to.be.true; expect(runStub.calledWithExactly({verbose: false, prompt: false, development: false, auto: true})).to.be.true; expect(onStub.calledTwice).to.be.true; @@ -360,9 +368,11 @@ describe('Unit: Command', function () { }); it('runs updateCheck if checkVersion property is true on command class', async function () { - const uiStub = sinon.stub().returns({ui: true}); + const run = sinon.stub().callsFake(fn => fn()); + const uiStub = sinon.stub().returns({ui: true, run}); const setEnvironmentStub = sinon.stub(); - const systemStub = sinon.stub().returns({setEnvironment: setEnvironmentStub}); + const loadOsInfo = sinon.stub().resolves(); + const systemStub = sinon.stub().returns({setEnvironment: setEnvironmentStub, loadOsInfo}); const preChecksStub = sinon.stub().resolves(); const Command = proxyquire(modulePath, { @@ -393,18 +403,22 @@ describe('Unit: Command', function () { expect(setEnvironmentStub.calledOnce).to.be.true; expect(setEnvironmentStub.calledWithExactly(true, true)).to.be.true; expect(systemStub.calledOnce).to.be.true; - expect(systemStub.calledWithExactly({ui: true}, [{extensiona: true}])).to.be.true; + expect(systemStub.calledWithExactly({ui: true, run}, [{extensiona: true}])).to.be.true; + expect(run.calledOnce).to.be.true; + expect(loadOsInfo.calledOnce).to.be.true; expect(preChecksStub.calledOnce).to.be.true; - expect(preChecksStub.calledWithExactly({ui: true}, {setEnvironment: setEnvironmentStub})).to.be.true; + expect(preChecksStub.calledWithExactly({ui: true, run}, {setEnvironment: setEnvironmentStub, loadOsInfo})).to.be.true; expect(runStub.calledOnce).to.be.true; expect(runStub.calledWithExactly({verbose: false, prompt: false, development: false, auto: false})).to.be.true; }); it('catches errors, passes them to ui error method, then exits', async function () { + const run = sinon.stub().callsFake(fn => fn()); const errorStub = sinon.stub(); - const uiStub = sinon.stub().returns({error: errorStub}); + const uiStub = sinon.stub().returns({error: errorStub, run}); + const loadOsInfo = sinon.stub().resolves(); const setEnvironmentStub = sinon.stub(); - const systemStub = sinon.stub().returns({setEnvironment: setEnvironmentStub}); + const systemStub = sinon.stub().returns({setEnvironment: setEnvironmentStub, loadOsInfo}); const Command = proxyquire(modulePath, { './ui': uiStub, @@ -437,7 +451,9 @@ describe('Unit: Command', function () { expect(setEnvironmentStub.calledOnce).to.be.true; expect(setEnvironmentStub.calledWithExactly(false, true)).to.be.true; expect(systemStub.calledOnce).to.be.true; - expect(systemStub.calledWithExactly({error: errorStub}, [{extensiona: true}])).to.be.true; + expect(systemStub.calledWithExactly({error: errorStub, run}, [{extensiona: true}])).to.be.true; + expect(run.calledOnce).to.be.true; + expect(loadOsInfo.calledOnce).to.be.true; expect(runStub.calledOnce).to.be.true; expect(runStub.calledWithExactly({verbose: false, prompt: false, development: false, auto: false})).to.be.true; expect(errorStub.calledOnce).to.be.true; diff --git a/test/unit/system-spec.js b/test/unit/system-spec.js index baf40ccf4..9297f206f 100644 --- a/test/unit/system-spec.js +++ b/test/unit/system-spec.js @@ -112,34 +112,20 @@ describe('Unit: System', function () { }); }); - describe('operatingSystem getter', function () { - it('caches and returns the correct OS', function () { - const getOsStub = sinon.stub().returns({ - os: 'Ubuntu', - version: '16' - }); - const System = proxyquire(modulePath, { - './utils/get-os': getOsStub - }); + it('operatingSystem getter', function () { + const System = require(modulePath); + const sys = new System({}, []); - const instance = new System({}, []); - const platformStub = sinon.stub(os, 'platform').returns('linux'); - const operatingSystem = instance.operatingSystem; - - expect(platformStub.calledOnce).to.be.true; - expect(getOsStub.calledOnce).to.be.true; - expect(operatingSystem).to.be.an('object'); - expect(operatingSystem.os).to.equal('Ubuntu'); - expect(operatingSystem.version).to.equal('16'); - - // do the second call to see that it gets cached - const newOperatingSystem = instance.operatingSystem; - expect(newOperatingSystem).to.be.an('object'); - expect(newOperatingSystem.os).to.equal('Ubuntu'); - expect(newOperatingSystem.version).to.equal('16'); - expect(newOperatingSystem).to.deep.equal(operatingSystem); - expect(getOsStub.calledOnce).to.be.true; - }); + expect(sys.operatingSystem).to.deep.equal({}); + + sys._osInfo = { + platform: 'Linux', + distro: 'Ubuntu', + release: '18.04 LTS', + kernel: 'kernel' + }; + + expect(sys.operatingSystem).to.deep.equal(sys._osInfo); }); describe('setEnvironment', function () { @@ -578,6 +564,32 @@ describe('Unit: System', function () { expect(getInstanceStub.calledTwice).to.be.true; }); + it('loadOsInfo returns if info already loaded', async function () { + const osInfo = sinon.stub().rejects(); + const System = proxyquire(modulePath, { + 'systeminformation/lib/osinfo': {osInfo} + }); + + const sys = new System({}, []); + sys._osInfo = {distro: 'Mac OS X', release: '10.15'}; + + await sys.loadOsInfo(); + expect(osInfo.called).to.be.false; + }); + + it('loadOsInfo loads operating system information', async function () { + const osInfo = sinon.stub().resolves({distro: 'Windows', release: '10'}); + const System = proxyquire(modulePath, { + 'systeminformation/lib/osinfo': {osInfo} + }); + + const sys = new System({}, []); + + await sys.loadOsInfo(); + expect(osInfo.calledOnce).to.be.true; + expect(sys._osInfo).to.deep.equal({distro: 'Windows', release: '10'}); + }); + it('writeErrorLog works', function () { const ensureDirStub = sinon.stub(); const writeFileStub = sinon.stub(); diff --git a/test/unit/ui/index-spec.js b/test/unit/ui/index-spec.js index 4465fdb30..2f26b428a 100644 --- a/test/unit/ui/index-spec.js +++ b/test/unit/ui/index-spec.js @@ -945,8 +945,8 @@ describe('Unit: UI', function () { cliVersion: '0.9.1.8', environment: 'Earth', operatingSystem: { - os: 'Ubuntu', - version: '16' + distro: 'Ubuntu', + release: '16' }, getInstance: () => ({version: null}) }; @@ -970,8 +970,8 @@ describe('Unit: UI', function () { cliVersion: '0.9.1.8', environment: 'Earth', operatingSystem: { - os: 'Ubuntu', - version: '16' + distro: 'Ubuntu', + release: '16' }, getInstance: () => ({version: '1.0.0'}) }; diff --git a/test/unit/utils/get-os-spec.js b/test/unit/utils/get-os-spec.js deleted file mode 100644 index d104ae727..000000000 --- a/test/unit/utils/get-os-spec.js +++ /dev/null @@ -1,95 +0,0 @@ -'use strict'; -const expect = require('chai').expect; -const sinon = require('sinon'); -const execa = require('execa'); -const os = require('os'); -const getOS = require('../../../lib/utils/get-os'); - -describe('Unit: Utils > getOS', function () { - let platformStub, versionStub, execaStub; - - beforeEach(function () { - versionStub = sinon.stub(os, 'release'); - execaStub = sinon.stub(execa, 'shellSync'); - platformStub = sinon.stub(os, 'platform'); - }); - - afterEach(function () { - sinon.restore(); - }); - - it('returns correct Linux OS', function () { - platformStub.returns('linux'); - execaStub.withArgs('lsb_release -i -s').returns({stdout: 'Ubuntu'}); - execaStub.withArgs('lsb_release -r -s').returns({stdout: '16'}); - - const osResult = getOS({linux: true}); - expect(osResult.os).to.equal('Ubuntu'); - expect(osResult.version).to.equal('16'); - expect(execaStub.calledTwice).to.be.true; - }); - - it('returns correct mac OS', function () { - platformStub.returns('darwin'); - execaStub.withArgs('sw_vers -productName').returns({stdout: 'Mac OS X'}); - execaStub.withArgs('sw_vers -productVersion').returns({stdout: '10.13.3'}); - - const osResult = getOS({macos: true}); - expect(osResult.os).to.equal('Mac OS X'); - expect(osResult.version).to.equal('10.13.3'); - expect(execaStub.calledTwice).to.be.true; - }); - - it('returns correct Windows OS', function () { - platformStub.returns('win32'); - execaStub.withArgs('ver').returns({stdout: 'Microsoft Windows XP [Version 5.1.2600]'}); - - const osResult = getOS({windows: true}); - expect(osResult.os).to.equal('Microsoft Windows XP'); - expect(osResult.version).to.equal('5.1.2600'); - expect(execaStub.calledOnce).to.be.true; - }); - - it('returns default os.platform if OS is not Mac, Linux, or Windows', function () { - platformStub.returns('freebsd'); - versionStub.returns('1.0.0'); - const osResult = getOS({ - linux: false, - macos: false, - windows: false - }); - expect(osResult.os).to.equal('freebsd'); - expect(osResult.version).to.equal('1.0.0'); - expect(execaStub.calledOnce).to.be.false; - }); - - it('returns default os when syscall fails', function () { - platformStub.returns('linux'); - versionStub.returns('1.0.0'); - execaStub.throws(); - - let osResult = getOS({ - linux: true - }); - - expect(osResult.os).to.equal('linux'); - expect(osResult.version).to.equal('1.0.0'); - expect(execaStub.calledOnce).to.be.true; - - osResult = getOS({ - macos: true - }); - - expect(osResult.os).to.equal('linux'); - expect(osResult.version).to.equal('1.0.0'); - expect(execaStub.calledTwice).to.be.true; - - osResult = getOS({ - windows: true - }); - - expect(osResult.os).to.equal('linux'); - expect(osResult.version).to.equal('1.0.0'); - expect(execaStub.calledThrice).to.be.true; - }); -});