lim 0.13.2 → 0.14.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/dist/commands/ios/create.js +1 -1
- package/dist/commands/ios/create.js.map +1 -1
- package/dist/commands/run.d.ts +1 -8
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +22 -121
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/xcode/rbe/install.d.ts +18 -0
- package/dist/commands/xcode/rbe/install.d.ts.map +1 -0
- package/dist/commands/xcode/rbe/install.js +118 -0
- package/dist/commands/xcode/rbe/install.js.map +1 -0
- package/dist/commands/xcode/rbe.d.ts +71 -0
- package/dist/commands/xcode/rbe.d.ts.map +1 -0
- package/dist/commands/xcode/rbe.js +559 -0
- package/dist/commands/xcode/rbe.js.map +1 -0
- package/dist/lib/progress.d.ts +18 -0
- package/dist/lib/progress.d.ts.map +1 -0
- package/dist/lib/progress.js +125 -0
- package/dist/lib/progress.js.map +1 -0
- package/dist/lib/rbe-session.d.ts +72 -0
- package/dist/lib/rbe-session.d.ts.map +1 -0
- package/dist/lib/rbe-session.js +188 -0
- package/dist/lib/rbe-session.js.map +1 -0
- package/dist/lib/rbe-workspace.d.ts +132 -0
- package/dist/lib/rbe-workspace.d.ts.map +1 -0
- package/dist/lib/rbe-workspace.js +356 -0
- package/dist/lib/rbe-workspace.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProgressReporter = void 0;
|
|
4
|
+
const core_1 = require("@oclif/core");
|
|
5
|
+
/**
|
|
6
|
+
* Spinner + checkmark progress reporting on stderr, shared across commands so
|
|
7
|
+
* they all look the same (e.g. `lim run`, `lim xcode rbe`). Renders a live
|
|
8
|
+
* spinner with an optional tail of streamed log lines on a TTY, and prints a
|
|
9
|
+
* green ✔ / red ✖ line on completion. All output is suppressed when the owning
|
|
10
|
+
* command is in --json/--quiet mode (via the injected `suppressed` predicate),
|
|
11
|
+
* and falls back to no-op animation when stderr is not a TTY.
|
|
12
|
+
*/
|
|
13
|
+
const SPINNER_FRAMES = process.platform === 'win32' ? ['-', '\\', '|', '/'] : ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
14
|
+
const SUCCESS_ICON = process.platform === 'win32' ? '√' : '✔';
|
|
15
|
+
const FAILURE_ICON = process.platform === 'win32' ? '×' : '✖';
|
|
16
|
+
const DEFAULT_TAIL_LINES = 10;
|
|
17
|
+
class ProgressReporter {
|
|
18
|
+
constructor(suppressed, opts = {}) {
|
|
19
|
+
this.suppressed = suppressed;
|
|
20
|
+
this.tailLines = opts.tailLines ?? DEFAULT_TAIL_LINES;
|
|
21
|
+
}
|
|
22
|
+
/** Print a standalone green ✔ line (no spinner). */
|
|
23
|
+
success(message) {
|
|
24
|
+
if (this.suppressed()) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
process.stderr.write(`${core_1.ux.colorize('green', SUCCESS_ICON)} ${message}\n`);
|
|
28
|
+
}
|
|
29
|
+
/** Run `fn` under a spinner, resolving to a ✔ (or ✖ on throw). */
|
|
30
|
+
async withProgress(message, fn, successMessage) {
|
|
31
|
+
this.start(message);
|
|
32
|
+
try {
|
|
33
|
+
const result = await fn();
|
|
34
|
+
this.stop('success', successMessage);
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
this.stop('failure');
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
start(message) {
|
|
43
|
+
if (this.suppressed()) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
this.progress = { frame: 0, logLines: [], message, renderedRows: 0 };
|
|
47
|
+
if (process.stderr.isTTY) {
|
|
48
|
+
this.progress.timer = setInterval(() => this.render(), process.platform === 'win32' ? 500 : 100);
|
|
49
|
+
this.progress.timer.unref();
|
|
50
|
+
this.render();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
stop(result = 'success', message) {
|
|
54
|
+
if (this.suppressed() || !this.progress) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const progress = this.progress;
|
|
58
|
+
if (progress.timer) {
|
|
59
|
+
clearInterval(progress.timer);
|
|
60
|
+
}
|
|
61
|
+
this.progress = undefined;
|
|
62
|
+
this.clear(progress);
|
|
63
|
+
const icon = result === 'success' ? core_1.ux.colorize('green', SUCCESS_ICON) : core_1.ux.colorize('red', FAILURE_ICON);
|
|
64
|
+
process.stderr.write(`${icon} ${message ?? progress.message}\n`);
|
|
65
|
+
}
|
|
66
|
+
appendLog(chunk) {
|
|
67
|
+
if (this.suppressed() || !this.progress) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const lines = String(chunk)
|
|
71
|
+
.replace(/\r/g, '\n')
|
|
72
|
+
.split('\n')
|
|
73
|
+
.map((line) => line.trimEnd())
|
|
74
|
+
.filter((line) => line.length > 0);
|
|
75
|
+
if (lines.length === 0) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.progress.logLines.push(...lines);
|
|
79
|
+
this.progress.logLines = this.progress.logLines.slice(-this.tailLines);
|
|
80
|
+
this.render();
|
|
81
|
+
}
|
|
82
|
+
render() {
|
|
83
|
+
if (!this.progress || !process.stderr.isTTY) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const frame = SPINNER_FRAMES[this.progress.frame % SPINNER_FRAMES.length];
|
|
87
|
+
this.progress.frame += 1;
|
|
88
|
+
const lines = [
|
|
89
|
+
progressLine(`${core_1.ux.colorize('magenta', frame)} ${this.progress.message}`),
|
|
90
|
+
...this.progress.logLines.map((line) => core_1.ux.colorize('dim', ` ${truncateTerminalLine(line, 2)}`)),
|
|
91
|
+
];
|
|
92
|
+
this.clear(this.progress);
|
|
93
|
+
this.progress.renderedRows = lines.length;
|
|
94
|
+
process.stderr.write(lines.join('\n'));
|
|
95
|
+
}
|
|
96
|
+
clear(progress) {
|
|
97
|
+
if (!process.stderr.isTTY) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
process.stderr.clearLine(0);
|
|
101
|
+
process.stderr.cursorTo(0);
|
|
102
|
+
for (let i = 1; i < progress.renderedRows; i += 1) {
|
|
103
|
+
process.stderr.moveCursor(0, -1);
|
|
104
|
+
process.stderr.clearLine(0);
|
|
105
|
+
process.stderr.cursorTo(0);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.ProgressReporter = ProgressReporter;
|
|
110
|
+
function progressLine(line) {
|
|
111
|
+
const width = process.stderr.columns;
|
|
112
|
+
if (!width || line.length < width - 1) {
|
|
113
|
+
return line;
|
|
114
|
+
}
|
|
115
|
+
return `${line.slice(0, Math.max(0, width - 4))}...`;
|
|
116
|
+
}
|
|
117
|
+
function truncateTerminalLine(line, indent = 0) {
|
|
118
|
+
const width = process.stderr.columns;
|
|
119
|
+
const max = width ? width - indent - 1 : undefined;
|
|
120
|
+
if (!max || line.length < max) {
|
|
121
|
+
return line;
|
|
122
|
+
}
|
|
123
|
+
return `${line.slice(0, Math.max(0, max - 3))}...`;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/lib/progress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { RbeStatus, XcodeClient } from '@limrun/api';
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic, side-effect-light helpers behind `lim xcode rbe`, extracted
|
|
4
|
+
* from the command so they can be unit-tested without the oclif lifecycle.
|
|
5
|
+
*/
|
|
6
|
+
export type Sleep = (ms: number) => Promise<void>;
|
|
7
|
+
export declare const defaultSleep: Sleep;
|
|
8
|
+
export declare function isTransientError(err: unknown): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Retries `fn` on transient gateway errors. Non-transient errors propagate
|
|
11
|
+
* immediately. After exhausting `attempts`, throws the last error.
|
|
12
|
+
*/
|
|
13
|
+
export declare function retryTransient<T>(fn: () => Promise<T>, opts?: {
|
|
14
|
+
sleep?: Sleep;
|
|
15
|
+
log?: (msg: string) => void;
|
|
16
|
+
attempts?: number;
|
|
17
|
+
}): Promise<T>;
|
|
18
|
+
/**
|
|
19
|
+
* Polls `getRbe` until the stack is `running` (with a usable frontend port and
|
|
20
|
+
* Xcode version), starting from the `initial` status returned by `startRbe`.
|
|
21
|
+
* Each poll is wrapped in retryTransient so a transient blip mid-startup does
|
|
22
|
+
* not abort. Throws when the stack ends in `failed`, stays `starting` past
|
|
23
|
+
* `maxAttempts`, or reports `running` without the fields the caller needs.
|
|
24
|
+
*/
|
|
25
|
+
export declare function waitForRbeRunning(client: Pick<XcodeClient, 'getRbe'>, initial: RbeStatus, opts?: {
|
|
26
|
+
sleep?: Sleep;
|
|
27
|
+
maxAttempts?: number;
|
|
28
|
+
}): Promise<Required<Pick<RbeStatus, 'frontendPort' | 'xcodeVersion'>> & RbeStatus>;
|
|
29
|
+
/**
|
|
30
|
+
* Builds the argv for the detached child that holds the tunnel: re-invokes this
|
|
31
|
+
* same CLI as `xcode rbe --serve --id <id> --port <port> [--api-key <key>]`.
|
|
32
|
+
* `scriptPath` is the CLI entry (process.argv[1]).
|
|
33
|
+
*/
|
|
34
|
+
export declare function buildServeChildArgs(opts: {
|
|
35
|
+
scriptPath: string;
|
|
36
|
+
id: string;
|
|
37
|
+
port: number;
|
|
38
|
+
apiKey?: string;
|
|
39
|
+
}): string[];
|
|
40
|
+
/**
|
|
41
|
+
* A running background tunnel's coordinates, persisted to `.limrun/rbe.pid` so
|
|
42
|
+
* `lim xcode rbe --stop` can find and stop it (adb prints the PID and forgets
|
|
43
|
+
* it; we keep just enough to offer a discoverable stop). Lives under `.limrun/`,
|
|
44
|
+
* which is self-gitignored.
|
|
45
|
+
*/
|
|
46
|
+
export type RbePidInfo = {
|
|
47
|
+
pid: number;
|
|
48
|
+
instanceId: string;
|
|
49
|
+
port: number;
|
|
50
|
+
/** iOS simulator created by `--ios`, torn down on --stop. Absent otherwise. */
|
|
51
|
+
simInstanceId?: string;
|
|
52
|
+
};
|
|
53
|
+
export declare function rbePidFilePath(workspaceRoot: string): string;
|
|
54
|
+
export declare function writeRbePidFile(workspaceRoot: string, info: RbePidInfo): void;
|
|
55
|
+
export declare function readRbePidFile(workspaceRoot: string): RbePidInfo | null;
|
|
56
|
+
export declare function clearRbePidFile(workspaceRoot: string): void;
|
|
57
|
+
/** Whether `pid` is a live process (treats EPERM — owned by another user — as alive). */
|
|
58
|
+
export declare function isProcessAlive(pid: number): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Resolves when `port` on `host` is bindable; rejects with a friendly message
|
|
61
|
+
* when it is already in use, or with the raw error otherwise. Frees the port
|
|
62
|
+
* immediately (the probe listener is closed before resolving).
|
|
63
|
+
*/
|
|
64
|
+
export declare function assertLocalPortFree(port: number, host?: string): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Resolves true if a TCP connection to `host:port` is accepted (something is
|
|
67
|
+
* listening), false otherwise (connection refused, error, or no answer within
|
|
68
|
+
* `timeoutMs`). The timeout only bites when a connect neither completes nor is
|
|
69
|
+
* refused (a dropped SYN); on loopback a closed port refuses instantly.
|
|
70
|
+
*/
|
|
71
|
+
export declare function probePortOpen(port: number, host?: string, timeoutMs?: number): Promise<boolean>;
|
|
72
|
+
//# sourceMappingURL=rbe-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rbe-session.d.ts","sourceRoot":"","sources":["../../src/lib/rbe-session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1D;;;GAGG;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAClD,eAAO,MAAM,YAAY,EAAE,KAAiE,CAAC;AAc7F,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGtD;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,KAAK,CAAC;IAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3E,OAAO,CAAC,CAAC,CAAC,CAoBZ;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,EACnC,OAAO,EAAE,SAAS,EAClB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,KAAK,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,GAAG,cAAc,CAAC,CAAC,GAAG,SAAS,CAAC,CAYjF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,EAAE,CAoBX;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAE7E;AAED,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAUvE;AAED,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAM3D;AAED,yFAAyF;AACzF,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,SAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAezF;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,SAAc,EAAE,SAAS,SAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAajG"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.defaultSleep = void 0;
|
|
7
|
+
exports.isTransientError = isTransientError;
|
|
8
|
+
exports.retryTransient = retryTransient;
|
|
9
|
+
exports.waitForRbeRunning = waitForRbeRunning;
|
|
10
|
+
exports.buildServeChildArgs = buildServeChildArgs;
|
|
11
|
+
exports.rbePidFilePath = rbePidFilePath;
|
|
12
|
+
exports.writeRbePidFile = writeRbePidFile;
|
|
13
|
+
exports.readRbePidFile = readRbePidFile;
|
|
14
|
+
exports.clearRbePidFile = clearRbePidFile;
|
|
15
|
+
exports.isProcessAlive = isProcessAlive;
|
|
16
|
+
exports.assertLocalPortFree = assertLocalPortFree;
|
|
17
|
+
exports.probePortOpen = probePortOpen;
|
|
18
|
+
const fs_1 = __importDefault(require("fs"));
|
|
19
|
+
const net_1 = __importDefault(require("net"));
|
|
20
|
+
const path_1 = __importDefault(require("path"));
|
|
21
|
+
const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
22
|
+
exports.defaultSleep = defaultSleep;
|
|
23
|
+
/**
|
|
24
|
+
* Matches the transient gateway / dropped-connection errors that occur right
|
|
25
|
+
* after an instance is created, when its proxy path is not fully serving yet.
|
|
26
|
+
*
|
|
27
|
+
* The HTTP part anchors on the exact `failed: <code>` shape `directInstanceHttpError`
|
|
28
|
+
* produces (`${operation} failed: ${status}...`), so a bare 502/503/504 buried in
|
|
29
|
+
* a response body or an instance id does NOT count as transient. Fetch-thrown
|
|
30
|
+
* network errors carry their own names and are matched directly. A 404 never
|
|
31
|
+
* reaches here — `readRbeResponse` maps it to RbeUnsupportedError first.
|
|
32
|
+
*/
|
|
33
|
+
const TRANSIENT = /failed: (?:502|503|504)\b|\bEOF\b|ECONNRESET|ECONNREFUSED|socket hang up|fetch failed/i;
|
|
34
|
+
function isTransientError(err) {
|
|
35
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
36
|
+
return TRANSIENT.test(message);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Retries `fn` on transient gateway errors. Non-transient errors propagate
|
|
40
|
+
* immediately. After exhausting `attempts`, throws the last error.
|
|
41
|
+
*/
|
|
42
|
+
async function retryTransient(fn, opts = {}) {
|
|
43
|
+
const sleep = opts.sleep ?? exports.defaultSleep;
|
|
44
|
+
const attempts = opts.attempts ?? 5;
|
|
45
|
+
let lastErr;
|
|
46
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
47
|
+
try {
|
|
48
|
+
return await fn();
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (!isTransientError(err)) {
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
lastErr = err;
|
|
55
|
+
if (attempt < attempts) {
|
|
56
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
57
|
+
opts.log?.(`Instance not serving yet (${message.trim()}); retrying...`);
|
|
58
|
+
await sleep(2000 * attempt);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
throw lastErr;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Polls `getRbe` until the stack is `running` (with a usable frontend port and
|
|
66
|
+
* Xcode version), starting from the `initial` status returned by `startRbe`.
|
|
67
|
+
* Each poll is wrapped in retryTransient so a transient blip mid-startup does
|
|
68
|
+
* not abort. Throws when the stack ends in `failed`, stays `starting` past
|
|
69
|
+
* `maxAttempts`, or reports `running` without the fields the caller needs.
|
|
70
|
+
*/
|
|
71
|
+
async function waitForRbeRunning(client, initial, opts = {}) {
|
|
72
|
+
const sleep = opts.sleep ?? exports.defaultSleep;
|
|
73
|
+
const maxAttempts = opts.maxAttempts ?? 15;
|
|
74
|
+
let status = initial;
|
|
75
|
+
for (let attempt = 0; status.state === 'starting' && attempt < maxAttempts; attempt++) {
|
|
76
|
+
await sleep(2000);
|
|
77
|
+
status = await retryTransient(() => client.getRbe(), { sleep });
|
|
78
|
+
}
|
|
79
|
+
if (status.state !== 'running' || !status.frontendPort || !status.xcodeVersion) {
|
|
80
|
+
throw new Error(`Remote-execution stack failed to start: ${status.error ?? `state is ${status.state}`}`);
|
|
81
|
+
}
|
|
82
|
+
return status;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Builds the argv for the detached child that holds the tunnel: re-invokes this
|
|
86
|
+
* same CLI as `xcode rbe --serve --id <id> --port <port> [--api-key <key>]`.
|
|
87
|
+
* `scriptPath` is the CLI entry (process.argv[1]).
|
|
88
|
+
*/
|
|
89
|
+
function buildServeChildArgs(opts) {
|
|
90
|
+
// --no-create: the child must never own instance creation. The parent already
|
|
91
|
+
// resolved/created the instance and started RBE on it; if that instance has
|
|
92
|
+
// vanished by the time the child resolves it, the child should fail cleanly
|
|
93
|
+
// rather than spin up a stray instance the parent never started a stack on.
|
|
94
|
+
const args = [
|
|
95
|
+
opts.scriptPath,
|
|
96
|
+
'xcode',
|
|
97
|
+
'rbe',
|
|
98
|
+
'--serve',
|
|
99
|
+
'--no-create',
|
|
100
|
+
'--id',
|
|
101
|
+
opts.id,
|
|
102
|
+
'--port',
|
|
103
|
+
String(opts.port),
|
|
104
|
+
];
|
|
105
|
+
if (opts.apiKey) {
|
|
106
|
+
args.push('--api-key', opts.apiKey);
|
|
107
|
+
}
|
|
108
|
+
return args;
|
|
109
|
+
}
|
|
110
|
+
function rbePidFilePath(workspaceRoot) {
|
|
111
|
+
return path_1.default.join(workspaceRoot, '.limrun', 'rbe.pid');
|
|
112
|
+
}
|
|
113
|
+
function writeRbePidFile(workspaceRoot, info) {
|
|
114
|
+
fs_1.default.writeFileSync(rbePidFilePath(workspaceRoot), JSON.stringify(info));
|
|
115
|
+
}
|
|
116
|
+
function readRbePidFile(workspaceRoot) {
|
|
117
|
+
try {
|
|
118
|
+
const parsed = JSON.parse(fs_1.default.readFileSync(rbePidFilePath(workspaceRoot), 'utf8'));
|
|
119
|
+
if (parsed && typeof parsed.pid === 'number') {
|
|
120
|
+
return parsed;
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function clearRbePidFile(workspaceRoot) {
|
|
129
|
+
try {
|
|
130
|
+
fs_1.default.unlinkSync(rbePidFilePath(workspaceRoot));
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// already gone
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** Whether `pid` is a live process (treats EPERM — owned by another user — as alive). */
|
|
137
|
+
function isProcessAlive(pid) {
|
|
138
|
+
try {
|
|
139
|
+
process.kill(pid, 0);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
return err.code === 'EPERM';
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Resolves when `port` on `host` is bindable; rejects with a friendly message
|
|
148
|
+
* when it is already in use, or with the raw error otherwise. Frees the port
|
|
149
|
+
* immediately (the probe listener is closed before resolving).
|
|
150
|
+
*/
|
|
151
|
+
async function assertLocalPortFree(port, host = '127.0.0.1') {
|
|
152
|
+
await new Promise((resolve, reject) => {
|
|
153
|
+
const probe = net_1.default.createServer();
|
|
154
|
+
probe.once('error', (err) => {
|
|
155
|
+
if (err.code === 'EADDRINUSE') {
|
|
156
|
+
reject(new Error(`Local port ${port} is already in use. Pass --port to choose another.`));
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
reject(err);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
probe.once('listening', () => {
|
|
163
|
+
probe.close(() => resolve());
|
|
164
|
+
});
|
|
165
|
+
probe.listen(port, host);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Resolves true if a TCP connection to `host:port` is accepted (something is
|
|
170
|
+
* listening), false otherwise (connection refused, error, or no answer within
|
|
171
|
+
* `timeoutMs`). The timeout only bites when a connect neither completes nor is
|
|
172
|
+
* refused (a dropped SYN); on loopback a closed port refuses instantly.
|
|
173
|
+
*/
|
|
174
|
+
function probePortOpen(port, host = '127.0.0.1', timeoutMs = 500) {
|
|
175
|
+
return new Promise((resolve) => {
|
|
176
|
+
const socket = new net_1.default.Socket();
|
|
177
|
+
const done = (open) => {
|
|
178
|
+
socket.destroy();
|
|
179
|
+
resolve(open);
|
|
180
|
+
};
|
|
181
|
+
socket.setTimeout(timeoutMs);
|
|
182
|
+
socket.once('connect', () => done(true));
|
|
183
|
+
socket.once('timeout', () => done(false));
|
|
184
|
+
socket.once('error', () => done(false));
|
|
185
|
+
socket.connect(port, host);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=rbe-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rbe-session.js","sourceRoot":"","sources":["../../src/lib/rbe-session.ts"],"names":[],"mappings":";;;;;;AAyBA,4CAGC;AAMD,wCAuBC;AASD,8CAgBC;AAOD,kDAyBC;AAgBD,wCAEC;AAED,0CAEC;AAED,wCAUC;AAED,0CAMC;AAGD,wCAOC;AAOD,kDAeC;AAQD,sCAaC;AAjND,4CAAoB;AACpB,8CAAsB;AACtB,gDAAwB;AASjB,MAAM,YAAY,GAAU,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAAhF,QAAA,YAAY,gBAAoE;AAE7F;;;;;;;;;GASG;AACH,MAAM,SAAS,GAAG,wFAAwF,CAAC;AAE3G,SAAgB,gBAAgB,CAAC,GAAY;IAC3C,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,cAAc,CAClC,EAAoB,EACpB,OAA0E,EAAE;IAE5E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,oBAAY,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;IACpC,IAAI,OAAgB,CAAC;IACrB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC;QACrD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC3B,MAAM,GAAG,CAAC;YACZ,CAAC;YACD,OAAO,GAAG,GAAG,CAAC;YACd,IAAI,OAAO,GAAG,QAAQ,EAAE,CAAC;gBACvB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjE,IAAI,CAAC,GAAG,EAAE,CAAC,6BAA6B,OAAO,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;gBACxE,MAAM,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,OAAO,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,iBAAiB,CACrC,MAAmC,EACnC,OAAkB,EAClB,OAAgD,EAAE;IAElD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,oBAAY,CAAC;IACzC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;IAC3C,IAAI,MAAM,GAAG,OAAO,CAAC;IACrB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,MAAM,CAAC,KAAK,KAAK,UAAU,IAAI,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACtF,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;QAClB,MAAM,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QAC/E,MAAM,IAAI,KAAK,CAAC,2CAA2C,MAAM,CAAC,KAAK,IAAI,YAAY,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3G,CAAC;IACD,OAAO,MAAgF,CAAC;AAC1F,CAAC;AAED;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,IAKnC;IACC,8EAA8E;IAC9E,4EAA4E;IAC5E,4EAA4E;IAC5E,4EAA4E;IAC5E,MAAM,IAAI,GAAG;QACX,IAAI,CAAC,UAAU;QACf,OAAO;QACP,KAAK;QACL,SAAS;QACT,aAAa;QACb,MAAM;QACN,IAAI,CAAC,EAAE;QACP,QAAQ;QACR,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;KAClB,CAAC;IACF,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAgBD,SAAgB,cAAc,CAAC,aAAqB;IAClD,OAAO,cAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;AACxD,CAAC;AAED,SAAgB,eAAe,CAAC,aAAqB,EAAE,IAAgB;IACrE,YAAE,CAAC,aAAa,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,SAAgB,cAAc,CAAC,aAAqB;IAClD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAClF,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC7C,OAAO,MAAoB,CAAC;QAC9B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAgB,eAAe,CAAC,aAAqB;IACnD,IAAI,CAAC;QACH,YAAE,CAAC,UAAU,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;AACH,CAAC;AAED,yFAAyF;AACzF,SAAgB,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAQ,GAA6B,CAAC,IAAI,KAAK,OAAO,CAAC;IACzD,CAAC;AACH,CAAC;AAED;;;;GAIG;AACI,KAAK,UAAU,mBAAmB,CAAC,IAAY,EAAE,IAAI,GAAG,WAAW;IACxE,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,KAAK,GAAG,aAAG,CAAC,YAAY,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;YACjD,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,cAAc,IAAI,oDAAoD,CAAC,CAAC,CAAC;YAC5F,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;YAC3B,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,IAAY,EAAE,IAAI,GAAG,WAAW,EAAE,SAAS,GAAG,GAAG;IAC7E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,IAAI,aAAG,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,CAAC,IAAa,EAAE,EAAE;YAC7B,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC;QACF,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates the .limrun/ workspace companion for `lim xcode rbe`: a Bazel
|
|
3
|
+
* package pinning the remote fleet's Xcode version and an rc fragment with the
|
|
4
|
+
* remote-execution flags under the `limrun` config. The caller learns the
|
|
5
|
+
* fleet's version key from the instance's RBE status, so the generated config
|
|
6
|
+
* always matches the fleet without any user action; rerunning the command
|
|
7
|
+
* after a fleet Xcode upgrade regenerates the pin.
|
|
8
|
+
*/
|
|
9
|
+
export declare const LIMRUN_DIR = ".limrun";
|
|
10
|
+
export declare const TRY_IMPORT_LINE = "try-import %workspace%/.limrun/bazelrc";
|
|
11
|
+
/**
|
|
12
|
+
* Finds the Bazel workspace root by walking up from `startDir` to the first
|
|
13
|
+
* ancestor containing a MODULE.bazel / WORKSPACE / WORKSPACE.bazel, mirroring
|
|
14
|
+
* how Bazel itself locates the workspace when run from a subdirectory. Returns
|
|
15
|
+
* null when no workspace is found up to the filesystem root. The generated
|
|
16
|
+
* `.limrun/` and the `try-import` must live at this root, since `%workspace%`
|
|
17
|
+
* in bazelrc resolves here regardless of the directory the build is run from.
|
|
18
|
+
*/
|
|
19
|
+
export declare function findBazelWorkspaceRoot(startDir: string): string | null;
|
|
20
|
+
/**
|
|
21
|
+
* Best-effort guess of a single buildable app target to show in the printed
|
|
22
|
+
* build command, so it reads `//App` instead of a `//your:target` placeholder.
|
|
23
|
+
* Scans the workspace's BUILD files (buildifier-formatted) for apple
|
|
24
|
+
* `*_application` rules — no bazel invocation — and returns the label in short
|
|
25
|
+
* form (`//pkg` when the target name matches the package's last segment).
|
|
26
|
+
* Returns null when there are zero or multiple candidates (ambiguous → caller
|
|
27
|
+
* keeps the placeholder).
|
|
28
|
+
*/
|
|
29
|
+
export declare function inferBuildTarget(workspaceRoot: string): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Reads the workspace's pinned Bazel major version from `.bazelversion`, or
|
|
32
|
+
* null when the file is absent or its first line has no leading integer.
|
|
33
|
+
*
|
|
34
|
+
* Used to decide whether the generated BUILD must `load` the Xcode rules from
|
|
35
|
+
* apple_support: in Bazel 9 they are no longer native globals and must be
|
|
36
|
+
* loaded, while in Bazel 8 they ARE native globals and the apple_support rule
|
|
37
|
+
* impls `fail()` on the unmigrated Bazel, so loading them there breaks
|
|
38
|
+
* analysis. The generator runs in the workspace on the client, so the file is
|
|
39
|
+
* the authoritative signal for the Bazel that bazelisk will launch.
|
|
40
|
+
*/
|
|
41
|
+
export declare function detectBazelMajorVersion(workspaceDir: string): number | null;
|
|
42
|
+
/**
|
|
43
|
+
* Whether to treat the workspace as Bazel 9+ for RBE config: true when the
|
|
44
|
+
* detected major version is >= 9, OR unknown (no `.bazelversion` means bazelisk
|
|
45
|
+
* runs the latest release, which is 9+). This single predicate decides both
|
|
46
|
+
* emitting the apple_support Xcode-rule loads and surfacing the SHA256 digest
|
|
47
|
+
* hint, so the two stay in lockstep.
|
|
48
|
+
*/
|
|
49
|
+
export declare function isBazel9OrLater(bazelMajor: number | null): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Renders the generated Bazel package pinning the Xcode version to the fleet's.
|
|
52
|
+
*
|
|
53
|
+
* remoteVersionKey is the fleet's `xcodebuild -version` in major.minor.patch.build
|
|
54
|
+
* form (e.g. 26.4.0.17E192).
|
|
55
|
+
*
|
|
56
|
+
* Uses Bazel's remote/local `xcode_config` split with BOTH sets pointing at the
|
|
57
|
+
* SAME fleet pin (rather than a single `default=/versions=` bucket, which
|
|
58
|
+
* resolves with availability UNKNOWN and leaves Apple/Swift actions eligible for
|
|
59
|
+
* local execution). With local == remote, `--xcode_version` resolves as
|
|
60
|
+
* "mutually available" (BOTH), which declares up front that this build uses only
|
|
61
|
+
* the fleet's Xcode AND keeps apple_support from emitting its remote-only
|
|
62
|
+
* "...specified, but it is not available locally..." DEBUG notice (that notice
|
|
63
|
+
* fires only when the pinned version is in `remote_versions` but not
|
|
64
|
+
* `local_versions`).
|
|
65
|
+
*
|
|
66
|
+
* We intentionally do NOT name the client's own local Xcode: under
|
|
67
|
+
* `--config=limrun` every action runs remotely (`--spawn_strategy=remote` +
|
|
68
|
+
* `--noremote_local_fallback`), so a local DEVELOPER_DIR is never resolved.
|
|
69
|
+
* Declaring a distinct local version would only reintroduce that DEBUG notice on
|
|
70
|
+
* a client whose Xcode differs from the fleet's. (The fleet pin is used, not
|
|
71
|
+
* Bazel's `@local_config_xcode//:host_available_xcodes`: that repo is not
|
|
72
|
+
* visible from the main module under bzlmod and is never generated off-darwin.)
|
|
73
|
+
*
|
|
74
|
+
* When `emitLoads` is true (Bazel 9+), the Xcode rules are loaded from
|
|
75
|
+
* apple_support; on Bazel 8 they are native globals and MUST NOT be loaded
|
|
76
|
+
* (the apple_support rule impls fail on the unmigrated Bazel).
|
|
77
|
+
*/
|
|
78
|
+
export declare function renderXcodeConfigBuild(remoteVersionKey: string, emitLoads: boolean): string;
|
|
79
|
+
/**
|
|
80
|
+
* Renders the rc fragment with the remote-execution flags under
|
|
81
|
+
* --config=limrun.
|
|
82
|
+
*
|
|
83
|
+
* - `--xcode_version` pins the fleet's version: without it, a mac client
|
|
84
|
+
* lacking that exact version has no mutual version and silently falls back
|
|
85
|
+
* to its LOCAL default, shipping the wrong version to the remote worker via
|
|
86
|
+
* XCODE_VERSION_OVERRIDE (the worker then rejects it).
|
|
87
|
+
* - `--strategy=SwiftCompile=remote` / `--strategy=Genrule=remote` override
|
|
88
|
+
* mnemonic-specific strategies a workspace may pin (rules_swift defaults
|
|
89
|
+
* SwiftCompile to a local persistent `worker`; repos often pin Genrule to
|
|
90
|
+
* `standalone`). Those run locally and break RBE: a local Swift worker can't
|
|
91
|
+
* run on a Linux client at all, and on a mac it would demand the fleet's
|
|
92
|
+
* Xcode locally. --spawn_strategy=remote does not override per-mnemonic
|
|
93
|
+
* pins, so these explicit overrides are required.
|
|
94
|
+
* - PATH includes /usr/sbin:/sbin so genrules that probe `sysctl` (e.g.
|
|
95
|
+
* `hw.logicalcpu` for `make -j`) resolve it on the worker.
|
|
96
|
+
* - `--remote_download_outputs=minimal` keeps build outputs (the .ipa) in the
|
|
97
|
+
* instance's CAS instead of downloading them to the client. `lim xcode rbe
|
|
98
|
+
* install` then installs the artifact on the attached simulator server-side
|
|
99
|
+
* (fast diff-sync), so the bytes never round-trip — pointless on a Linux
|
|
100
|
+
* client, and the artifact is produced in the instance anyway. Scoped to
|
|
101
|
+
* --config=limrun, so a plain `bazel build` still materializes outputs.
|
|
102
|
+
* - `--build_event_json_file` writes the Build Event Protocol to .limrun/bep.json;
|
|
103
|
+
* `lim xcode rbe install` reads the built target's .ipa CAS digest from it. The
|
|
104
|
+
* path is ABSOLUTE on purpose: Bazel expands `%workspace%` only in
|
|
105
|
+
* import/try-import, NOT in flag values (it would be taken literally and create
|
|
106
|
+
* a junk `%workspace%/` dir), and a relative path resolves against bazel's cwd
|
|
107
|
+
* rather than the workspace root.
|
|
108
|
+
* - `--extra_execution_platforms` is emitted ONLY for non-mac clients: a Linux
|
|
109
|
+
* host has no auto-detected darwin execution platform, so the Apple/Swift
|
|
110
|
+
* toolchain (exec_compatible_with macos) needs one registered to route
|
|
111
|
+
* actions to the mac RBE pool. On a mac it is HARMFUL: it makes bazel run
|
|
112
|
+
* exec-config actions on the local host instead of the remote worker, which
|
|
113
|
+
* then demand a local Xcode.
|
|
114
|
+
*/
|
|
115
|
+
export declare function renderLimrunBazelrc(port: number, versionKey: string, isMacClient: boolean, bepPath: string): string;
|
|
116
|
+
/**
|
|
117
|
+
* Idempotently ensures the workspace .bazelrc try-imports the generated
|
|
118
|
+
* fragment. Creates .bazelrc when missing. Returns true when the file changed.
|
|
119
|
+
*/
|
|
120
|
+
export declare function ensureTryImport(workspaceDir: string): boolean;
|
|
121
|
+
export type RbeWorkspaceFiles = {
|
|
122
|
+
buildFile: string;
|
|
123
|
+
bazelrcFragment: string;
|
|
124
|
+
bazelrcUpdated: boolean;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Writes .limrun/{BUILD,bazelrc,.gitignore} into the workspace and wires the
|
|
128
|
+
* try-import. The .gitignore containing "*" makes the directory self-ignoring
|
|
129
|
+
* so nothing else in the user's repo needs to change.
|
|
130
|
+
*/
|
|
131
|
+
export declare function writeRbeWorkspaceFiles(workspaceDir: string, xcodeVersionKey: string, port: number, isMacClient?: boolean, bazelMajor?: number | null): RbeWorkspaceFiles;
|
|
132
|
+
//# sourceMappingURL=rbe-workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rbe-workspace.d.ts","sourceRoot":"","sources":["../../src/lib/rbe-workspace.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,eAAO,MAAM,UAAU,YAAY,CAAC;AACpC,eAAO,MAAM,eAAe,2CAA2C,CAAC;AAKxE;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYtE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAqBrE;AAqCD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS3E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAElE;AA6CD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,sBAAsB,CAAC,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAmC3F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,EACpB,OAAO,EAAE,MAAM,GACd,MAAM,CAkBR;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAiB7D;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,MAAM,EACZ,WAAW,GAAE,OAAuC,EACpD,UAAU,GAAE,MAAM,GAAG,IAA4C,GAChE,iBAAiB,CAkBnB"}
|