Skip to content

Commit f78e58f

Browse files
committed
refactor for added spawning method to handle general spawn use case
1 parent 464066a commit f78e58f

File tree

4 files changed

+131
-83
lines changed

4 files changed

+131
-83
lines changed

index.js

Lines changed: 91 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,18 @@ const SYS_MANAGERS = {
4545
shell: ['powershell'],
4646
};
4747

48-
function sysManager(reject) {
49-
if (!reject)
50-
reject = (data) => {
51-
return new Error(data);
52-
}
53-
48+
function sysManager() {
5449
let managers = SYS_MANAGERS[process.platform];
5550
if (!managers || !managers.length) {
56-
return reject('unknown platform \'' + process.platform + '\'');
51+
return 'unknown platform \'' + process.platform + '\'';
5752
}
5853

5954
managers = managers.filter(function (mng) {
6055
return (where(mng) !== null);
6156
});
6257

6358
if (!managers.length) {
64-
return reject('System OS package manager not found');
59+
return 'System OS package manager not found';
6560
}
6661

6762
return SYS_COMMANDS[managers[0]].split(' ');
@@ -82,7 +77,7 @@ function sysManager(reject) {
8277
*/
8378
export const packager = Sys.packager = function () {
8479
let sys = sysManager();
85-
if (sys[0])
80+
if (Array.isArray(sys) && sys[0])
8681
return {
8782
sudo: (sys[0] === 'sudo'),
8883
command: ((!sys[2]) ? sys[0] : sys[1]),
@@ -100,75 +95,39 @@ export const packager = Sys.packager = function () {
10095
* - Defaults to 'get os-manager installer' if no package manager is found.
10196
* @throws Throws if `process.platform` is none of darwin, freebsd, linux, sunos or win32.
10297
*/
103-
export const installer = Sys.installer = function (application) {
104-
let installOutput = '';
105-
return new Promise(function (resolve, reject) {
106-
if (!application)
107-
return reject("No package, application name missing.");
108-
109-
let manger = sysManager(reject);
110-
let cmd = manger[0];
111-
let args = null;
112-
let install = null;
113-
if (manger[1])
114-
args = [manger[1]];
115-
if (manger[2])
116-
install = [manger[2]];
117-
118-
let whatToInstall = (Array.isArray(application)) ? [].concat(application).concat(['-y']) : [].concat([application]).concat(['-y']);
119-
let system = whatToInstall;
120-
if ((args) && (!install))
121-
system = args.concat(whatToInstall);
122-
if ((args) && (install))
123-
system = args.concat(install).concat(whatToInstall);
124-
125-
if (cmd != 'powershell') {
126-
let input = '';
127-
if (cmd.includes('choco') && process.platform == 'win32') {
128-
cmd = where('choco');
129-
system = [cmd].concat(system);
130-
cmd = join(__dirname, 'bin', 'sudo.bat');
131-
}
132-
133-
const proc = spawn(cmd, system, {
134-
stdio: 'pipe',
135-
//shell: true
136-
});
137-
138-
proc.on('close', () => {
139-
return resolve(installOutput);
140-
});
141-
142-
proc.on('exit', () => {
143-
return resolve(installOutput);
144-
});
145-
146-
proc.stdout.on('data', (data) => {
147-
installOutput += input = data.toString();
148-
if (system.includes('node-fake-tester')) {
149-
proc.kill('SIGKILL');
150-
return resolve('For testing only, no package installed.');
151-
}
152-
/*
153-
if (input.includes('The package was not found') || input.includes('Unable to locate package') || input.includes('is denied') || input.includes('Throwing error')) {
154-
proc.kill('SIGKILL');
155-
return reject(input);
156-
}*/
157-
});
158-
159-
proc.stderr.on('data', (data) => {
160-
return reject(data.toString());
161-
});
162-
163-
if (system.includes('node-fake-tester') && Object.getOwnPropertyDescriptor(process, 'platform').value == 'darwin') {
164-
proc.kill('SIGKILL');
165-
return resolve('For testing only, no package installed.');
166-
}
167-
168-
} else {
169-
return reject('No package manager installed!');
98+
export const installer = Sys.installer = function (application, progress = () => { }) {
99+
if (!application)
100+
return new Promise((resolve, reject) => { return reject("No package, application name missing."); });
101+
102+
let manager = sysManager();
103+
if (!Array.isArray(manager))
104+
return new Promise((resolve, reject) => { return reject(manager); });
105+
let cmd = manager[0];
106+
let args = null;
107+
let install = null;
108+
if (manager[1])
109+
args = [manager[1]];
110+
if (manager[2])
111+
install = [manager[2]];
112+
113+
let whatToInstall = (Array.isArray(application)) ? [].concat(application).concat(['-y']) : [].concat([application]).concat(['-y']);
114+
let system = whatToInstall;
115+
if ((args) && (!install))
116+
system = args.concat(whatToInstall);
117+
if ((args) && (install))
118+
system = args.concat(install).concat(whatToInstall);
119+
120+
if (cmd != 'powershell') {
121+
if (cmd.includes('choco') && process.platform == 'win32') {
122+
cmd = where('choco');
123+
system = [cmd].concat(system);
124+
cmd = join(__dirname, 'bin', 'sudo.bat');
170125
}
171-
});
126+
127+
return spawning(cmd, system, progress);
128+
} else {
129+
return new Promise((resolve, reject) => { return reject('No package manager installed!') });
130+
}
172131
}
173132

174133
/**
@@ -188,6 +147,61 @@ export const where = Sys.where = function (executable) {
188147
return found;
189148
}
190149

150+
/**
151+
* Spawn subprocess with `Promise` features, and `progress` callback for `on('data') `event.
152+
*
153+
* @param {String} cmd - platform command
154+
* @param {Array} argument - command arguments
155+
* @param {Function} progress - callback for `on('data')` event.
156+
*```js
157+
* { handle: object, output: string }
158+
*```
159+
* - the callback will received object, `instance` **handle** of the spawned child processes, and any **output** data.
160+
* - any returns will be the **`resolve()` .then()** handler.
161+
* @param {Object} options - Any child process `spawn` options, defaults: stdio: 'pipe'.
162+
*/
163+
export const spawning = Sys.spawning = function (cmd, argument = [], progress = () => { }, options = { stdio: 'pipe', }) {
164+
return new Promise((resolve, reject) => {
165+
let output = null;
166+
const child = spawn(cmd, argument, options);
167+
child.on('close', () => {
168+
return resolve(output);
169+
});
170+
171+
child.on('exit', () => {
172+
return resolve(output);
173+
});
174+
175+
child.stdout.on('data', (data) => {
176+
let input = data.toString();
177+
let onProgress = null
178+
if (progress) {
179+
onProgress = progress({ handle: child, output: input });
180+
}
181+
182+
if (onProgress) {
183+
output = onProgress;
184+
} else {
185+
output += input;
186+
}
187+
188+
if (argument.includes('fake-js')) {
189+
child.kill('SIGKILL');
190+
return resolve('For testing only. ' + output);
191+
}
192+
});
193+
194+
child.stderr.on('data', (data) => {
195+
return reject(data.toString());
196+
});
197+
198+
if (argument.includes('fake-js') && Object.getOwnPropertyDescriptor(process, 'platform').value == 'darwin') {
199+
child.kill('SIGKILL');
200+
return resolve('For testing only. ' + output);
201+
}
202+
});
203+
}
204+
191205
function Sys() { }
192206

193207
export default Sys;

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "node-sys",
3-
"version": "1.0.3",
3+
"version": "1.0.4",
44
"description": "Universal package installer, get the command for managing packages, or auto install any package, using one command for all platforms. Automate the installation of macOS Brew, and Windows Chocolatey package managers.",
55
"type": "module",
66
"main": "index.js",

test/test.js

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ describe('Method: `installer` for platform set to `other`', function () {
115115

116116
describe('Method: `installer` install packages `unzip` and `nano`', function () {
117117
it('should return on successful install of multiple packages or print error on unknown platform', function (done) {
118-
let multi = ['unzip', 'nano', 'node-fake-tester', '--noop'];
118+
let multi = ['unzip', 'nano', 'fake-js', '--noop'];
119119

120120
installer(multi)
121121
.then(function (data) {
@@ -144,7 +144,7 @@ describe('Method: `installer` install packages `unzip` and `nano`, platform set
144144
});
145145

146146
it('should return on successful install of multiple packages or print error on unknown platform, platform set to `win64`', function (done) {
147-
let multi = ['unzip', 'nano', 'node-fake-tester'];
147+
let multi = ['unzip', 'nano', 'fake-js'];
148148

149149
installer(multi)
150150
.then(function (data) {
@@ -181,12 +181,45 @@ describe('Method: `installer` install packages `unzip`, platform set to `shell`'
181181
});
182182
});
183183

184+
describe('Method: `spawning`', function () {
185+
// save original process.platform
186+
before(function () {
187+
this.originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
188+
// redefine process.platform
189+
Object.defineProperty(process, 'platform', {
190+
value: 'win64'
191+
});
192+
});
193+
// restore original process.platform
194+
after(function () {
195+
Object.defineProperty(process, 'platform', this.originalPlatform);
196+
});
197+
198+
it('should return on successful install of multiple packages with different output from `progress`, platform set to `win64`', function (done) {
199+
let multi = ['unzip', 'nano', 'fake-js'];
200+
installer(multi, (object) => {
201+
expect(object).to.be.a('object');
202+
expect(object.handle).to.be.instanceOf(Object);
203+
expect(object.output).to.be.a('string');
204+
return 'hello world';
205+
})
206+
.then(function (data) {
207+
expect(data).to.be.a('string');
208+
expect(data).to.equal('For testing only. hello world');
209+
done();
210+
})
211+
.catch(function (err) {
212+
expect(err).to.be.empty;
213+
done();
214+
});
215+
});
216+
});
217+
184218
describe('Method: `where`', function () {
185219
it('should return null/empty for executable not found', function (done) {
186-
let found = where('node-fake-tester');
220+
let found = where('fake-js');
187221
expect(found).to.be.null;
188222
done();
189-
190223
});
191224
});
192225

@@ -200,5 +233,6 @@ describe('Function: `Sys`', function () {
200233
expect(Sys).itself.to.respondTo('installer');
201234
expect(Sys).itself.to.respondTo('where');
202235
expect(Sys).itself.to.respondTo('packager');
236+
expect(Sys).itself.to.respondTo('spawning');
203237
});
204238
});

0 commit comments

Comments
 (0)