Repository navigation
Expand file tree
/
Copy pathplatform-runtime-host.ts
More file actions
93 lines (89 loc) · 3.41 KB
/
Copy pathplatform-runtime-host.ts
File metadata and controls
93 lines (89 loc) · 3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import type { HostEnvironment } from '@agent-device/kernel/source-value';
import type {
DeviceInventoryHost,
HostOperatingSystem,
HostCommandRequest,
HostTemporaryTextFile,
} from '@agent-device/contracts/platform-runtime-host';
import type { DeviceInfo } from '@agent-device/kernel/device';
import { constants } from 'node:fs';
import { access, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { createAppleToolHost } from './platform-runtime-apple-tool-host.ts';
import { createHostToolchainPreparer } from './platform-runtime-toolchain-host.ts';
import { runCmd, whichCmd } from '@agent-device/host-kit/command';
import { guardedHostCommandArgv } from './platform-runtime-host-device-shell.ts';
import { hostHomeDirectoryFromEnv } from '@agent-device/host-kit/host-file';
export function createDeviceInventoryHost(host: HostEnvironment): DeviceInventoryHost {
const env = host.env;
return Object.freeze({
commands: Object.freeze({
which: async (executable: string) =>
(await whichCmd(executable, env)) ? executable : undefined,
run: async (request: HostCommandRequest, signal?: AbortSignal) => {
const result = await runCmd(request.executable, guardedHostCommandArgv(request), {
allowFailure: request.allowFailure,
cwd: request.cwd,
env: request.env ? { ...env, ...request.env } : undefined,
signal,
timeoutMs: request.timeoutMs,
});
return {
stdout: result.stdout,
stderr: result.stderr,
exitCode: result.exitCode,
};
},
}),
appleTools: createAppleToolHost(),
toolchains: createHostToolchainPreparer(env),
files: Object.freeze({
isExecutable: async (candidate: string) => await isExecutable(candidate),
createTemporaryTextFile: async (options: { prefix: string; suffix: string }) =>
await createTemporaryTextFile(options),
}),
hostOs: hostOperatingSystem(process.platform),
hostName: os.hostname(),
// The host names its own home; families derive default-install paths from it (#3794).
homeDirectory: hostHomeDirectoryFromEnv(env),
observations: Object.freeze({
deviceBooted: async (device: DeviceInfo) => {
const { markSimulatorBooted } = await import('@agent-device/platform-apple/simulator');
markSimulatorBooted(device);
},
}),
});
}
function hostOperatingSystem(platform: NodeJS.Platform): HostOperatingSystem {
if (platform === 'darwin' || platform === 'linux' || platform === 'win32') return platform;
return 'other';
}
async function isExecutable(candidate: string): Promise<boolean> {
try {
await access(candidate, constants.X_OK);
return true;
} catch {
return false;
}
}
export async function createTemporaryTextFile(
options: Readonly<{
prefix: string;
suffix: string;
}>,
): Promise<HostTemporaryTextFile> {
const directory = await mkdtemp(path.join(os.tmpdir(), options.prefix));
const filePath = path.join(directory, `value${options.suffix}`);
let disposed = false;
return {
path: filePath,
readText: async () => await readFile(filePath, 'utf8'),
writeText: async (value: string) => await writeFile(filePath, value, 'utf8'),
[Symbol.asyncDispose]: async () => {
if (disposed) return;
disposed = true;
await rm(directory, { recursive: true, force: true });
},
};
}