AJ ONeal
5 years ago
5 changed files with 274 additions and 0 deletions
@ -0,0 +1 @@ |
|||
node_modules |
@ -0,0 +1,28 @@ |
|||
# serviceman |
|||
|
|||
A cross-platform service manager |
|||
|
|||
```bash |
|||
serviceman add --name "my-project" node ./serve.js --port 3000 |
|||
serviceman stop my-project |
|||
serviceman start my-project |
|||
``` |
|||
|
|||
Works with launchd (Mac), systemd (Linux), or standalone (Windows). |
|||
|
|||
## Meta Package |
|||
|
|||
This is a meta-package to fetch and install the correction version of |
|||
[go-serviceman](https://git.rootprojects.org/root/serviceman) |
|||
for your architecture and platform. |
|||
|
|||
```bash |
|||
npm install serviceman |
|||
``` |
|||
|
|||
## How does it work? |
|||
|
|||
1. Resolves executable from PATH, or hashbang (ex: `#!/usr/bin/env node`) |
|||
2. Resolves file and directory paths to absolute paths (ex: `/Users/me/my-project/serve.js`) |
|||
3. Creates a template `.plist` (Mac), `.service` (Linux), or `.json` (Windows) file |
|||
4. Calls `launchd` (Mac), `systemd` (Linux), or `serviceman-runner` (Windows) to enable/start/stop/etc |
@ -0,0 +1,18 @@ |
|||
{ |
|||
"name": "serviceman", |
|||
"version": "0.5.0", |
|||
"lockfileVersion": 1, |
|||
"requires": true, |
|||
"dependencies": { |
|||
"@root/mkdirp": { |
|||
"version": "1.0.0", |
|||
"resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz", |
|||
"integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA==" |
|||
}, |
|||
"@root/request": { |
|||
"version": "1.3.11", |
|||
"resolved": "https://registry.npmjs.org/@root/request/-/request-1.3.11.tgz", |
|||
"integrity": "sha512-3a4Eeghcjsfe6zh7EJ+ni1l8OK9Fz2wL1OjP4UCa0YdvtH39kdXB9RGWuzyNv7dZi0+Ffkc83KfH0WbPMiuJFw==" |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,30 @@ |
|||
{ |
|||
"name": "serviceman", |
|||
"version": "0.5.0", |
|||
"description": "A cross-platform service manager", |
|||
"main": "index.js", |
|||
"scripts": { |
|||
"postinstall": "bin/install-serviceman.js", |
|||
"test": "echo \"Error: no test specified\" && exit 1" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "https://git.rootprojects.org/root/serviceman.git" |
|||
}, |
|||
"keywords": [ |
|||
"launchd", |
|||
"systemd", |
|||
"winsvc", |
|||
"launchctl", |
|||
"systemctl", |
|||
"HKEY_CURRENT_USER", |
|||
"HKCU", |
|||
"Run" |
|||
], |
|||
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", |
|||
"license": "MPL-2.0", |
|||
"dependencies": { |
|||
"@root/mkdirp": "^1.0.0", |
|||
"@root/request": "^1.3.11" |
|||
} |
|||
} |
@ -0,0 +1,197 @@ |
|||
'use strict'; |
|||
var os = require('os'); |
|||
|
|||
// https://nodejs.org/api/os.html#os_os_arch
|
|||
// 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x', 'x32', and 'x64'
|
|||
var arch = os.arch(); // process.arch
|
|||
|
|||
// https://nodejs.org/api/os.html#os_os_platform
|
|||
// 'aix', 'darwin', 'freebsd', 'linux', 'openbsd', 'sunos', 'win32'
|
|||
var platform = os.platform(); // process.platform
|
|||
var ext = 'windows' === platform ? '.exe' : ''; |
|||
|
|||
// This is _probably_ right. It's good enough for us
|
|||
// https://github.com/nodejs/node/issues/13629
|
|||
if ('arm' === arch) { |
|||
arch += 'v' + process.config.variables.arm_version; |
|||
} |
|||
|
|||
var map = { |
|||
// arches
|
|||
armv6: 'armv6', |
|||
armv7: 'armv7', |
|||
arm64: 'armv8', |
|||
ia32: '386', |
|||
x32: '386', |
|||
x64: 'amd64', |
|||
// platforms
|
|||
darwin: 'darwin', |
|||
linux: 'linux', |
|||
win32: 'windows' |
|||
}; |
|||
|
|||
arch = map[arch]; |
|||
platform = map[platform]; |
|||
|
|||
if (!arch || !platform) { |
|||
console.error( |
|||
"'" + os.platform() + "' on '" + os.arch() + "' isn't supported yet." |
|||
); |
|||
console.error( |
|||
'Please open an issue at https://git.rootprojects.org/root/serviceman/issues' |
|||
); |
|||
process.exit(1); |
|||
} |
|||
|
|||
var newVer = require('../package.json').version; |
|||
var fs = require('fs'); |
|||
var exec = require('child_process').exec; |
|||
var request = require('@root/request'); |
|||
var mkdirp = require('@root/mkdirp'); |
|||
|
|||
function needsUpdate(oldVer, newVer) { |
|||
// "v1.0.0-pre" is BEHIND "v1.0.0"
|
|||
newVer = newVer.replace(/^v/, '').split(/[\.\-\+]/); |
|||
oldVer = oldVer.replace(/^v/, '').split(/[\.\-\+]/); |
|||
//console.log(oldVer, newVer);
|
|||
|
|||
if (newVer[3] && !oldVer[3]) { |
|||
// don't install beta over stable
|
|||
return false; |
|||
} |
|||
|
|||
if (oldVer[3]) { |
|||
if (oldVer[2] > 0) { |
|||
oldVer[2] -= 1; |
|||
} else if (oldVer[1] > 0) { |
|||
oldVer[2] = 999; |
|||
oldVer[1] -= 1; |
|||
} else if (oldVer[0] > 0) { |
|||
oldVer[2] = 999; |
|||
oldVer[1] = 999; |
|||
oldVer[0] -= 1; |
|||
} else { |
|||
// v0.0.0
|
|||
return true; |
|||
} |
|||
} |
|||
if (newVer[3]) { |
|||
if (newVer[2] > 0) { |
|||
newVer[2] -= 1; |
|||
} else if (newVer[1] > 0) { |
|||
newVer[2] = 999; |
|||
newVer[1] -= 1; |
|||
} else if (newVer[0] > 0) { |
|||
newVer[2] = 999; |
|||
newVer[1] = 999; |
|||
newVer[0] -= 1; |
|||
} else { |
|||
// v0.0.0
|
|||
return false; |
|||
} |
|||
} |
|||
|
|||
//console.log(oldVer, newVer);
|
|||
if (oldVer[0] > newVer[0]) { |
|||
return false; |
|||
} else if (oldVer[0] < newVer[0]) { |
|||
return true; |
|||
} else if (oldVer[1] > newVer[1]) { |
|||
return false; |
|||
} else if (oldVer[1] < newVer[1]) { |
|||
return true; |
|||
} else if (oldVer[2] > newVer[2]) { |
|||
return false; |
|||
} else if (oldVer[2] < newVer[2]) { |
|||
return true; |
|||
} else if (!oldVer[3] && newVer[3]) { |
|||
return false; |
|||
} else if (oldVer[3] && !newVer[3]) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/* |
|||
// Same version
|
|||
console.log(false === needsUpdate('0.5.0', '0.5.0')); |
|||
// No previous version
|
|||
console.log(true === needsUpdate('', '0.5.1')); |
|||
// The new version is slightly newer
|
|||
console.log(true === needsUpdate('0.5.0', '0.5.1')); |
|||
console.log(true === needsUpdate('0.4.999-pre1', '0.5.0-pre1')); |
|||
// The new version is slightly older
|
|||
console.log(false === needsUpdate('0.5.0', '0.5.0-pre1')); |
|||
console.log(false === needsUpdate('0.5.1', '0.5.0')); |
|||
*/ |
|||
|
|||
exec('serviceman version', { windowsHide: true }, function(err, stdout) { |
|||
var oldVer = (stdout || '').split(' ')[0]; |
|||
console.log(oldVer, newVer); |
|||
if (!needsUpdate(oldVer, newVer)) { |
|||
console.info( |
|||
'Current serviceman version is new enough:', |
|||
oldVer, |
|||
newVer |
|||
); |
|||
return; |
|||
//} else {
|
|||
// console.info('Current serviceman version is older:', oldVer, newVer);
|
|||
} |
|||
|
|||
var url = 'https://rootprojects.org/serviceman/dist/{{ .Platform }}/{{ .Arch }}/serviceman{{ .Ext }}' |
|||
.replace(/{{ .Version }}/g, newVer) |
|||
.replace(/{{ .Platform }}/g, platform) |
|||
.replace(/{{ .Arch }}/g, arch) |
|||
.replace(/{{ .Ext }}/g, ext); |
|||
|
|||
console.info('Installing from', url); |
|||
return request({ uri: url, encoding: null }, function(err, resp) { |
|||
if (err) { |
|||
console.error(err); |
|||
return; |
|||
} |
|||
|
|||
//console.log(resp.body.byteLength);
|
|||
//console.log(typeof resp.body);
|
|||
var serviceman = 'serviceman' + ext; |
|||
return fs.writeFile(serviceman, resp.body, null, function(err) { |
|||
if (err) { |
|||
console.error(err); |
|||
return; |
|||
} |
|||
fs.chmodSync(serviceman, parseInt('0755', 8)); |
|||
|
|||
var path = require('path'); |
|||
var localdir = '/usr/local/bin'; |
|||
fs.rename(serviceman, path.join(localdir, serviceman), function( |
|||
err |
|||
) { |
|||
if (err) { |
|||
//console.error(err);
|
|||
} |
|||
// ignore
|
|||
}); |
|||
|
|||
var homedir = require('os').homedir(); |
|||
var bindir = path.join(homedir, '.local', 'bin'); |
|||
return mkdirp(bindir, function(err) { |
|||
if (err) { |
|||
console.error(err); |
|||
return; |
|||
} |
|||
|
|||
var localsrv = path.join(bindir, serviceman); |
|||
return fs.writeFile(localsrv, resp.body, function(err) { |
|||
if (err) { |
|||
console.error(err); |
|||
return; |
|||
} |
|||
fs.chmodSync(localsrv, parseInt('0755', 8)); |
|||
console.info('Wrote', serviceman, 'to', bindir); |
|||
}); |
|||
}); |
|||
}); |
|||
}); |
|||
}); |
Loading…
Reference in new issue