unitup 0.1.0 → 0.1.1
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/package.json +1 -1
- package/src/schedule.js +32 -35
- package/src/unit.js +11 -5
- package/src/utils.js +1 -1
package/package.json
CHANGED
package/src/schedule.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
3
4
|
import {
|
|
4
5
|
sanitizeServiceName,
|
|
5
6
|
getUnitFilename,
|
|
@@ -106,42 +107,29 @@ export async function createSchedule(opts = {}) {
|
|
|
106
107
|
|
|
107
108
|
const safeName = sanitizeServiceName(rawName);
|
|
108
109
|
|
|
109
|
-
|
|
110
|
-
let execArgs = [];
|
|
111
|
-
let detectedRuntime = opts.runtime || 'node';
|
|
112
|
-
let scriptPath = '';
|
|
113
|
-
|
|
114
|
-
if (opts.command) {
|
|
115
|
-
commandExec = resolveAbsolutePath(opts.command);
|
|
116
|
-
execArgs = Array.isArray(opts.args) ? opts.args : [];
|
|
117
|
-
if (opts.script) {
|
|
118
|
-
scriptPath = resolveAbsolutePath(opts.script);
|
|
119
|
-
}
|
|
120
|
-
} else if (opts.script) {
|
|
121
|
-
scriptPath = resolveAbsolutePath(opts.script);
|
|
122
|
-
const runtimeInfo = detectRuntime(scriptPath, opts.runtime);
|
|
123
|
-
detectedRuntime = runtimeInfo.runtime;
|
|
124
|
-
|
|
125
|
-
const resolved = await resolveRuntimeConfig({
|
|
126
|
-
runtime: detectedRuntime,
|
|
127
|
-
script: scriptPath,
|
|
128
|
-
command: opts.command,
|
|
129
|
-
args: opts.args || [],
|
|
130
|
-
runtimeArgs: opts.runtimeArgs || [],
|
|
131
|
-
customNodePath: opts.node
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
commandExec = resolved.command;
|
|
135
|
-
execArgs = resolved.args;
|
|
136
|
-
} else {
|
|
110
|
+
if (!opts.script && !opts.command) {
|
|
137
111
|
throw new Error('Either script or command must be provided to create schedule.');
|
|
138
112
|
}
|
|
139
113
|
|
|
114
|
+
const scriptPath = opts.script ? resolveAbsolutePath(opts.script) : '';
|
|
115
|
+
const resolved = await resolveRuntimeConfig({
|
|
116
|
+
runtime: opts.runtime,
|
|
117
|
+
script: scriptPath,
|
|
118
|
+
command: opts.command,
|
|
119
|
+
args: opts.args || [],
|
|
120
|
+
runtimeArgs: opts.runtimeArgs || [],
|
|
121
|
+
customNodePath: opts.node
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const commandExec = resolved.command;
|
|
125
|
+
const execArgs = resolved.args;
|
|
126
|
+
const detectedRuntime = resolved.runtime;
|
|
127
|
+
|
|
140
128
|
const cwd = opts.cwd
|
|
141
129
|
? resolveAbsolutePath(opts.cwd)
|
|
142
130
|
: scriptPath
|
|
143
131
|
? path.dirname(scriptPath)
|
|
144
|
-
:
|
|
132
|
+
: process.cwd();
|
|
145
133
|
|
|
146
134
|
const envObj = {};
|
|
147
135
|
if (opts.env) {
|
|
@@ -333,7 +321,7 @@ export async function getScheduleStatus(name) {
|
|
|
333
321
|
'--user',
|
|
334
322
|
'show',
|
|
335
323
|
timerFilename,
|
|
336
|
-
'--property=ActiveState,SubState,NextElapseUSecRealtime,NextElapseUSec,LastTriggerUSec,Unit,Triggers,UnitFileState'
|
|
324
|
+
'--property=ActiveState,SubState,NextElapseUSecRealtime,NextElapseUSecMonotonic,NextElapseUSec,LastTriggerUSec,Unit,Triggers,UnitFileState'
|
|
337
325
|
]);
|
|
338
326
|
|
|
339
327
|
const showServiceRes = await runCommand('systemctl', [
|
|
@@ -374,18 +362,27 @@ export async function getScheduleStatus(name) {
|
|
|
374
362
|
|
|
375
363
|
// Parse NextElapse timestamp
|
|
376
364
|
let rawNext = timerProps.NextElapseUSecRealtime || timerProps.NextElapseUSec;
|
|
377
|
-
if (!rawNext || rawNext === '0' || rawNext === '18446744073709551615') {
|
|
378
|
-
rawNext = 'n/a';
|
|
379
|
-
}
|
|
380
|
-
|
|
381
365
|
let nextRun = 'n/a';
|
|
382
|
-
|
|
366
|
+
|
|
367
|
+
if (rawNext && rawNext !== '0' && rawNext !== '18446744073709551615') {
|
|
383
368
|
const num = Number(rawNext);
|
|
384
369
|
if (!isNaN(num) && num > 0) {
|
|
385
370
|
nextRun = formatFutureTime(Math.floor(num / 1000));
|
|
386
371
|
} else {
|
|
387
372
|
nextRun = formatFutureTime(rawNext);
|
|
388
373
|
}
|
|
374
|
+
} else if (timerProps.NextElapseUSecMonotonic && timerProps.NextElapseUSecMonotonic !== '0' && timerProps.NextElapseUSecMonotonic !== '18446744073709551615') {
|
|
375
|
+
const monoNum = Number(timerProps.NextElapseUSecMonotonic);
|
|
376
|
+
if (!isNaN(monoNum) && monoNum > 0) {
|
|
377
|
+
const currentMonoUSec = os.uptime() * 1000000;
|
|
378
|
+
const diffUSec = monoNum - currentMonoUSec;
|
|
379
|
+
if (diffUSec > 0) {
|
|
380
|
+
const targetMs = Date.now() + Math.floor(diffUSec / 1000);
|
|
381
|
+
nextRun = formatFutureTime(targetMs);
|
|
382
|
+
} else {
|
|
383
|
+
nextRun = 'imminent';
|
|
384
|
+
}
|
|
385
|
+
}
|
|
389
386
|
}
|
|
390
387
|
|
|
391
388
|
// Parse LastTrigger timestamp
|
package/src/unit.js
CHANGED
|
@@ -83,8 +83,11 @@ export function generateUnitContent(opts) {
|
|
|
83
83
|
throw new Error('Either "command" or "script" must be provided to generate systemd unit file.');
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
const
|
|
87
|
-
|
|
86
|
+
const cwd = opts.cwd
|
|
87
|
+
? resolveAbsolutePath(opts.cwd)
|
|
88
|
+
: opts.script
|
|
89
|
+
? path.dirname(resolveAbsolutePath(opts.script))
|
|
90
|
+
: process.cwd();
|
|
88
91
|
const restartPolicy = opts.restart || 'on-failure';
|
|
89
92
|
|
|
90
93
|
const execStartTokens = [commandExec, ...execArgs];
|
|
@@ -306,8 +309,11 @@ export function generateScheduleServiceContent(opts) {
|
|
|
306
309
|
throw new Error('Either "command" or "script" must be provided to generate scheduled unit file.');
|
|
307
310
|
}
|
|
308
311
|
|
|
309
|
-
const
|
|
310
|
-
|
|
312
|
+
const cwd = opts.cwd
|
|
313
|
+
? resolveAbsolutePath(opts.cwd)
|
|
314
|
+
: opts.script
|
|
315
|
+
? path.dirname(resolveAbsolutePath(opts.script))
|
|
316
|
+
: process.cwd();
|
|
311
317
|
|
|
312
318
|
const execStartTokens = [commandExec, ...execArgs];
|
|
313
319
|
const execStartLine = execStartTokens.map(escapeExecArg).join(' ');
|
|
@@ -440,7 +446,7 @@ export function writeScheduleUnitFiles(opts) {
|
|
|
440
446
|
saveScheduleMetadata({
|
|
441
447
|
name: safeName,
|
|
442
448
|
group: opts.group || 'default',
|
|
443
|
-
runtime: opts.runtime || 'node',
|
|
449
|
+
runtime: opts.runtime || (opts.command ? 'custom' : 'node'),
|
|
444
450
|
command: opts.command,
|
|
445
451
|
args: opts.args,
|
|
446
452
|
cwd: opts.cwd,
|
package/src/utils.js
CHANGED
|
@@ -141,7 +141,7 @@ export function saveAppMetadata(meta) {
|
|
|
141
141
|
const rawArgs = Array.isArray(meta.args) ? meta.args : (meta.script ? [meta.script] : []);
|
|
142
142
|
const args = rawArgs.map(a => (a.startsWith('/') || a.startsWith('./') || a.startsWith('../') || a.startsWith('~/')) ? resolveAbsolutePath(a) : a);
|
|
143
143
|
const scriptPath = meta.script ? resolveAbsolutePath(meta.script) : (args[0] ? resolveAbsolutePath(args[0]) : command);
|
|
144
|
-
const cwd = meta.cwd ? resolveAbsolutePath(meta.cwd) : path.dirname(
|
|
144
|
+
const cwd = meta.cwd ? resolveAbsolutePath(meta.cwd) : (meta.script ? path.dirname(resolveAbsolutePath(meta.script)) : process.cwd());
|
|
145
145
|
|
|
146
146
|
// Extract memory resources if present
|
|
147
147
|
const resources = meta.resources || {};
|