systemd-ts 0.3.1 → 0.3.2

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.
@@ -0,0 +1,106 @@
1
+ import {
2
+ Systemd,
3
+ type CommandExecutionOptions,
4
+ type CommandExecutor,
5
+ type CommandOutput,
6
+ } from "../main/index.ts";
7
+
8
+ import { runGuestCommand, runIsolatedGuestCommand } from "./host.ts";
9
+ import { useCurrentTestSandbox } from "./sandbox.ts";
10
+
11
+ /**
12
+ * Creates a command executor that runs argv-style commands inside the current
13
+ * test host guest shell.
14
+ */
15
+ export function createGuestCommandExecutor(
16
+ runCommand: (script: string) => Promise<string>,
17
+ ): CommandExecutor {
18
+ return async (
19
+ command: string,
20
+ args: readonly string[],
21
+ options: CommandExecutionOptions = {},
22
+ ): Promise<CommandOutput> => {
23
+ try {
24
+ const stdout = await runCommand(buildGuestCommand(command, args, options));
25
+ return {
26
+ stderr: ``,
27
+ stdout,
28
+ };
29
+ } catch (cause) {
30
+ throw enrichGuestCommandError(cause);
31
+ }
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Executor that reuses the warm guest shell for fast sandbox-backed tests.
37
+ */
38
+ export const guestCommandExecutor = createGuestCommandExecutor(runGuestCommand);
39
+
40
+ /**
41
+ * Executor that runs each guest command in a fresh isolated guest shell.
42
+ */
43
+ export const isolatedGuestCommandExecutor = createGuestCommandExecutor(runIsolatedGuestCommand);
44
+
45
+ /**
46
+ * Creates a `Systemd` instance scoped to the active test sandbox and backed by
47
+ * the warm guest-shell executor.
48
+ */
49
+ export function sandboxSystemd(): Systemd {
50
+ const sandbox = useCurrentTestSandbox();
51
+ return new Systemd({
52
+ executor: guestCommandExecutor,
53
+ linkUnits: true,
54
+ scope: `user`,
55
+ unitDir: sandbox.linkedUnitDir,
56
+ });
57
+ }
58
+
59
+ /**
60
+ * Creates a `Systemd` instance scoped to the active test sandbox and backed by
61
+ * a fresh guest shell per command.
62
+ */
63
+ export function isolatedSandboxSystemd(): Systemd {
64
+ const sandbox = useCurrentTestSandbox();
65
+ return new Systemd({
66
+ executor: isolatedGuestCommandExecutor,
67
+ linkUnits: true,
68
+ scope: `user`,
69
+ unitDir: sandbox.linkedUnitDir,
70
+ });
71
+ }
72
+
73
+ function buildGuestCommand(
74
+ command: string,
75
+ args: readonly string[],
76
+ options: CommandExecutionOptions,
77
+ ): string {
78
+ const envArgs =
79
+ options.env === undefined
80
+ ? []
81
+ : Object.entries(options.env).flatMap(([key, value]) =>
82
+ value === undefined ? [`-u`, key] : [`${key}=${value}`],
83
+ );
84
+
85
+ return [`env`, ...envArgs, command, ...args].map((part) => shellQuote(part)).join(` `);
86
+ }
87
+
88
+ function enrichGuestCommandError(cause: unknown): Error {
89
+ if (cause instanceof Error) {
90
+ return Object.assign(cause, {
91
+ code: 1,
92
+ stderr: ``,
93
+ stdout: cause.message,
94
+ });
95
+ }
96
+
97
+ return Object.assign(new Error(`Guest command failed`), {
98
+ code: 1,
99
+ stderr: ``,
100
+ stdout: ``,
101
+ });
102
+ }
103
+
104
+ function shellQuote(value: string): string {
105
+ return `'${value.replaceAll(`'`, `'\\''`)}'`;
106
+ }