bun-workspaces 1.0.0-alpha.3 → 1.0.0-alpha.30
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/LICENSE.md +1 -1
- package/README.md +131 -77
- package/bin/cli.js +1 -2
- package/package.json +24 -30
- package/src/cli/commands/commandHandlerUtils.d.ts +41 -0
- package/src/cli/commands/commandHandlerUtils.mjs +59 -0
- package/src/cli/commands/commands.d.ts +10 -0
- package/src/cli/commands/commands.mjs +23 -0
- package/src/cli/commands/commandsConfig.d.ts +312 -0
- package/src/cli/commands/commandsConfig.mjs +155 -0
- package/src/cli/commands/handleRunScript.d.ts +3 -0
- package/src/cli/commands/handleRunScript.mjs +217 -0
- package/src/cli/commands/handleSimpleCommands.d.ts +15 -0
- package/src/cli/commands/handleSimpleCommands.mjs +170 -0
- package/src/cli/commands/index.d.ts +2 -0
- package/src/cli/commands/index.mjs +2 -0
- package/src/cli/createCli.d.ts +19 -0
- package/src/cli/createCli.mjs +113 -0
- package/src/cli/fatalErrorLogger.d.ts +1 -0
- package/src/cli/fatalErrorLogger.mjs +7 -0
- package/src/cli/globalOptions/globalOptions.d.ts +38 -0
- package/src/cli/globalOptions/globalOptions.mjs +120 -0
- package/src/cli/globalOptions/globalOptionsConfig.d.ts +43 -0
- package/src/cli/globalOptions/globalOptionsConfig.mjs +34 -0
- package/src/cli/globalOptions/index.d.ts +2 -0
- package/src/cli/globalOptions/index.mjs +2 -0
- package/src/cli/index.d.ts +3 -0
- package/src/cli/index.mjs +3 -0
- package/src/config/bunWorkspacesConfig.d.ts +17 -0
- package/src/config/bunWorkspacesConfig.mjs +50 -0
- package/src/config/configFile.d.ts +8 -0
- package/src/config/configFile.mjs +43 -0
- package/src/config/errors.d.ts +3 -0
- package/src/config/errors.mjs +10 -0
- package/src/config/{index.ts → index.d.ts} +1 -0
- package/src/config/index.mjs +11 -0
- package/src/config/userEnvVars.d.ts +9 -0
- package/src/config/userEnvVars.mjs +9 -0
- package/src/config/workspaceConfig/errors.d.ts +3 -0
- package/src/config/workspaceConfig/errors.mjs +9 -0
- package/src/config/workspaceConfig/index.d.ts +4 -0
- package/src/config/workspaceConfig/index.mjs +4 -0
- package/src/config/workspaceConfig/loadWorkspaceConfig.d.ts +5 -0
- package/src/config/workspaceConfig/loadWorkspaceConfig.mjs +82 -0
- package/src/config/workspaceConfig/workspaceConfig.d.ts +25 -0
- package/src/config/workspaceConfig/workspaceConfig.mjs +80 -0
- package/src/config/workspaceConfig/workspaceConfigLocation.d.ts +2 -0
- package/src/config/workspaceConfig/workspaceConfigLocation.mjs +5 -0
- package/src/doctor/doctor.d.ts +35 -0
- package/src/doctor/doctor.mjs +52 -0
- package/src/doctor/index.d.ts +1 -0
- package/src/doctor/index.mjs +1 -0
- package/src/index.d.ts +31 -0
- package/src/index.mjs +9 -0
- package/src/internal/bun/bunLock.d.ts +20 -0
- package/src/internal/bun/bunLock.mjs +72 -0
- package/src/internal/bun/bunVersion.d.ts +21 -0
- package/src/internal/bun/bunVersion.mjs +43 -0
- package/src/internal/bun/index.d.ts +2 -0
- package/src/internal/bun/index.mjs +2 -0
- package/src/internal/core/asyncIterable/asyncIterableQueue.d.ts +15 -0
- package/src/internal/core/asyncIterable/asyncIterableQueue.mjs +73 -0
- package/src/internal/core/asyncIterable/mergeAsyncIterables.d.ts +5 -0
- package/src/internal/core/asyncIterable/mergeAsyncIterables.mjs +27 -0
- package/src/internal/core/error.d.ts +9 -0
- package/src/internal/{error.ts → core/error.mjs} +7 -16
- package/src/internal/core/index.d.ts +7 -0
- package/src/internal/core/index.mjs +6 -0
- package/src/internal/core/json/index.d.ts +2 -0
- package/src/internal/core/json/index.mjs +2 -0
- package/src/internal/core/json/json.d.ts +9 -0
- package/src/internal/core/json/json.mjs +6 -0
- package/src/internal/core/json/jsonc.d.ts +9 -0
- package/src/internal/core/json/jsonc.mjs +117 -0
- package/src/internal/core/optionalArray.d.ts +15 -0
- package/src/internal/core/optionalArray.mjs +8 -0
- package/src/internal/core/regex.d.ts +3 -0
- package/src/internal/core/regex.mjs +10 -0
- package/src/internal/core/types.d.ts +6 -0
- package/src/internal/core/types.mjs +3 -0
- package/src/internal/logger/index.d.ts +1 -0
- package/src/internal/logger/index.mjs +1 -0
- package/src/internal/logger/logger.d.ts +44 -0
- package/src/internal/logger/logger.mjs +110 -0
- package/src/internal/runtime/env.d.ts +5 -0
- package/src/internal/runtime/env.mjs +29 -0
- package/src/internal/runtime/index.d.ts +2 -0
- package/src/internal/runtime/index.mjs +2 -0
- package/src/internal/runtime/onExit.d.ts +6 -0
- package/src/internal/runtime/onExit.mjs +24 -0
- package/src/internal/runtime/os.d.ts +4 -0
- package/src/internal/runtime/os.mjs +7 -0
- package/src/internal/runtime/tempFile.d.ts +16 -0
- package/src/internal/runtime/tempFile.mjs +50 -0
- package/src/project/errors.d.ts +3 -0
- package/src/project/errors.mjs +9 -0
- package/src/project/implementations/fileSystemProject.d.ts +106 -0
- package/src/project/implementations/fileSystemProject.mjs +227 -0
- package/src/project/implementations/memoryProject.d.ts +32 -0
- package/src/project/implementations/memoryProject.mjs +46 -0
- package/src/project/implementations/projectBase.d.ts +28 -0
- package/src/project/implementations/projectBase.mjs +117 -0
- package/src/project/index.d.ts +5 -0
- package/src/project/index.mjs +4 -0
- package/src/project/project.d.ts +64 -0
- package/src/project/project.mjs +6 -0
- package/src/runScript/index.d.ts +7 -0
- package/src/runScript/index.mjs +7 -0
- package/src/runScript/outputChunk.d.ts +22 -0
- package/src/runScript/outputChunk.mjs +30 -0
- package/src/runScript/parallel.d.ts +12 -0
- package/src/runScript/parallel.mjs +52 -0
- package/src/runScript/runScript.d.ts +37 -0
- package/src/runScript/runScript.mjs +60 -0
- package/src/runScript/runScripts.d.ts +48 -0
- package/src/runScript/runScripts.mjs +124 -0
- package/src/runScript/scriptCommand.d.ts +33 -0
- package/src/runScript/scriptCommand.mjs +19 -0
- package/src/runScript/scriptExecution.d.ts +9 -0
- package/src/runScript/scriptExecution.mjs +51 -0
- package/src/runScript/scriptRuntimeMetadata.d.ts +75 -0
- package/src/runScript/scriptRuntimeMetadata.mjs +62 -0
- package/src/runScript/scriptShellOption.d.ts +7 -0
- package/src/runScript/scriptShellOption.mjs +36 -0
- package/src/workspaces/errors.d.ts +12 -0
- package/src/workspaces/{errors.ts → errors.mjs} +5 -2
- package/src/workspaces/findWorkspaces.d.ts +22 -0
- package/src/workspaces/findWorkspaces.mjs +168 -0
- package/src/workspaces/index.d.ts +4 -0
- package/src/workspaces/index.mjs +3 -0
- package/src/workspaces/packageJson.d.ts +15 -0
- package/src/workspaces/packageJson.mjs +135 -0
- package/src/workspaces/{workspace.ts → workspace.d.ts} +5 -6
- package/src/workspaces/workspace.mjs +2 -0
- package/bun.lock +0 -576
- package/src/cli/cli.ts +0 -87
- package/src/cli/globalOptions.ts +0 -122
- package/src/cli/index.ts +0 -1
- package/src/cli/projectCommands.ts +0 -390
- package/src/config/bunWorkspacesConfig.ts +0 -62
- package/src/config/configFile.ts +0 -33
- package/src/index.ts +0 -3
- package/src/internal/bunVersion.ts +0 -26
- package/src/internal/env.ts +0 -25
- package/src/internal/logger.ts +0 -180
- package/src/internal/regex.ts +0 -5
- package/src/project/errors.ts +0 -6
- package/src/project/index.ts +0 -6
- package/src/project/project.ts +0 -155
- package/src/project/scriptCommand.ts +0 -40
- package/src/workspaces/findWorkspaces.ts +0 -137
- package/src/workspaces/index.ts +0 -7
- package/src/workspaces/packageJson.ts +0 -166
- package/tsconfig.json +0 -28
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ScriptCommand, WorkspaceScriptCommandMethod } from "../runScript";
|
|
2
|
+
import type { Workspace } from "../workspaces";
|
|
3
|
+
/** Metadata about a {@link Project}'s script, including the workspaces that have it in their package.json */
|
|
4
|
+
export type WorkspaceScriptMetadata = {
|
|
5
|
+
name: string;
|
|
6
|
+
workspaces: Workspace[];
|
|
7
|
+
};
|
|
8
|
+
/** Arguments for {@link Project.createScriptCommand} */
|
|
9
|
+
export type CreateProjectScriptCommandOptions = {
|
|
10
|
+
/** The workspace to run the script in */
|
|
11
|
+
workspaceNameOrAlias: string;
|
|
12
|
+
/** The name of the script to run */
|
|
13
|
+
scriptName: string;
|
|
14
|
+
/**
|
|
15
|
+
* The method to use to run the script.
|
|
16
|
+
* Either run in the workspace directory or use bun's --filter option.
|
|
17
|
+
* Defaults to "cd".
|
|
18
|
+
*/
|
|
19
|
+
method?: WorkspaceScriptCommandMethod;
|
|
20
|
+
/** The arguments to append to the command */
|
|
21
|
+
args?: string;
|
|
22
|
+
};
|
|
23
|
+
/** Result of {@link Project.createScriptCommand}. Includes a command string that will run a workspace's script. */
|
|
24
|
+
export type CreateProjectScriptCommandResult = {
|
|
25
|
+
/** Data including a command string using the `bun`
|
|
26
|
+
* CLI that will run a workspace's script and the
|
|
27
|
+
* directory to run it in. */
|
|
28
|
+
commandDetails: ScriptCommand;
|
|
29
|
+
/** The name of the script to run */
|
|
30
|
+
scriptName: string;
|
|
31
|
+
/** The workspace that the script belongs to */
|
|
32
|
+
workspace: Workspace;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* A project contains a collection of workspaces and is the core of `bun-workspaces`'s functionality.
|
|
36
|
+
*
|
|
37
|
+
* Typically based on a root package.json file's `"workspaces"` field and any matching nested package.json files that are found.
|
|
38
|
+
*/
|
|
39
|
+
export interface Project {
|
|
40
|
+
/** The name of the project. This is typically the name of the root package.json unless otherwise provided. */
|
|
41
|
+
name: string;
|
|
42
|
+
/** The root directory of the project */
|
|
43
|
+
rootDirectory: string;
|
|
44
|
+
/** The list of all workspaces in the project */
|
|
45
|
+
workspaces: Workspace[];
|
|
46
|
+
/** The means by which the project was created */
|
|
47
|
+
sourceType: "fileSystem" | "memory";
|
|
48
|
+
/** Find a workspace by its package.json name */
|
|
49
|
+
findWorkspaceByName(workspaceName: string): Workspace | null;
|
|
50
|
+
/** Find a workspace by a workspace alias */
|
|
51
|
+
findWorkspaceByAlias(alias: string): Workspace | null;
|
|
52
|
+
/** Find a workspace that matches a workspace's name or an alias if no name matches. */
|
|
53
|
+
findWorkspaceByNameOrAlias(nameOrAlias: string): Workspace | null;
|
|
54
|
+
/** Accepts a wildcard pattern for finding a list of workspaces by their name*/
|
|
55
|
+
findWorkspacesByPattern(workspacePattern: string): Workspace[];
|
|
56
|
+
/** Get an array of all workspaces that have a given script in their package.json */
|
|
57
|
+
listWorkspacesWithScript(scriptName: string): Workspace[];
|
|
58
|
+
/** Get a mapping of all scripts to the workspaces that have them in their package.json */
|
|
59
|
+
mapScriptsToWorkspaces(): Record<string, WorkspaceScriptMetadata>;
|
|
60
|
+
/** Create metadata that can be used to run a workspace's script */
|
|
61
|
+
createScriptCommand(
|
|
62
|
+
options: CreateProjectScriptCommandOptions,
|
|
63
|
+
): CreateProjectScriptCommandResult;
|
|
64
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// CONCATENATED MODULE: ./src/project/project.ts
|
|
2
|
+
/**
|
|
3
|
+
* A project contains a collection of workspaces and is the core of `bun-workspaces`'s functionality.
|
|
4
|
+
*
|
|
5
|
+
* Typically based on a root package.json file's `"workspaces"` field and any matching nested package.json files that are found.
|
|
6
|
+
*/
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./runScript.mjs";
|
|
2
|
+
export * from "./runScripts.mjs";
|
|
3
|
+
export * from "./scriptCommand.mjs";
|
|
4
|
+
export * from "./outputChunk.mjs";
|
|
5
|
+
export * from "./parallel.mjs";
|
|
6
|
+
export * from "./scriptRuntimeMetadata.mjs";
|
|
7
|
+
export * from "./scriptShellOption.mjs"; // CONCATENATED MODULE: ./src/runScript/index.ts
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type OutputStreamName = "stdout" | "stderr";
|
|
2
|
+
export interface DecodeOptions {
|
|
3
|
+
/** Whether to strip ANSI escape codes */
|
|
4
|
+
stripAnsi?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/** Output captured from a script subprocess */
|
|
7
|
+
export interface OutputChunk {
|
|
8
|
+
/** The source of the output, `"stdout"` or `"stderr"` */
|
|
9
|
+
streamName: OutputStreamName;
|
|
10
|
+
/** Raw output text. Pass `true` to strip ANSI escape codes. */
|
|
11
|
+
decode(options?: DecodeOptions): string;
|
|
12
|
+
/** The raw output content */
|
|
13
|
+
raw: Uint8Array<ArrayBuffer>;
|
|
14
|
+
/** @deprecated Use `decode()` instead */
|
|
15
|
+
text: string;
|
|
16
|
+
/** @deprecated Use `decode({ stripAnsi: true })` instead */
|
|
17
|
+
textNoAnsi: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const createOutputChunk: (
|
|
20
|
+
streamName: OutputStreamName,
|
|
21
|
+
raw: Uint8Array<ArrayBuffer>,
|
|
22
|
+
) => OutputChunk;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { sanitizeAnsi } from "../internal/core/index.mjs"; // CONCATENATED MODULE: external "../internal/core/index.mjs"
|
|
2
|
+
// CONCATENATED MODULE: ./src/runScript/outputChunk.ts
|
|
3
|
+
|
|
4
|
+
class _OutputChunk {
|
|
5
|
+
streamName;
|
|
6
|
+
raw;
|
|
7
|
+
constructor(streamName, raw) {
|
|
8
|
+
this.streamName = streamName;
|
|
9
|
+
this.raw = raw;
|
|
10
|
+
}
|
|
11
|
+
decode(options) {
|
|
12
|
+
const { stripAnsi = false } = options ?? {};
|
|
13
|
+
const text = new TextDecoder().decode(this.raw);
|
|
14
|
+
return stripAnsi ? sanitizeAnsi(text) : text;
|
|
15
|
+
}
|
|
16
|
+
/** @deprecated Use `decode()` instead */ get text() {
|
|
17
|
+
// TODO remove in future major release
|
|
18
|
+
return this.decode();
|
|
19
|
+
}
|
|
20
|
+
/** @deprecated Use `decode({ stripAnsi: true })` instead */ get textNoAnsi() {
|
|
21
|
+
// TODO remove in future major release
|
|
22
|
+
return this.decode({
|
|
23
|
+
stripAnsi: true,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const createOutputChunk = (streamName, raw) =>
|
|
28
|
+
new _OutputChunk(streamName, raw);
|
|
29
|
+
|
|
30
|
+
export { createOutputChunk };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type PercentageValue = `${number}%`;
|
|
2
|
+
export type ParallelMaxValue =
|
|
3
|
+
| number
|
|
4
|
+
| "auto"
|
|
5
|
+
| "default"
|
|
6
|
+
| "unbounded"
|
|
7
|
+
| PercentageValue;
|
|
8
|
+
/** Should always return at least 1 */
|
|
9
|
+
export declare const determineParallelMax: (
|
|
10
|
+
value: ParallelMaxValue,
|
|
11
|
+
fromEnvVar?: boolean,
|
|
12
|
+
) => number;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { availableParallelism } from "node:os";
|
|
2
|
+
import { getUserEnvVar, getUserEnvVarName } from "../config/userEnvVars.mjs";
|
|
3
|
+
import { BunWorkspacesError } from "../internal/core/index.mjs"; // CONCATENATED MODULE: external "node:os"
|
|
4
|
+
// CONCATENATED MODULE: external "../config/userEnvVars.mjs"
|
|
5
|
+
// CONCATENATED MODULE: external "../internal/core/index.mjs"
|
|
6
|
+
// CONCATENATED MODULE: ./src/runScript/parallel.ts
|
|
7
|
+
|
|
8
|
+
/** Should always return at least 1 */ const determineParallelMax = (
|
|
9
|
+
value,
|
|
10
|
+
fromEnvVar = false,
|
|
11
|
+
) => {
|
|
12
|
+
const errorMessageSuffix = fromEnvVar
|
|
13
|
+
? ` (set by env var ${getUserEnvVarName("parallelMaxDefault")})`
|
|
14
|
+
: "";
|
|
15
|
+
if (!isNaN(Number(value))) {
|
|
16
|
+
value = Math.floor(Number(value));
|
|
17
|
+
}
|
|
18
|
+
if (typeof value === "number") {
|
|
19
|
+
if (value < 1 || isNaN(value)) {
|
|
20
|
+
throw new BunWorkspacesError(
|
|
21
|
+
`Parallel max value must be at least 1${errorMessageSuffix}`,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
return Math.floor(value);
|
|
25
|
+
}
|
|
26
|
+
if (value === "default") {
|
|
27
|
+
const defaultMax = getUserEnvVar("parallelMaxDefault")?.trim();
|
|
28
|
+
if (defaultMax === "default") return determineParallelMax("auto");
|
|
29
|
+
return determineParallelMax(defaultMax ?? "auto", true);
|
|
30
|
+
}
|
|
31
|
+
if (value === "unbounded") {
|
|
32
|
+
return Infinity;
|
|
33
|
+
}
|
|
34
|
+
const cpuCount = Math.max(1, availableParallelism());
|
|
35
|
+
if (value === "auto") {
|
|
36
|
+
return cpuCount;
|
|
37
|
+
}
|
|
38
|
+
if (value.endsWith("%")) {
|
|
39
|
+
const percentage = parseFloat(value.slice(0, -1));
|
|
40
|
+
if (isNaN(percentage) || percentage <= 0 || percentage > 100) {
|
|
41
|
+
throw new BunWorkspacesError(
|
|
42
|
+
`Parallel max value must be a number greater than 0 and less than or equal to 100${errorMessageSuffix}`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
return Math.max(1, Math.floor((cpuCount * percentage) / 100));
|
|
46
|
+
}
|
|
47
|
+
throw new BunWorkspacesError(
|
|
48
|
+
`Invalid parallel max value: ${JSON.stringify(value)}${errorMessageSuffix}`,
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { determineParallelMax };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type SimpleAsyncIterable } from "../internal/core";
|
|
2
|
+
import { type OutputChunk } from "./outputChunk";
|
|
3
|
+
import type { ScriptCommand } from "./scriptCommand";
|
|
4
|
+
import type { ScriptShellOption } from "./scriptShellOption";
|
|
5
|
+
export type RunScriptExit<ScriptMetadata extends object = object> = {
|
|
6
|
+
exitCode: number;
|
|
7
|
+
signal: NodeJS.Signals | null;
|
|
8
|
+
success: boolean;
|
|
9
|
+
startTimeISO: string;
|
|
10
|
+
endTimeISO: string;
|
|
11
|
+
durationMs: number;
|
|
12
|
+
metadata: ScriptMetadata;
|
|
13
|
+
};
|
|
14
|
+
export type RunScriptResult<ScriptMetadata extends object = object> = {
|
|
15
|
+
output: SimpleAsyncIterable<OutputChunk>;
|
|
16
|
+
exit: Promise<RunScriptExit<ScriptMetadata>>;
|
|
17
|
+
metadata: ScriptMetadata;
|
|
18
|
+
kill: (exit?: number | NodeJS.Signals) => void;
|
|
19
|
+
};
|
|
20
|
+
export type RunScriptOptions<ScriptMetadata extends object = object> = {
|
|
21
|
+
scriptCommand: ScriptCommand;
|
|
22
|
+
metadata: ScriptMetadata;
|
|
23
|
+
env: Record<string, string>;
|
|
24
|
+
/** The shell to use to run the script. Defaults to "system". */
|
|
25
|
+
shell?: ScriptShellOption;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Run some script and get an async output stream of
|
|
29
|
+
* stdout and stderr chunks and a result object
|
|
30
|
+
* containing exit details.
|
|
31
|
+
*/
|
|
32
|
+
export declare const runScript: <ScriptMetadata extends object = object>({
|
|
33
|
+
scriptCommand,
|
|
34
|
+
metadata,
|
|
35
|
+
env,
|
|
36
|
+
shell,
|
|
37
|
+
}: RunScriptOptions<ScriptMetadata>) => RunScriptResult<ScriptMetadata>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { mergeAsyncIterables } from "../internal/core/index.mjs";
|
|
2
|
+
import { createOutputChunk } from "./outputChunk.mjs";
|
|
3
|
+
import { createScriptExecutor } from "./scriptExecution.mjs"; // CONCATENATED MODULE: external "../internal/core/index.mjs"
|
|
4
|
+
// CONCATENATED MODULE: external "./outputChunk.mjs"
|
|
5
|
+
// CONCATENATED MODULE: external "./scriptExecution.mjs"
|
|
6
|
+
// CONCATENATED MODULE: ./src/runScript/runScript.ts
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Run some script and get an async output stream of
|
|
10
|
+
* stdout and stderr chunks and a result object
|
|
11
|
+
* containing exit details.
|
|
12
|
+
*/ const runScript = ({ scriptCommand, metadata, env, shell = "system" }) => {
|
|
13
|
+
const startTime = new Date();
|
|
14
|
+
const { argv, cleanup } = createScriptExecutor(scriptCommand.command, shell);
|
|
15
|
+
const proc = Bun.spawn(argv, {
|
|
16
|
+
cwd: scriptCommand.workingDirectory || process.cwd(),
|
|
17
|
+
env: {
|
|
18
|
+
...process.env,
|
|
19
|
+
...env,
|
|
20
|
+
_BW_SCRIPT_SHELL_OPTION: shell,
|
|
21
|
+
FORCE_COLOR: "1",
|
|
22
|
+
},
|
|
23
|
+
stdout: "pipe",
|
|
24
|
+
stderr: "pipe",
|
|
25
|
+
stdin: "ignore",
|
|
26
|
+
});
|
|
27
|
+
proc.exited.finally(cleanup);
|
|
28
|
+
async function* pipeOutput(streamName) {
|
|
29
|
+
const stream = proc[streamName];
|
|
30
|
+
if (stream) {
|
|
31
|
+
for await (const chunk of stream) {
|
|
32
|
+
yield createOutputChunk(streamName, chunk);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const output = mergeAsyncIterables([
|
|
37
|
+
pipeOutput("stdout"),
|
|
38
|
+
pipeOutput("stderr"),
|
|
39
|
+
]);
|
|
40
|
+
const exit = proc.exited.then((exitCode) => {
|
|
41
|
+
const endTime = new Date();
|
|
42
|
+
return {
|
|
43
|
+
exitCode,
|
|
44
|
+
signal: proc.signalCode,
|
|
45
|
+
success: exitCode === 0,
|
|
46
|
+
startTimeISO: startTime.toISOString(),
|
|
47
|
+
endTimeISO: endTime.toISOString(),
|
|
48
|
+
durationMs: endTime.getTime() - startTime.getTime(),
|
|
49
|
+
metadata,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
output,
|
|
54
|
+
exit,
|
|
55
|
+
metadata,
|
|
56
|
+
kill: (exit) => proc.kill(exit),
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export { runScript };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type SimpleAsyncIterable } from "../internal/core";
|
|
2
|
+
import type { OutputChunk } from "./outputChunk";
|
|
3
|
+
import { type ParallelMaxValue } from "./parallel";
|
|
4
|
+
import { type RunScriptExit, type RunScriptResult } from "./runScript";
|
|
5
|
+
import { type ScriptCommand } from "./scriptCommand";
|
|
6
|
+
export type RunScriptsScript<ScriptMetadata extends object = object> = {
|
|
7
|
+
scriptCommand: ScriptCommand;
|
|
8
|
+
metadata: ScriptMetadata;
|
|
9
|
+
env: Record<string, string>;
|
|
10
|
+
};
|
|
11
|
+
export type RunScriptsScriptResult<ScriptMetadata extends object = object> = {
|
|
12
|
+
/** The result of running the script */
|
|
13
|
+
result: RunScriptResult<ScriptMetadata>;
|
|
14
|
+
};
|
|
15
|
+
export type RunScriptsSummary<ScriptMetadata extends object = object> = {
|
|
16
|
+
totalCount: number;
|
|
17
|
+
successCount: number;
|
|
18
|
+
failureCount: number;
|
|
19
|
+
allSuccess: boolean;
|
|
20
|
+
startTimeISO: string;
|
|
21
|
+
endTimeISO: string;
|
|
22
|
+
durationMs: number;
|
|
23
|
+
scriptResults: RunScriptExit<ScriptMetadata>[];
|
|
24
|
+
};
|
|
25
|
+
export type RunScriptsOutput<ScriptMetadata extends object = object> = {
|
|
26
|
+
/** The output chunk from a script execution */
|
|
27
|
+
outputChunk: OutputChunk;
|
|
28
|
+
/** The metadata for the script that produced the output chunk */
|
|
29
|
+
scriptMetadata: ScriptMetadata;
|
|
30
|
+
};
|
|
31
|
+
export type RunScriptsResult<ScriptMetadata extends object = object> = {
|
|
32
|
+
/** Allows async iteration of output chunks from all script executions */
|
|
33
|
+
output: SimpleAsyncIterable<RunScriptsOutput<ScriptMetadata>>;
|
|
34
|
+
/** Resolves with a results summary after all scripts have exited */
|
|
35
|
+
summary: Promise<RunScriptsSummary<ScriptMetadata>>;
|
|
36
|
+
};
|
|
37
|
+
export type RunScriptsParallelOptions = {
|
|
38
|
+
max: ParallelMaxValue;
|
|
39
|
+
};
|
|
40
|
+
export type RunScriptsOptions<ScriptMetadata extends object = object> = {
|
|
41
|
+
scripts: RunScriptsScript<ScriptMetadata>[];
|
|
42
|
+
parallel: boolean | RunScriptsParallelOptions;
|
|
43
|
+
};
|
|
44
|
+
/** Run a list of scripts */
|
|
45
|
+
export declare const runScripts: <ScriptMetadata extends object = object>({
|
|
46
|
+
scripts,
|
|
47
|
+
parallel,
|
|
48
|
+
}: RunScriptsOptions<ScriptMetadata>) => RunScriptsResult<ScriptMetadata>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createAsyncIterableQueue } from "../internal/core/index.mjs";
|
|
2
|
+
import { logger } from "../internal/logger/index.mjs";
|
|
3
|
+
import { determineParallelMax } from "./parallel.mjs";
|
|
4
|
+
import { runScript } from "./runScript.mjs"; // CONCATENATED MODULE: external "../internal/core/index.mjs"
|
|
5
|
+
// CONCATENATED MODULE: external "../internal/logger/index.mjs"
|
|
6
|
+
// CONCATENATED MODULE: external "./parallel.mjs"
|
|
7
|
+
// CONCATENATED MODULE: external "./runScript.mjs"
|
|
8
|
+
// CONCATENATED MODULE: ./src/runScript/runScripts.ts
|
|
9
|
+
|
|
10
|
+
/** Run a list of scripts */ const runScripts = ({ scripts, parallel }) => {
|
|
11
|
+
const startTime = new Date();
|
|
12
|
+
const scriptTriggers = scripts.map((_, index) => {
|
|
13
|
+
let trigger = () => {
|
|
14
|
+
void 0;
|
|
15
|
+
};
|
|
16
|
+
const promise = new Promise((res) => {
|
|
17
|
+
trigger = () => res(result);
|
|
18
|
+
});
|
|
19
|
+
const result = {
|
|
20
|
+
promise,
|
|
21
|
+
trigger,
|
|
22
|
+
index,
|
|
23
|
+
};
|
|
24
|
+
return result;
|
|
25
|
+
});
|
|
26
|
+
const outputQueue = createAsyncIterableQueue();
|
|
27
|
+
const scriptResults = scripts.map(() => null);
|
|
28
|
+
const parallelMax =
|
|
29
|
+
parallel === false
|
|
30
|
+
? 1
|
|
31
|
+
: determineParallelMax(
|
|
32
|
+
typeof parallel === "boolean" ? "default" : parallel.max,
|
|
33
|
+
);
|
|
34
|
+
const parallelBatchSize = Math.min(parallelMax, scripts.length);
|
|
35
|
+
const recommendedParallelMax = determineParallelMax("auto");
|
|
36
|
+
if (
|
|
37
|
+
parallel &&
|
|
38
|
+
parallelBatchSize > recommendedParallelMax &&
|
|
39
|
+
process.env._BW_IS_INTERNAL_TEST !== "true"
|
|
40
|
+
) {
|
|
41
|
+
logger.warn(
|
|
42
|
+
`Number of scripts to run in parallel (${parallelBatchSize}) is greater than the available CPUs (${recommendedParallelMax})`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
let runningScriptCount = 0;
|
|
46
|
+
let nextScriptIndex = 0;
|
|
47
|
+
const queueScript = (index) => {
|
|
48
|
+
if (runningScriptCount >= parallelMax) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const scriptResult = {
|
|
52
|
+
...scripts[index],
|
|
53
|
+
result: runScript({
|
|
54
|
+
...scripts[index],
|
|
55
|
+
env: {
|
|
56
|
+
...scripts[index].env,
|
|
57
|
+
_BW_PARALLEL_MAX: parallelMax.toString(),
|
|
58
|
+
},
|
|
59
|
+
}),
|
|
60
|
+
};
|
|
61
|
+
scriptResults[index] = scriptResult;
|
|
62
|
+
scriptTriggers[index].trigger();
|
|
63
|
+
runningScriptCount++;
|
|
64
|
+
nextScriptIndex++;
|
|
65
|
+
scriptResults[index].result.exit.then(() => {
|
|
66
|
+
runningScriptCount--;
|
|
67
|
+
if (nextScriptIndex < scripts.length) {
|
|
68
|
+
queueScript(nextScriptIndex);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return scriptResult;
|
|
72
|
+
};
|
|
73
|
+
const handleScriptProcesses = async () => {
|
|
74
|
+
const outputReaders = [];
|
|
75
|
+
const scriptExits = [];
|
|
76
|
+
let pendingScriptCount = scripts.length;
|
|
77
|
+
while (pendingScriptCount > 0) {
|
|
78
|
+
const { index } = await Promise.race(
|
|
79
|
+
scriptTriggers.map((trigger) => trigger.promise),
|
|
80
|
+
);
|
|
81
|
+
pendingScriptCount--;
|
|
82
|
+
scriptTriggers[index].promise = new Promise(() => {
|
|
83
|
+
void 0;
|
|
84
|
+
});
|
|
85
|
+
outputReaders.push(
|
|
86
|
+
(async () => {
|
|
87
|
+
for await (const chunk of scriptResults[index].result.output) {
|
|
88
|
+
outputQueue.push({
|
|
89
|
+
outputChunk: chunk,
|
|
90
|
+
scriptMetadata: scripts[index].metadata,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
})(),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
await Promise.all(outputReaders);
|
|
97
|
+
await Promise.all(scriptExits);
|
|
98
|
+
outputQueue.close();
|
|
99
|
+
};
|
|
100
|
+
const awaitSummary = async () => {
|
|
101
|
+
scripts.forEach((_, index) => queueScript(index));
|
|
102
|
+
await handleScriptProcesses();
|
|
103
|
+
const scriptExitResults = await Promise.all(
|
|
104
|
+
scripts.map((_, index) => scriptResults[index].result.exit),
|
|
105
|
+
);
|
|
106
|
+
const endTime = new Date();
|
|
107
|
+
return {
|
|
108
|
+
totalCount: scriptExitResults.length,
|
|
109
|
+
successCount: scriptExitResults.filter((exit) => exit.success).length,
|
|
110
|
+
failureCount: scriptExitResults.filter((exit) => !exit.success).length,
|
|
111
|
+
allSuccess: scriptExitResults.every((exit) => exit.success),
|
|
112
|
+
startTimeISO: startTime.toISOString(),
|
|
113
|
+
endTimeISO: endTime.toISOString(),
|
|
114
|
+
durationMs: endTime.getTime() - startTime.getTime(),
|
|
115
|
+
scriptResults: scriptExitResults,
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
return {
|
|
119
|
+
output: outputQueue,
|
|
120
|
+
summary: awaitSummary(),
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export { runScripts };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Workspace } from "../workspaces";
|
|
2
|
+
export declare const WORKSPACE_SCRIPT_COMMAND_METHODS: readonly [
|
|
3
|
+
"cd",
|
|
4
|
+
"filter",
|
|
5
|
+
];
|
|
6
|
+
export type WorkspaceScriptCommandMethod =
|
|
7
|
+
(typeof WORKSPACE_SCRIPT_COMMAND_METHODS)[number];
|
|
8
|
+
/** Basic metadata to run a script, the command string and the directory to run it in */
|
|
9
|
+
export interface ScriptCommand {
|
|
10
|
+
/** The command string to run */
|
|
11
|
+
command: string;
|
|
12
|
+
/** The directory to run the command in */
|
|
13
|
+
workingDirectory: string;
|
|
14
|
+
}
|
|
15
|
+
export interface CreateWorkspaceScriptCommandOptions {
|
|
16
|
+
/**
|
|
17
|
+
* The method to use to run the script.
|
|
18
|
+
* Either run in the workspace directory or use bun's --filter option.
|
|
19
|
+
* Defaults to "cd".
|
|
20
|
+
*/
|
|
21
|
+
method?: WorkspaceScriptCommandMethod;
|
|
22
|
+
/** The name of the script to run */
|
|
23
|
+
scriptName: string;
|
|
24
|
+
/** The arguments to append to the command */
|
|
25
|
+
args: string;
|
|
26
|
+
/** The workspace that the script belongs to */
|
|
27
|
+
workspace: Workspace;
|
|
28
|
+
/** The root directory of the project */
|
|
29
|
+
rootDirectory: string;
|
|
30
|
+
}
|
|
31
|
+
export declare const createWorkspaceScriptCommand: (
|
|
32
|
+
options: CreateWorkspaceScriptCommandOptions,
|
|
33
|
+
) => ScriptCommand;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import path from "path"; // CONCATENATED MODULE: external "path"
|
|
2
|
+
// CONCATENATED MODULE: ./src/runScript/scriptCommand.ts
|
|
3
|
+
|
|
4
|
+
const WORKSPACE_SCRIPT_COMMAND_METHODS = ["cd", "filter"];
|
|
5
|
+
const spaceArgs = (args) => (args ? ` ${args.trim()}` : "");
|
|
6
|
+
const METHODS = {
|
|
7
|
+
cd: ({ scriptName, workspace, rootDirectory, args }) => ({
|
|
8
|
+
workingDirectory: path.resolve(rootDirectory, workspace.path),
|
|
9
|
+
command: `bun --silent run ${scriptName}${spaceArgs(args)}`,
|
|
10
|
+
}),
|
|
11
|
+
filter: ({ scriptName, workspace, args, rootDirectory }) => ({
|
|
12
|
+
workingDirectory: rootDirectory,
|
|
13
|
+
command: `bun --silent run --filter=${JSON.stringify(workspace.name)} ${scriptName}${spaceArgs(args)}`,
|
|
14
|
+
}),
|
|
15
|
+
};
|
|
16
|
+
const createWorkspaceScriptCommand = (options) =>
|
|
17
|
+
METHODS[options.method ?? "cd"](options);
|
|
18
|
+
|
|
19
|
+
export { WORKSPACE_SCRIPT_COMMAND_METHODS, createWorkspaceScriptCommand };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import node_crypto from "node:crypto";
|
|
2
|
+
import { BunWorkspacesError } from "../internal/core/index.mjs";
|
|
3
|
+
import { IS_WINDOWS } from "../internal/runtime/index.mjs";
|
|
4
|
+
import { createTempFile } from "../internal/runtime/tempFile.mjs";
|
|
5
|
+
import { resolveScriptShell } from "./scriptShellOption.mjs"; // CONCATENATED MODULE: external "node:crypto"
|
|
6
|
+
// CONCATENATED MODULE: external "../internal/core/index.mjs"
|
|
7
|
+
// CONCATENATED MODULE: external "../internal/runtime/index.mjs"
|
|
8
|
+
// CONCATENATED MODULE: external "../internal/runtime/tempFile.mjs"
|
|
9
|
+
// CONCATENATED MODULE: external "./scriptShellOption.mjs"
|
|
10
|
+
// CONCATENATED MODULE: ./src/runScript/scriptExecution.ts
|
|
11
|
+
|
|
12
|
+
const createWindowsBatchFile = (command) => {
|
|
13
|
+
const fileName = `${node_crypto.randomUUID()}.cmd`;
|
|
14
|
+
const fileContent = `@echo off\r\n${command}\r\n`;
|
|
15
|
+
return createTempFile({
|
|
16
|
+
fileName,
|
|
17
|
+
fileContent,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
const createShellScript = (command) => {
|
|
21
|
+
const fileName = `${node_crypto.randomUUID()}.sh`;
|
|
22
|
+
return createTempFile({
|
|
23
|
+
fileName,
|
|
24
|
+
fileContent: command,
|
|
25
|
+
mode: 493,
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
const createScriptExecutor = (command, shell) => {
|
|
29
|
+
shell = resolveScriptShell(shell);
|
|
30
|
+
if (shell === "bun") {
|
|
31
|
+
const { filePath, cleanup } = createShellScript(command);
|
|
32
|
+
return {
|
|
33
|
+
argv: ["bun", filePath],
|
|
34
|
+
cleanup,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (shell === "system") {
|
|
38
|
+
const { filePath, cleanup } = IS_WINDOWS
|
|
39
|
+
? createWindowsBatchFile(command)
|
|
40
|
+
: createShellScript(command);
|
|
41
|
+
return {
|
|
42
|
+
argv: IS_WINDOWS
|
|
43
|
+
? ["cmd", "/d", "/s", "/c", "call", filePath]
|
|
44
|
+
: ["sh", "-c", filePath],
|
|
45
|
+
cleanup,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
throw new BunWorkspacesError(`Invalid shell option: ${shell}`);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export { createScriptExecutor };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { ScriptShellOption } from "./scriptShellOption";
|
|
2
|
+
export interface ScriptRuntimeMetadata {
|
|
3
|
+
projectPath: string;
|
|
4
|
+
projectName: string;
|
|
5
|
+
workspacePath: string;
|
|
6
|
+
workspaceRelativePath: string;
|
|
7
|
+
workspaceName: string;
|
|
8
|
+
scriptName: string;
|
|
9
|
+
}
|
|
10
|
+
declare const SCRIPT_RUNTIME_METADATA_CONFIG: {
|
|
11
|
+
readonly projectPath: {
|
|
12
|
+
readonly inlineName: readonly ["<projectPath>"];
|
|
13
|
+
readonly envVarName: "BW_PROJECT_PATH";
|
|
14
|
+
};
|
|
15
|
+
readonly projectName: {
|
|
16
|
+
readonly inlineName: readonly ["<projectName>"];
|
|
17
|
+
readonly envVarName: "BW_PROJECT_NAME";
|
|
18
|
+
};
|
|
19
|
+
readonly workspacePath: {
|
|
20
|
+
readonly inlineName: readonly ["<workspacePath>"];
|
|
21
|
+
readonly envVarName: "BW_WORKSPACE_PATH";
|
|
22
|
+
};
|
|
23
|
+
readonly workspaceRelativePath: {
|
|
24
|
+
readonly inlineName: readonly ["<workspaceRelativePath>"];
|
|
25
|
+
readonly envVarName: "BW_WORKSPACE_RELATIVE_PATH";
|
|
26
|
+
};
|
|
27
|
+
readonly scriptName: {
|
|
28
|
+
readonly inlineName: readonly ["<scriptName>"];
|
|
29
|
+
readonly envVarName: "BW_SCRIPT_NAME";
|
|
30
|
+
};
|
|
31
|
+
readonly workspaceName: {
|
|
32
|
+
/** @todo @deprecated Deprecate <workspace> in favor of <workspaceName> in major release */
|
|
33
|
+
readonly inlineName: readonly ["<workspaceName>", "<workspace>"];
|
|
34
|
+
readonly envVarName: "BW_WORKSPACE_NAME";
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export type ScriptRuntimeMetadataKey =
|
|
38
|
+
keyof typeof SCRIPT_RUNTIME_METADATA_CONFIG;
|
|
39
|
+
export declare const getScriptRuntimeMetadataConfig: (
|
|
40
|
+
key: ScriptRuntimeMetadataKey,
|
|
41
|
+
) =>
|
|
42
|
+
| {
|
|
43
|
+
readonly inlineName: readonly ["<projectPath>"];
|
|
44
|
+
readonly envVarName: "BW_PROJECT_PATH";
|
|
45
|
+
}
|
|
46
|
+
| {
|
|
47
|
+
readonly inlineName: readonly ["<projectName>"];
|
|
48
|
+
readonly envVarName: "BW_PROJECT_NAME";
|
|
49
|
+
}
|
|
50
|
+
| {
|
|
51
|
+
readonly inlineName: readonly ["<workspacePath>"];
|
|
52
|
+
readonly envVarName: "BW_WORKSPACE_PATH";
|
|
53
|
+
}
|
|
54
|
+
| {
|
|
55
|
+
readonly inlineName: readonly ["<workspaceRelativePath>"];
|
|
56
|
+
readonly envVarName: "BW_WORKSPACE_RELATIVE_PATH";
|
|
57
|
+
}
|
|
58
|
+
| {
|
|
59
|
+
readonly inlineName: readonly ["<scriptName>"];
|
|
60
|
+
readonly envVarName: "BW_SCRIPT_NAME";
|
|
61
|
+
}
|
|
62
|
+
| {
|
|
63
|
+
/** @todo @deprecated Deprecate <workspace> in favor of <workspaceName> in major release */
|
|
64
|
+
readonly inlineName: readonly ["<workspaceName>", "<workspace>"];
|
|
65
|
+
readonly envVarName: "BW_WORKSPACE_NAME";
|
|
66
|
+
};
|
|
67
|
+
export declare const createScriptRuntimeEnvVars: (
|
|
68
|
+
metadata: ScriptRuntimeMetadata,
|
|
69
|
+
) => Record<string, string>;
|
|
70
|
+
export declare const interpolateScriptRuntimeMetadata: (
|
|
71
|
+
text: string,
|
|
72
|
+
metadata: ScriptRuntimeMetadata,
|
|
73
|
+
shell: ScriptShellOption,
|
|
74
|
+
) => string;
|
|
75
|
+
export {};
|