@effect/platform-node-shared 0.0.0-snapshot-c0ae728e57df2c572ea803e1bb7121088cd67b49
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/Http/Etag/package.json +6 -0
- package/Http/Multipart/package.json +6 -0
- package/LICENSE +21 -0
- package/NodeCommandExecutor/package.json +6 -0
- package/NodeFileSystem/package.json +6 -0
- package/NodeKeyValueStore/package.json +6 -0
- package/NodePath/package.json +6 -0
- package/NodeRuntime/package.json +6 -0
- package/NodeSink/package.json +6 -0
- package/NodeStream/package.json +6 -0
- package/NodeTerminal/package.json +6 -0
- package/README.md +64 -0
- package/dist/cjs/Http/Etag.js +43 -0
- package/dist/cjs/Http/Etag.js.map +1 -0
- package/dist/cjs/Http/Multipart.js +48 -0
- package/dist/cjs/Http/Multipart.js.map +1 -0
- package/dist/cjs/NodeCommandExecutor.js +38 -0
- package/dist/cjs/NodeCommandExecutor.js.map +1 -0
- package/dist/cjs/NodeFileSystem.js +42 -0
- package/dist/cjs/NodeFileSystem.js.map +1 -0
- package/dist/cjs/NodeKeyValueStore.js +42 -0
- package/dist/cjs/NodeKeyValueStore.js.map +1 -0
- package/dist/cjs/NodePath.js +52 -0
- package/dist/cjs/NodePath.js.map +1 -0
- package/dist/cjs/NodeRuntime.js +38 -0
- package/dist/cjs/NodeRuntime.js.map +1 -0
- package/dist/cjs/NodeSink.js +43 -0
- package/dist/cjs/NodeSink.js.map +1 -0
- package/dist/cjs/NodeStream.js +68 -0
- package/dist/cjs/NodeStream.js.map +1 -0
- package/dist/cjs/NodeTerminal.js +43 -0
- package/dist/cjs/NodeTerminal.js.map +1 -0
- package/dist/cjs/internal/commandExecutor.js +151 -0
- package/dist/cjs/internal/commandExecutor.js.map +1 -0
- package/dist/cjs/internal/error.js +44 -0
- package/dist/cjs/internal/error.js.map +1 -0
- package/dist/cjs/internal/fileSystem.js +370 -0
- package/dist/cjs/internal/fileSystem.js.map +1 -0
- package/dist/cjs/internal/http/etag.js +74 -0
- package/dist/cjs/internal/http/etag.js.map +1 -0
- package/dist/cjs/internal/http/multipart.js +119 -0
- package/dist/cjs/internal/http/multipart.js.map +1 -0
- package/dist/cjs/internal/path.js +72 -0
- package/dist/cjs/internal/path.js.map +1 -0
- package/dist/cjs/internal/runtime.js +59 -0
- package/dist/cjs/internal/runtime.js.map +1 -0
- package/dist/cjs/internal/sink.js +52 -0
- package/dist/cjs/internal/sink.js.map +1 -0
- package/dist/cjs/internal/stream.js +208 -0
- package/dist/cjs/internal/stream.js.map +1 -0
- package/dist/cjs/internal/terminal.js +121 -0
- package/dist/cjs/internal/terminal.js.map +1 -0
- package/dist/dts/Http/Etag.d.ts +16 -0
- package/dist/dts/Http/Etag.d.ts.map +1 -0
- package/dist/dts/Http/Multipart.d.ts +29 -0
- package/dist/dts/Http/Multipart.d.ts.map +1 -0
- package/dist/dts/NodeCommandExecutor.d.ts +12 -0
- package/dist/dts/NodeCommandExecutor.d.ts.map +1 -0
- package/dist/dts/NodeFileSystem.d.ts +11 -0
- package/dist/dts/NodeFileSystem.d.ts.map +1 -0
- package/dist/dts/NodeKeyValueStore.d.ts +12 -0
- package/dist/dts/NodeKeyValueStore.d.ts.map +1 -0
- package/dist/dts/NodePath.d.ts +21 -0
- package/dist/dts/NodePath.d.ts.map +1 -0
- package/dist/dts/NodeRuntime.d.ts +10 -0
- package/dist/dts/NodeRuntime.d.ts.map +1 -0
- package/dist/dts/NodeSink.d.ts +22 -0
- package/dist/dts/NodeSink.d.ts.map +1 -0
- package/dist/dts/NodeStream.d.ts +79 -0
- package/dist/dts/NodeStream.d.ts.map +1 -0
- package/dist/dts/NodeTerminal.d.ts +18 -0
- package/dist/dts/NodeTerminal.d.ts.map +1 -0
- package/dist/dts/internal/commandExecutor.d.ts +2 -0
- package/dist/dts/internal/commandExecutor.d.ts.map +1 -0
- package/dist/dts/internal/error.d.ts +2 -0
- package/dist/dts/internal/error.d.ts.map +1 -0
- package/dist/dts/internal/fileSystem.d.ts +2 -0
- package/dist/dts/internal/fileSystem.d.ts.map +1 -0
- package/dist/dts/internal/http/etag.d.ts +2 -0
- package/dist/dts/internal/http/etag.d.ts.map +1 -0
- package/dist/dts/internal/http/multipart.d.ts +2 -0
- package/dist/dts/internal/http/multipart.d.ts.map +1 -0
- package/dist/dts/internal/path.d.ts +2 -0
- package/dist/dts/internal/path.d.ts.map +1 -0
- package/dist/dts/internal/runtime.d.ts +2 -0
- package/dist/dts/internal/runtime.d.ts.map +1 -0
- package/dist/dts/internal/sink.d.ts +2 -0
- package/dist/dts/internal/sink.d.ts.map +1 -0
- package/dist/dts/internal/stream.d.ts +2 -0
- package/dist/dts/internal/stream.d.ts.map +1 -0
- package/dist/dts/internal/terminal.d.ts +2 -0
- package/dist/dts/internal/terminal.d.ts.map +1 -0
- package/dist/esm/Http/Etag.js +12 -0
- package/dist/esm/Http/Etag.js.map +1 -0
- package/dist/esm/Http/Multipart.js +17 -0
- package/dist/esm/Http/Multipart.js.map +1 -0
- package/dist/esm/NodeCommandExecutor.js +7 -0
- package/dist/esm/NodeCommandExecutor.js.map +1 -0
- package/dist/esm/NodeFileSystem.js +10 -0
- package/dist/esm/NodeFileSystem.js.map +1 -0
- package/dist/esm/NodeKeyValueStore.js +10 -0
- package/dist/esm/NodeKeyValueStore.js.map +1 -0
- package/dist/esm/NodePath.js +20 -0
- package/dist/esm/NodePath.js.map +1 -0
- package/dist/esm/NodeRuntime.js +7 -0
- package/dist/esm/NodeRuntime.js.map +1 -0
- package/dist/esm/NodeSink.js +12 -0
- package/dist/esm/NodeSink.js.map +1 -0
- package/dist/esm/NodeStream.js +37 -0
- package/dist/esm/NodeStream.js.map +1 -0
- package/dist/esm/NodeTerminal.js +12 -0
- package/dist/esm/NodeTerminal.js.map +1 -0
- package/dist/esm/internal/commandExecutor.js +120 -0
- package/dist/esm/internal/commandExecutor.js.map +1 -0
- package/dist/esm/internal/error.js +37 -0
- package/dist/esm/internal/error.js.map +1 -0
- package/dist/esm/internal/fileSystem.js +339 -0
- package/dist/esm/internal/fileSystem.js.map +1 -0
- package/dist/esm/internal/http/etag.js +43 -0
- package/dist/esm/internal/http/etag.js.map +1 -0
- package/dist/esm/internal/http/multipart.js +85 -0
- package/dist/esm/internal/http/multipart.js.map +1 -0
- package/dist/esm/internal/path.js +41 -0
- package/dist/esm/internal/path.js.map +1 -0
- package/dist/esm/internal/runtime.js +27 -0
- package/dist/esm/internal/runtime.js.map +1 -0
- package/dist/esm/internal/sink.js +19 -0
- package/dist/esm/internal/sink.js.map +1 -0
- package/dist/esm/internal/stream.js +170 -0
- package/dist/esm/internal/stream.js.map +1 -0
- package/dist/esm/internal/terminal.js +89 -0
- package/dist/esm/internal/terminal.js.map +1 -0
- package/dist/esm/package.json +4 -0
- package/package.json +105 -0
- package/src/Http/Etag.ts +18 -0
- package/src/Http/Multipart.ts +40 -0
- package/src/NodeCommandExecutor.ts +13 -0
- package/src/NodeFileSystem.ts +13 -0
- package/src/NodeKeyValueStore.ts +20 -0
- package/src/NodePath.ts +25 -0
- package/src/NodeRuntime.ts +11 -0
- package/src/NodeSink.ts +30 -0
- package/src/NodeStream.ts +109 -0
- package/src/NodeTerminal.ts +20 -0
- package/src/internal/commandExecutor.ts +203 -0
- package/src/internal/error.ts +51 -0
- package/src/internal/fileSystem.ts +575 -0
- package/src/internal/http/etag.ts +44 -0
- package/src/internal/http/multipart.ts +107 -0
- package/src/internal/path.ts +58 -0
- package/src/internal/runtime.ts +36 -0
- package/src/internal/sink.ts +57 -0
- package/src/internal/stream.ts +325 -0
- package/src/internal/terminal.ts +123 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
import type { PlatformError } from "@effect/platform/Error"
|
|
5
|
+
import type { SizeInput } from "@effect/platform/FileSystem"
|
|
6
|
+
import type { Channel } from "effect/Channel"
|
|
7
|
+
import type { Chunk } from "effect/Chunk"
|
|
8
|
+
import type { Effect } from "effect/Effect"
|
|
9
|
+
import type { LazyArg } from "effect/Function"
|
|
10
|
+
import type { Stream } from "effect/Stream"
|
|
11
|
+
import type { Duplex, Readable } from "node:stream"
|
|
12
|
+
import * as internal from "./internal/stream.js"
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @category models
|
|
16
|
+
* @since 1.0.0
|
|
17
|
+
*/
|
|
18
|
+
export interface FromReadableOptions {
|
|
19
|
+
/** Defaults to undefined, which lets Node.js decide the chunk size */
|
|
20
|
+
readonly chunkSize?: SizeInput
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @category model
|
|
25
|
+
* @since 1.0.0
|
|
26
|
+
*/
|
|
27
|
+
export interface FromWritableOptions {
|
|
28
|
+
readonly endOnDone?: boolean
|
|
29
|
+
readonly encoding?: BufferEncoding
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @category constructors
|
|
34
|
+
* @since 1.0.0
|
|
35
|
+
*/
|
|
36
|
+
export const fromReadable: <E, A = Uint8Array>(
|
|
37
|
+
evaluate: LazyArg<Readable | NodeJS.ReadableStream>,
|
|
38
|
+
onError: (error: unknown) => E,
|
|
39
|
+
{ chunkSize }?: FromReadableOptions
|
|
40
|
+
) => Stream<A, E> = internal.fromReadable
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @category constructors
|
|
44
|
+
* @since 1.0.0
|
|
45
|
+
*/
|
|
46
|
+
export const fromReadableChannel: <E, A = Uint8Array>(
|
|
47
|
+
evaluate: LazyArg<Readable | NodeJS.ReadableStream>,
|
|
48
|
+
onError: (error: unknown) => E,
|
|
49
|
+
chunkSize: number | undefined
|
|
50
|
+
) => Channel<never, unknown, unknown, unknown, E, Chunk<A>, void> = internal.fromReadableChannel
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @category constructors
|
|
54
|
+
* @since 1.0.0
|
|
55
|
+
*/
|
|
56
|
+
export const fromDuplex: <IE, E, I = Uint8Array, O = Uint8Array>(
|
|
57
|
+
evaluate: LazyArg<Duplex>,
|
|
58
|
+
onError: (error: unknown) => E,
|
|
59
|
+
options?: FromReadableOptions & FromWritableOptions
|
|
60
|
+
) => Channel<never, IE, Chunk<I>, unknown, IE | E, Chunk<O>, void> = internal.fromDuplex
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @category combinators
|
|
64
|
+
* @since 1.0.0
|
|
65
|
+
*/
|
|
66
|
+
export const pipeThroughDuplex: {
|
|
67
|
+
<E2, B = Uint8Array>(
|
|
68
|
+
duplex: LazyArg<Duplex>,
|
|
69
|
+
onError: (error: unknown) => E2,
|
|
70
|
+
options?: (FromReadableOptions & FromWritableOptions) | undefined
|
|
71
|
+
): <R, E, A>(self: Stream<A, E, R>) => Stream<B, E2 | E, R>
|
|
72
|
+
<R, E, A, E2, B = Uint8Array>(
|
|
73
|
+
self: Stream<A, E, R>,
|
|
74
|
+
duplex: LazyArg<Duplex>,
|
|
75
|
+
onError: (error: unknown) => E2,
|
|
76
|
+
options?: (FromReadableOptions & FromWritableOptions) | undefined
|
|
77
|
+
): Stream<B, E | E2, R>
|
|
78
|
+
} = internal.pipeThroughDuplex
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @category combinators
|
|
82
|
+
* @since 1.0.0
|
|
83
|
+
*/
|
|
84
|
+
export const pipeThroughSimple: {
|
|
85
|
+
(duplex: LazyArg<Duplex>): <R, E>(self: Stream<string | Uint8Array, E, R>) => Stream<Uint8Array, E | PlatformError, R>
|
|
86
|
+
<R, E>(self: Stream<string | Uint8Array, E, R>, duplex: LazyArg<Duplex>): Stream<Uint8Array, PlatformError | E, R>
|
|
87
|
+
} = internal.pipeThroughSimple
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @since 1.0.0
|
|
91
|
+
* @category conversions
|
|
92
|
+
*/
|
|
93
|
+
export const toString: <E>(
|
|
94
|
+
readable: LazyArg<Readable | NodeJS.ReadableStream>,
|
|
95
|
+
options: {
|
|
96
|
+
readonly onFailure: (error: unknown) => E
|
|
97
|
+
readonly encoding?: BufferEncoding | undefined
|
|
98
|
+
readonly maxBytes?: SizeInput | undefined
|
|
99
|
+
}
|
|
100
|
+
) => Effect<string, E> = internal.toString
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @since 1.0.0
|
|
104
|
+
* @category conversions
|
|
105
|
+
*/
|
|
106
|
+
export const toUint8Array: <E>(
|
|
107
|
+
readable: LazyArg<Readable | NodeJS.ReadableStream>,
|
|
108
|
+
options: { readonly onFailure: (error: unknown) => E; readonly maxBytes?: SizeInput | undefined }
|
|
109
|
+
) => Effect<Uint8Array, E> = internal.toUint8Array
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
import type { Terminal, UserInput } from "@effect/platform/Terminal"
|
|
5
|
+
import type { Effect } from "effect/Effect"
|
|
6
|
+
import type { Layer } from "effect/Layer"
|
|
7
|
+
import type { Scope } from "effect/Scope"
|
|
8
|
+
import * as InternalTerminal from "./internal/terminal.js"
|
|
9
|
+
/**
|
|
10
|
+
* @since 1.0.0
|
|
11
|
+
* @category constructors
|
|
12
|
+
*/
|
|
13
|
+
export const make: (shouldQuit?: (input: UserInput) => boolean) => Effect<Terminal, never, Scope> =
|
|
14
|
+
InternalTerminal.make
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @since 1.0.0
|
|
18
|
+
* @category layer
|
|
19
|
+
*/
|
|
20
|
+
export const layer: Layer<Terminal> = InternalTerminal.layer
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import * as Command from "@effect/platform/Command"
|
|
2
|
+
import * as CommandExecutor from "@effect/platform/CommandExecutor"
|
|
3
|
+
import type * as Error from "@effect/platform/Error"
|
|
4
|
+
import * as FileSystem from "@effect/platform/FileSystem"
|
|
5
|
+
import * as Deferred from "effect/Deferred"
|
|
6
|
+
import * as Effect from "effect/Effect"
|
|
7
|
+
import { constUndefined, pipe } from "effect/Function"
|
|
8
|
+
import * as Layer from "effect/Layer"
|
|
9
|
+
import * as Option from "effect/Option"
|
|
10
|
+
import type * as Scope from "effect/Scope"
|
|
11
|
+
import * as Sink from "effect/Sink"
|
|
12
|
+
import * as Stream from "effect/Stream"
|
|
13
|
+
import * as ChildProcess from "node:child_process"
|
|
14
|
+
import { handleErrnoException } from "./error.js"
|
|
15
|
+
import { fromWritable } from "./sink.js"
|
|
16
|
+
import { fromReadable } from "./stream.js"
|
|
17
|
+
|
|
18
|
+
const inputToStdioOption = (stdin: Option.Option<Command.Command.Input>): "pipe" | "inherit" =>
|
|
19
|
+
Option.match(stdin, { onNone: () => "inherit", onSome: () => "pipe" })
|
|
20
|
+
|
|
21
|
+
const outputToStdioOption = (output: Command.Command.Output): "pipe" | "inherit" =>
|
|
22
|
+
typeof output === "string" ? output : "pipe"
|
|
23
|
+
|
|
24
|
+
const toError = (err: unknown): Error => err instanceof globalThis.Error ? err : new globalThis.Error(String(err))
|
|
25
|
+
|
|
26
|
+
const toPlatformError = (
|
|
27
|
+
method: string,
|
|
28
|
+
error: NodeJS.ErrnoException,
|
|
29
|
+
command: Command.Command
|
|
30
|
+
): Error.PlatformError => {
|
|
31
|
+
const flattened = Command.flatten(command).reduce((acc, curr) => {
|
|
32
|
+
const command = `${curr.command} ${curr.args.join(" ")}`
|
|
33
|
+
return acc.length === 0 ? command : `${acc} | ${command}`
|
|
34
|
+
}, "")
|
|
35
|
+
return handleErrnoException("Command", method)(error, [flattened])
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type ExitCode = readonly [code: number | null, signal: NodeJS.Signals | null]
|
|
39
|
+
type ExitCodeDeferred = Deferred.Deferred<never, ExitCode>
|
|
40
|
+
|
|
41
|
+
const runCommand =
|
|
42
|
+
(fileSystem: FileSystem.FileSystem) =>
|
|
43
|
+
(command: Command.Command): Effect.Effect<CommandExecutor.Process, Error.PlatformError, Scope.Scope> => {
|
|
44
|
+
switch (command._tag) {
|
|
45
|
+
case "StandardCommand": {
|
|
46
|
+
const spawn = Effect.flatMap(
|
|
47
|
+
Deferred.make<never, ExitCode>(),
|
|
48
|
+
(exitCode) =>
|
|
49
|
+
Effect.async<readonly [ChildProcess.ChildProcess, ExitCodeDeferred], Error.PlatformError, never>(
|
|
50
|
+
(resume) => {
|
|
51
|
+
const handle = ChildProcess.spawn(command.command, command.args, {
|
|
52
|
+
stdio: [
|
|
53
|
+
inputToStdioOption(command.stdin),
|
|
54
|
+
outputToStdioOption(command.stdout),
|
|
55
|
+
outputToStdioOption(command.stderr)
|
|
56
|
+
],
|
|
57
|
+
cwd: Option.getOrElse(command.cwd, constUndefined),
|
|
58
|
+
shell: command.shell,
|
|
59
|
+
env: { ...process.env, ...Object.fromEntries(command.env) }
|
|
60
|
+
})
|
|
61
|
+
handle.on("error", (err) => {
|
|
62
|
+
resume(Effect.fail(toPlatformError("spawn", err, command)))
|
|
63
|
+
})
|
|
64
|
+
handle.on("exit", (...args) => {
|
|
65
|
+
Deferred.unsafeDone(exitCode, Effect.succeed(args))
|
|
66
|
+
})
|
|
67
|
+
handle.on("spawn", () => {
|
|
68
|
+
resume(Effect.succeed([handle, exitCode]))
|
|
69
|
+
})
|
|
70
|
+
return Effect.sync(() => {
|
|
71
|
+
handle.kill("SIGTERM")
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
return pipe(
|
|
77
|
+
// Validate that the directory is accessible
|
|
78
|
+
Option.match(command.cwd, {
|
|
79
|
+
onNone: () => Effect.unit,
|
|
80
|
+
onSome: (dir) => fileSystem.access(dir)
|
|
81
|
+
}),
|
|
82
|
+
Effect.zipRight(
|
|
83
|
+
Effect.acquireRelease(
|
|
84
|
+
spawn,
|
|
85
|
+
([handle, exitCode]) =>
|
|
86
|
+
Effect.flatMap(Deferred.isDone(exitCode), (done) =>
|
|
87
|
+
done ? Effect.unit : Effect.suspend(() => {
|
|
88
|
+
if (handle.kill("SIGTERM")) {
|
|
89
|
+
return Deferred.await(exitCode)
|
|
90
|
+
}
|
|
91
|
+
return Effect.unit
|
|
92
|
+
}))
|
|
93
|
+
)
|
|
94
|
+
),
|
|
95
|
+
Effect.map(([handle, exitCodeDeferred]): CommandExecutor.Process => {
|
|
96
|
+
let stdin: Sink.Sink<never, Error.PlatformError, unknown, never, void> = Sink.drain
|
|
97
|
+
|
|
98
|
+
if (handle.stdin !== null) {
|
|
99
|
+
stdin = fromWritable(
|
|
100
|
+
() => handle.stdin!,
|
|
101
|
+
(err) => toPlatformError("toWritable", toError(err), command)
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const exitCode: CommandExecutor.Process["exitCode"] = Effect.flatMap(
|
|
106
|
+
Deferred.await(exitCodeDeferred),
|
|
107
|
+
([code, signal]) => {
|
|
108
|
+
if (code !== null) {
|
|
109
|
+
return Effect.succeed(CommandExecutor.ExitCode(code))
|
|
110
|
+
}
|
|
111
|
+
// If code is `null`, then `signal` must be defined. See the NodeJS
|
|
112
|
+
// documentation for the `"exit"` event on a `child_process`.
|
|
113
|
+
// https://nodejs.org/api/child_process.html#child_process_event_exit
|
|
114
|
+
return Effect.fail(
|
|
115
|
+
toPlatformError(
|
|
116
|
+
"exitCode",
|
|
117
|
+
new globalThis.Error(`Process interrupted due to receipt of signal: ${signal}`),
|
|
118
|
+
command
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
const isRunning = Effect.negate(Deferred.isDone(exitCodeDeferred))
|
|
125
|
+
|
|
126
|
+
const kill: CommandExecutor.Process["kill"] = (signal = "SIGTERM") =>
|
|
127
|
+
Effect.suspend(() =>
|
|
128
|
+
handle.kill(signal)
|
|
129
|
+
? Effect.asUnit(Deferred.await(exitCodeDeferred))
|
|
130
|
+
: Effect.fail(toPlatformError("kill", new globalThis.Error("Failed to kill process"), command))
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
const pid = CommandExecutor.ProcessId(handle.pid!)
|
|
134
|
+
const stderr = fromReadable<Error.PlatformError, Uint8Array>(
|
|
135
|
+
() => handle.stderr!,
|
|
136
|
+
(err) => toPlatformError("fromReadable(stderr)", toError(err), command)
|
|
137
|
+
)
|
|
138
|
+
let stdout: Stream.Stream<Uint8Array, Error.PlatformError> = fromReadable<
|
|
139
|
+
Error.PlatformError,
|
|
140
|
+
Uint8Array
|
|
141
|
+
>(
|
|
142
|
+
() => handle.stdout!,
|
|
143
|
+
(err) => toPlatformError("fromReadable(stdout)", toError(err), command)
|
|
144
|
+
)
|
|
145
|
+
// TODO: add Sink.isSink
|
|
146
|
+
if (typeof command.stdout !== "string") {
|
|
147
|
+
stdout = Stream.transduce(stdout, command.stdout)
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
[CommandExecutor.ProcessTypeId]: CommandExecutor.ProcessTypeId,
|
|
151
|
+
pid,
|
|
152
|
+
exitCode,
|
|
153
|
+
isRunning,
|
|
154
|
+
kill,
|
|
155
|
+
stdin,
|
|
156
|
+
stderr,
|
|
157
|
+
stdout
|
|
158
|
+
}
|
|
159
|
+
}),
|
|
160
|
+
Effect.tap((process) =>
|
|
161
|
+
Option.match(command.stdin, {
|
|
162
|
+
onNone: () => Effect.unit,
|
|
163
|
+
onSome: (stdin) => Effect.forkDaemon(Stream.run(stdin, process.stdin))
|
|
164
|
+
})
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
case "PipedCommand": {
|
|
169
|
+
const flattened = Command.flatten(command)
|
|
170
|
+
if (flattened.length === 1) {
|
|
171
|
+
return pipe(flattened[0], runCommand(fileSystem))
|
|
172
|
+
}
|
|
173
|
+
const head = flattened[0]
|
|
174
|
+
const tail = flattened.slice(1)
|
|
175
|
+
const initial = tail.slice(0, tail.length - 1)
|
|
176
|
+
const last = tail[tail.length - 1]
|
|
177
|
+
const stream = initial.reduce(
|
|
178
|
+
(stdin, command) =>
|
|
179
|
+
pipe(
|
|
180
|
+
Command.stdin(command, stdin),
|
|
181
|
+
runCommand(fileSystem),
|
|
182
|
+
Effect.map((process) => process.stdout),
|
|
183
|
+
Stream.unwrapScoped
|
|
184
|
+
),
|
|
185
|
+
pipe(
|
|
186
|
+
runCommand(fileSystem)(head),
|
|
187
|
+
Effect.map((process) => process.stdout),
|
|
188
|
+
Stream.unwrapScoped
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
return pipe(Command.stdin(last, stream), runCommand(fileSystem))
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** @internal */
|
|
197
|
+
export const layer: Layer.Layer<CommandExecutor.CommandExecutor, never, FileSystem.FileSystem> = Layer.effect(
|
|
198
|
+
CommandExecutor.CommandExecutor,
|
|
199
|
+
pipe(
|
|
200
|
+
FileSystem.FileSystem,
|
|
201
|
+
Effect.map((fileSystem) => CommandExecutor.makeExecutor(runCommand(fileSystem)))
|
|
202
|
+
)
|
|
203
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { PlatformError, SystemErrorReason } from "@effect/platform/Error"
|
|
2
|
+
import { SystemError } from "@effect/platform/Error"
|
|
3
|
+
import type { PathLike } from "node:fs"
|
|
4
|
+
|
|
5
|
+
/** @internal */
|
|
6
|
+
export const handleErrnoException = (module: SystemError["module"], method: string) =>
|
|
7
|
+
(
|
|
8
|
+
err: NodeJS.ErrnoException,
|
|
9
|
+
[path]: [path: PathLike | number, ...args: Array<any>]
|
|
10
|
+
): PlatformError => {
|
|
11
|
+
let reason: SystemErrorReason = "Unknown"
|
|
12
|
+
|
|
13
|
+
switch (err.code) {
|
|
14
|
+
case "ENOENT":
|
|
15
|
+
reason = "NotFound"
|
|
16
|
+
break
|
|
17
|
+
|
|
18
|
+
case "EACCES":
|
|
19
|
+
reason = "PermissionDenied"
|
|
20
|
+
break
|
|
21
|
+
|
|
22
|
+
case "EEXIST":
|
|
23
|
+
reason = "AlreadyExists"
|
|
24
|
+
break
|
|
25
|
+
|
|
26
|
+
case "EISDIR":
|
|
27
|
+
reason = "BadResource"
|
|
28
|
+
break
|
|
29
|
+
|
|
30
|
+
case "ENOTDIR":
|
|
31
|
+
reason = "BadResource"
|
|
32
|
+
break
|
|
33
|
+
|
|
34
|
+
case "EBUSY":
|
|
35
|
+
reason = "Busy"
|
|
36
|
+
break
|
|
37
|
+
|
|
38
|
+
case "ELOOP":
|
|
39
|
+
reason = "BadResource"
|
|
40
|
+
break
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return SystemError({
|
|
44
|
+
reason,
|
|
45
|
+
module,
|
|
46
|
+
method,
|
|
47
|
+
pathOrDescriptor: path as string | number,
|
|
48
|
+
syscall: err.syscall,
|
|
49
|
+
message: err.message
|
|
50
|
+
})
|
|
51
|
+
}
|