unitup 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +89 -8
- package/biome.json +0 -1
- package/docs/index.html +188 -234
- package/index.d.ts +336 -445
- package/package.json +9 -3
- package/src/cli.js +187 -101
- package/src/doctor.js +123 -56
- package/src/errors.js +131 -0
- package/src/index.js +132 -59
- package/src/logs.js +148 -0
- package/src/platform/base.js +211 -0
- package/src/platform/index.js +43 -0
- package/src/platform/linux.js +155 -0
- package/src/platform/macos.js +723 -0
- package/src/platform/windows-host.js +246 -0
- package/src/platform/windows.js +495 -0
- package/src/runtimes/bun.js +4 -3
- package/src/runtimes/common.js +24 -6
- package/src/runtimes/deno.js +4 -3
- package/src/runtimes/elixir.js +4 -3
- package/src/runtimes/go.js +4 -3
- package/src/runtimes/index.js +14 -11
- package/src/runtimes/native.js +4 -5
- package/src/runtimes/node.js +4 -3
- package/src/runtimes/php.js +4 -3
- package/src/runtimes/python.js +4 -3
- package/src/runtimes/ruby.js +4 -3
- package/src/runtimes/shell.js +4 -3
- package/src/schedule.js +31 -24
- package/src/service/config.js +55 -0
- package/src/service/manager.js +233 -0
- package/src/service/normalize.js +216 -0
- package/src/systemd.js +84 -38
- package/src/unit.js +12 -18
- package/src/utils.js +32 -18
- package/tsconfig.json +1 -1
- package/types-test/index.ts +158 -0
package/src/runtimes/native.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
|
|
4
4
|
export async function createNativeAdapter(opts = {}) {
|
|
5
|
+
const baseDir = opts.cwd || process.cwd();
|
|
5
6
|
const targetPath = opts.script || opts.command;
|
|
6
7
|
|
|
7
8
|
if (!targetPath) {
|
|
8
9
|
throw new Error('Native executable path is required.');
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
const absPath = path.resolve(
|
|
12
|
+
const absPath = path.resolve(baseDir, targetPath);
|
|
12
13
|
|
|
13
14
|
if (!fs.existsSync(absPath)) {
|
|
14
15
|
throw new Error(`Executable file does not exist: ${absPath}`);
|
|
@@ -22,9 +23,7 @@ export async function createNativeAdapter(opts = {}) {
|
|
|
22
23
|
try {
|
|
23
24
|
fs.accessSync(absPath, fs.constants.X_OK);
|
|
24
25
|
} catch {
|
|
25
|
-
throw new Error(
|
|
26
|
-
`The executable is not runnable.\n\nRun:\n chmod +x ${absPath}`
|
|
27
|
-
);
|
|
26
|
+
throw new Error(`The executable is not runnable.\n\nRun:\n chmod +x ${absPath}`);
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
|
package/src/runtimes/node.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
import { findRuntimeExecutable, getBinaryVersion } from './common.js';
|
|
4
4
|
|
|
5
5
|
export async function createNodeAdapter(opts = {}) {
|
|
6
|
+
const baseDir = opts.cwd || process.cwd();
|
|
6
7
|
const customPath = opts.command || opts.nodePath;
|
|
7
8
|
let execPath = null;
|
|
8
9
|
|
|
9
10
|
if (customPath) {
|
|
10
|
-
const absPath = path.resolve(
|
|
11
|
+
const absPath = path.resolve(baseDir, customPath);
|
|
11
12
|
if (fs.existsSync(absPath)) {
|
|
12
13
|
try {
|
|
13
14
|
fs.accessSync(absPath, fs.constants.X_OK);
|
|
@@ -38,7 +39,7 @@ export async function createNodeAdapter(opts = {}) {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
const version = await getBinaryVersion(execPath, '-v');
|
|
41
|
-
const scriptPath = opts.script ? path.resolve(
|
|
42
|
+
const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
|
|
42
43
|
const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
|
|
43
44
|
const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
|
|
44
45
|
|
package/src/runtimes/php.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
import { findRuntimeExecutable, getBinaryVersion } from './common.js';
|
|
4
4
|
|
|
5
5
|
export async function createPhpAdapter(opts = {}) {
|
|
6
|
+
const baseDir = opts.cwd || process.cwd();
|
|
6
7
|
const customPath = opts.command;
|
|
7
8
|
let execPath = null;
|
|
8
9
|
|
|
9
10
|
if (customPath) {
|
|
10
|
-
const absPath = path.resolve(
|
|
11
|
+
const absPath = path.resolve(baseDir, customPath);
|
|
11
12
|
if (fs.existsSync(absPath)) {
|
|
12
13
|
try {
|
|
13
14
|
fs.accessSync(absPath, fs.constants.X_OK);
|
|
@@ -27,7 +28,7 @@ export async function createPhpAdapter(opts = {}) {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
const version = await getBinaryVersion(execPath, '-v');
|
|
30
|
-
const scriptPath = opts.script ? path.resolve(
|
|
31
|
+
const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
|
|
31
32
|
const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
|
|
32
33
|
const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
|
|
33
34
|
|
package/src/runtimes/python.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
import { findRuntimeExecutable, getBinaryVersion } from './common.js';
|
|
4
4
|
|
|
5
5
|
export async function createPythonAdapter(opts = {}) {
|
|
6
|
+
const baseDir = opts.cwd || process.cwd();
|
|
6
7
|
const customPath = opts.command;
|
|
7
8
|
let execPath = null;
|
|
8
9
|
|
|
9
10
|
if (customPath) {
|
|
10
|
-
const absPath = path.resolve(
|
|
11
|
+
const absPath = path.resolve(baseDir, customPath);
|
|
11
12
|
if (fs.existsSync(absPath)) {
|
|
12
13
|
try {
|
|
13
14
|
fs.accessSync(absPath, fs.constants.X_OK);
|
|
@@ -27,7 +28,7 @@ export async function createPythonAdapter(opts = {}) {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
const version = await getBinaryVersion(execPath, '--version');
|
|
30
|
-
const scriptPath = opts.script ? path.resolve(
|
|
31
|
+
const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
|
|
31
32
|
const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
|
|
32
33
|
const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
|
|
33
34
|
|
package/src/runtimes/ruby.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
import { findRuntimeExecutable, getBinaryVersion } from './common.js';
|
|
4
4
|
|
|
5
5
|
export async function createRubyAdapter(opts = {}) {
|
|
6
|
+
const baseDir = opts.cwd || process.cwd();
|
|
6
7
|
const customPath = opts.command;
|
|
7
8
|
let execPath = null;
|
|
8
9
|
|
|
9
10
|
if (customPath) {
|
|
10
|
-
const absPath = path.resolve(
|
|
11
|
+
const absPath = path.resolve(baseDir, customPath);
|
|
11
12
|
if (fs.existsSync(absPath)) {
|
|
12
13
|
try {
|
|
13
14
|
fs.accessSync(absPath, fs.constants.X_OK);
|
|
@@ -27,7 +28,7 @@ export async function createRubyAdapter(opts = {}) {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
const version = await getBinaryVersion(execPath, '-v');
|
|
30
|
-
const scriptPath = opts.script ? path.resolve(
|
|
31
|
+
const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
|
|
31
32
|
const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
|
|
32
33
|
const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
|
|
33
34
|
|
package/src/runtimes/shell.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
import { findRuntimeExecutable, getBinaryVersion } from './common.js';
|
|
4
4
|
|
|
5
5
|
export async function createShellAdapter(opts = {}) {
|
|
6
|
+
const baseDir = opts.cwd || process.cwd();
|
|
6
7
|
const customPath = opts.command;
|
|
7
8
|
let execPath = null;
|
|
8
9
|
|
|
9
10
|
if (customPath) {
|
|
10
|
-
const absPath = path.resolve(
|
|
11
|
+
const absPath = path.resolve(baseDir, customPath);
|
|
11
12
|
if (fs.existsSync(absPath)) {
|
|
12
13
|
try {
|
|
13
14
|
fs.accessSync(absPath, fs.constants.X_OK);
|
|
@@ -27,7 +28,7 @@ export async function createShellAdapter(opts = {}) {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
const version = await getBinaryVersion(execPath, '--version');
|
|
30
|
-
const scriptPath = opts.script ? path.resolve(
|
|
31
|
+
const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
|
|
31
32
|
const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
|
|
32
33
|
const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
|
|
33
34
|
|
package/src/schedule.js
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import fs from 'node:fs';
|
|
3
2
|
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { detectRuntime, resolveRuntimeConfig } from './runtimes/index.js';
|
|
5
|
+
import { runCommand } from './systemd.js';
|
|
4
6
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
deleteScheduleUnitFiles,
|
|
8
|
+
getTimerPath,
|
|
9
|
+
getUnitPath,
|
|
10
|
+
getUserUnitDir,
|
|
11
|
+
timerFileExists,
|
|
12
|
+
unitFileExists,
|
|
13
|
+
writeScheduleUnitFiles
|
|
14
|
+
} from './unit.js';
|
|
15
|
+
import {
|
|
16
|
+
deleteScheduleMetadata,
|
|
17
|
+
formatFutureTime,
|
|
18
|
+
formatRelativeTime,
|
|
19
|
+
getSchedulesDir,
|
|
7
20
|
getTimerFilename,
|
|
21
|
+
getUnitFilename,
|
|
22
|
+
readScheduleMetadata,
|
|
8
23
|
resolveAbsolutePath,
|
|
9
24
|
resolveWorkingDirectory,
|
|
10
|
-
|
|
11
|
-
formatFutureTime,
|
|
12
|
-
formatRelativeTime,
|
|
25
|
+
sanitizeServiceName,
|
|
13
26
|
saveScheduleMetadata,
|
|
14
|
-
|
|
15
|
-
deleteScheduleMetadata,
|
|
16
|
-
getSchedulesDir
|
|
27
|
+
validateDuration
|
|
17
28
|
} from './utils.js';
|
|
18
|
-
import {
|
|
19
|
-
getUserUnitDir,
|
|
20
|
-
getUnitPath,
|
|
21
|
-
getTimerPath,
|
|
22
|
-
timerFileExists,
|
|
23
|
-
unitFileExists,
|
|
24
|
-
writeScheduleUnitFiles,
|
|
25
|
-
deleteScheduleUnitFiles
|
|
26
|
-
} from './unit.js';
|
|
27
|
-
import { runCommand } from './systemd.js';
|
|
28
|
-
import { detectRuntime, resolveRuntimeConfig } from './runtimes/index.js';
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* Validates a systemd calendar expression using systemd-analyze if available.
|
|
@@ -53,7 +53,10 @@ export async function validateCalendar(expression) {
|
|
|
53
53
|
}
|
|
54
54
|
// If systemd-analyze binary is missing
|
|
55
55
|
if (res.code === 127 || (res.stderr && res.stderr.includes('not found'))) {
|
|
56
|
-
return {
|
|
56
|
+
return {
|
|
57
|
+
valid: true,
|
|
58
|
+
warning: 'systemd-analyze is not available; calendar expression could not be fully validated by systemd.'
|
|
59
|
+
};
|
|
57
60
|
}
|
|
58
61
|
} catch (err) {
|
|
59
62
|
if (err.message && err.message.startsWith('Invalid calendar expression')) {
|
|
@@ -360,7 +363,7 @@ export async function getScheduleStatus(name) {
|
|
|
360
363
|
}
|
|
361
364
|
|
|
362
365
|
// Parse NextElapse timestamp
|
|
363
|
-
|
|
366
|
+
const rawNext = timerProps.NextElapseUSecRealtime || timerProps.NextElapseUSec;
|
|
364
367
|
let nextRun = 'n/a';
|
|
365
368
|
|
|
366
369
|
if (rawNext && rawNext !== '0' && rawNext !== '18446744073709551615') {
|
|
@@ -370,7 +373,11 @@ export async function getScheduleStatus(name) {
|
|
|
370
373
|
} else {
|
|
371
374
|
nextRun = formatFutureTime(rawNext);
|
|
372
375
|
}
|
|
373
|
-
} else if (
|
|
376
|
+
} else if (
|
|
377
|
+
timerProps.NextElapseUSecMonotonic &&
|
|
378
|
+
timerProps.NextElapseUSecMonotonic !== '0' &&
|
|
379
|
+
timerProps.NextElapseUSecMonotonic !== '18446744073709551615'
|
|
380
|
+
) {
|
|
374
381
|
const monoNum = Number(timerProps.NextElapseUSecMonotonic);
|
|
375
382
|
if (!isNaN(monoNum) && monoNum > 0) {
|
|
376
383
|
const currentMonoUSec = os.uptime() * 1000000;
|
|
@@ -385,7 +392,7 @@ export async function getScheduleStatus(name) {
|
|
|
385
392
|
}
|
|
386
393
|
|
|
387
394
|
// Parse LastTrigger timestamp
|
|
388
|
-
|
|
395
|
+
const rawLast = timerProps.LastTriggerUSec;
|
|
389
396
|
let lastRun = 'never';
|
|
390
397
|
if (rawLast && rawLast !== '0' && rawLast !== 'n/a') {
|
|
391
398
|
const num = Number(rawLast);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {
|
|
4
|
+
findProjectConfig,
|
|
5
|
+
getConfigFilepath,
|
|
6
|
+
getUnitupDir,
|
|
7
|
+
readGlobalConfig,
|
|
8
|
+
readProjectConfig,
|
|
9
|
+
saveGlobalConfig,
|
|
10
|
+
saveProjectConfig
|
|
11
|
+
} from '../utils.js';
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
findProjectConfig,
|
|
15
|
+
readProjectConfig,
|
|
16
|
+
saveProjectConfig,
|
|
17
|
+
readGlobalConfig,
|
|
18
|
+
saveGlobalConfig,
|
|
19
|
+
getConfigFilepath,
|
|
20
|
+
getUnitupDir
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Merges raw CLI options with any found project configuration.
|
|
25
|
+
*
|
|
26
|
+
* @param {object} opts
|
|
27
|
+
* @returns {object} Merged options
|
|
28
|
+
*/
|
|
29
|
+
export function mergeConfigWithOptions(opts = {}) {
|
|
30
|
+
const targetCwd = opts.cwd ? path.resolve(process.cwd(), opts.cwd) : process.cwd();
|
|
31
|
+
const configPath = opts.config ? path.resolve(targetCwd, opts.config) : findProjectConfig(targetCwd);
|
|
32
|
+
const projectCfg = configPath ? readProjectConfig(configPath) : null;
|
|
33
|
+
|
|
34
|
+
if (!projectCfg) {
|
|
35
|
+
return { ...opts, cwd: targetCwd };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
name: opts.name || projectCfg.name,
|
|
40
|
+
group: opts.group || projectCfg.group || 'default',
|
|
41
|
+
script: opts.script || projectCfg.script,
|
|
42
|
+
command: opts.command || projectCfg.command,
|
|
43
|
+
runtime: opts.runtime || projectCfg.runtime,
|
|
44
|
+
runtimeArgs: opts.runtimeArgs && opts.runtimeArgs.length > 0 ? opts.runtimeArgs : projectCfg.runtimeArgs || [],
|
|
45
|
+
args: opts.args && opts.args.length > 0 ? opts.args : projectCfg.args || [],
|
|
46
|
+
envFile: opts.envFile || projectCfg.envFile,
|
|
47
|
+
restart: opts.restart && opts.restart !== 'on-failure' ? opts.restart : projectCfg.restart || 'on-failure',
|
|
48
|
+
memoryHigh: opts.memoryHigh || projectCfg?.resources?.memoryHigh || projectCfg?.memoryHigh || '',
|
|
49
|
+
memoryMax: opts.memoryMax || projectCfg?.resources?.memoryMax || projectCfg?.memoryMax || '',
|
|
50
|
+
memorySwapMax: opts.memorySwapMax || projectCfg?.resources?.memorySwapMax || projectCfg?.memorySwapMax || '',
|
|
51
|
+
...opts,
|
|
52
|
+
env: { ...(projectCfg.env || {}), ...(opts.env || {}) },
|
|
53
|
+
cwd: targetCwd
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { getAdapter } from '../platform/index.js';
|
|
2
|
+
import { readAppMetadata, readScheduleMetadata, sanitizeServiceName } from '../utils.js';
|
|
3
|
+
import { mergeConfigWithOptions } from './config.js';
|
|
4
|
+
import { normalizeServiceConfig } from './normalize.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* ServiceManager orchestrates service operations across platforms.
|
|
8
|
+
*/
|
|
9
|
+
export class ServiceManager {
|
|
10
|
+
/**
|
|
11
|
+
* @param {object} [opts]
|
|
12
|
+
* @param {string} [opts.platform]
|
|
13
|
+
* @param {import('../platform/base.js').ServiceAdapter} [opts.adapter]
|
|
14
|
+
*/
|
|
15
|
+
constructor(opts = {}) {
|
|
16
|
+
this.platformName = opts.platform;
|
|
17
|
+
this._adapter = opts.adapter;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get adapter() {
|
|
21
|
+
return this._adapter || getAdapter(this.platformName);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Gets the platform capabilities.
|
|
26
|
+
*/
|
|
27
|
+
get capabilities() {
|
|
28
|
+
return this.adapter.capabilities;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Generates the native service file/config from options (dry-run mode).
|
|
33
|
+
*
|
|
34
|
+
* @param {object} rawOpts
|
|
35
|
+
* @returns {Promise<string|object>}
|
|
36
|
+
*/
|
|
37
|
+
async generate(rawOpts = {}) {
|
|
38
|
+
const merged = mergeConfigWithOptions(rawOpts);
|
|
39
|
+
const normalized = await normalizeServiceConfig(merged);
|
|
40
|
+
return this.adapter.generateService(normalized);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Installs/registers a service.
|
|
45
|
+
*
|
|
46
|
+
* @param {object} rawOpts
|
|
47
|
+
* @returns {Promise<object>}
|
|
48
|
+
*/
|
|
49
|
+
async install(rawOpts = {}) {
|
|
50
|
+
const merged = mergeConfigWithOptions(rawOpts);
|
|
51
|
+
const normalized = await normalizeServiceConfig(merged);
|
|
52
|
+
return this.adapter.install(normalized, {
|
|
53
|
+
force: !!rawOpts.force,
|
|
54
|
+
start: !!rawOpts.start,
|
|
55
|
+
system: !!rawOpts.system
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Uninstalls/removes a service.
|
|
61
|
+
*
|
|
62
|
+
* @param {string} name
|
|
63
|
+
* @param {object} [options]
|
|
64
|
+
* @returns {Promise<boolean>}
|
|
65
|
+
*/
|
|
66
|
+
async uninstall(name, options = {}) {
|
|
67
|
+
if (name && typeof name === 'string' && name.startsWith('@')) {
|
|
68
|
+
const all = await this.list({ group: name });
|
|
69
|
+
if (all.length === 0) {
|
|
70
|
+
throw new Error(`No services found in group "${name}".`);
|
|
71
|
+
}
|
|
72
|
+
for (const item of all) {
|
|
73
|
+
await this.uninstall(item.name, options);
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
return this.adapter.uninstall(name, options);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Starts a service.
|
|
82
|
+
*
|
|
83
|
+
* @param {string} name
|
|
84
|
+
* @param {object} [options]
|
|
85
|
+
* @returns {Promise<boolean>}
|
|
86
|
+
*/
|
|
87
|
+
async start(name, options = {}) {
|
|
88
|
+
if (name && typeof name === 'string' && name.startsWith('@')) {
|
|
89
|
+
const all = await this.list({ group: name });
|
|
90
|
+
if (all.length === 0) {
|
|
91
|
+
throw new Error(`No services found in group "${name}".`);
|
|
92
|
+
}
|
|
93
|
+
for (const item of all) {
|
|
94
|
+
await this.start(item.name, options);
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return this.adapter.start(name, options);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Stops a service.
|
|
103
|
+
*
|
|
104
|
+
* @param {string} name
|
|
105
|
+
* @param {object} [options]
|
|
106
|
+
* @returns {Promise<boolean>}
|
|
107
|
+
*/
|
|
108
|
+
async stop(name, options = {}) {
|
|
109
|
+
if (name && typeof name === 'string' && name.startsWith('@')) {
|
|
110
|
+
const all = await this.list({ group: name });
|
|
111
|
+
if (all.length === 0) {
|
|
112
|
+
throw new Error(`No services found in group "${name}".`);
|
|
113
|
+
}
|
|
114
|
+
for (const item of all) {
|
|
115
|
+
await this.stop(item.name, options);
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
return this.adapter.stop(name, options);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Restarts a service.
|
|
124
|
+
*
|
|
125
|
+
* @param {string} name
|
|
126
|
+
* @param {object} [options]
|
|
127
|
+
* @returns {Promise<boolean>}
|
|
128
|
+
*/
|
|
129
|
+
async restart(name, options = {}) {
|
|
130
|
+
if (name && typeof name === 'string' && name.startsWith('@')) {
|
|
131
|
+
const all = await this.list({ group: name });
|
|
132
|
+
if (all.length === 0) {
|
|
133
|
+
throw new Error(`No services found in group "${name}".`);
|
|
134
|
+
}
|
|
135
|
+
for (const item of all) {
|
|
136
|
+
await this.restart(item.name, options);
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
return this.adapter.restart(name, options);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Enables a service for automatic startup.
|
|
145
|
+
*
|
|
146
|
+
* @param {string} name
|
|
147
|
+
* @param {object} [options]
|
|
148
|
+
* @returns {Promise<boolean>}
|
|
149
|
+
*/
|
|
150
|
+
async enable(name, options = {}) {
|
|
151
|
+
return this.adapter.enable(name, options);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Disables automatic startup for a service.
|
|
156
|
+
*
|
|
157
|
+
* @param {string} name
|
|
158
|
+
* @param {object} [options]
|
|
159
|
+
* @returns {Promise<boolean>}
|
|
160
|
+
*/
|
|
161
|
+
async disable(name, options = {}) {
|
|
162
|
+
return this.adapter.disable(name, options);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Gets normalized status for a service.
|
|
167
|
+
*
|
|
168
|
+
* @param {string} name
|
|
169
|
+
* @param {object} [options]
|
|
170
|
+
* @returns {Promise<object>}
|
|
171
|
+
*/
|
|
172
|
+
async status(name, options = {}) {
|
|
173
|
+
return this.adapter.status(name, options);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Inspects detailed configuration and runtime info for a service.
|
|
178
|
+
*
|
|
179
|
+
* @param {string} name
|
|
180
|
+
* @param {object} [options]
|
|
181
|
+
* @returns {Promise<object>}
|
|
182
|
+
*/
|
|
183
|
+
async inspect(name, options = {}) {
|
|
184
|
+
return this.adapter.inspect(name, options);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Retrieves or streams logs for a service.
|
|
189
|
+
*
|
|
190
|
+
* @param {string} name
|
|
191
|
+
* @param {object} [options]
|
|
192
|
+
* @returns {Promise<any>}
|
|
193
|
+
*/
|
|
194
|
+
async logs(name, options = {}) {
|
|
195
|
+
return this.adapter.logs(name, options);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Lists all services.
|
|
200
|
+
*
|
|
201
|
+
* @param {object} [options]
|
|
202
|
+
* @returns {Promise<Array<object>>}
|
|
203
|
+
*/
|
|
204
|
+
async list(options = {}) {
|
|
205
|
+
return this.adapter.list(options);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Lists failed services.
|
|
210
|
+
*
|
|
211
|
+
* @param {object} [options]
|
|
212
|
+
* @returns {Promise<Array<object>>}
|
|
213
|
+
*/
|
|
214
|
+
async failures(options = {}) {
|
|
215
|
+
return this.adapter.failures(options);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Checks if a service is installed.
|
|
220
|
+
*
|
|
221
|
+
* @param {string} name
|
|
222
|
+
* @param {object} [options]
|
|
223
|
+
* @returns {Promise<boolean>|boolean}
|
|
224
|
+
*/
|
|
225
|
+
isInstalled(name, options = {}) {
|
|
226
|
+
return this.adapter.isInstalled(name, options);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Default global ServiceManager instance.
|
|
232
|
+
*/
|
|
233
|
+
export const defaultManager = new ServiceManager();
|