File size: 2,606 Bytes
68d7816
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import type { Readable, Writable } from 'node:stream';

import { registerErrorDomain, type ErrorDomain } from '#/_base/errors/codes';
import { Error2, type Error2Options } from '#/_base/errors/errors';
import { createDecorator, type ServiceIdentifier } from '#/_base/di/instantiation';

export interface HostProcessOptions {
  readonly cwd?: string;
  readonly env?: Record<string, string>;
  readonly shell?: boolean | string;
  readonly detached?: boolean;
  readonly windowsHide?: boolean;
  readonly mergeStderr?: boolean;
  readonly timeout?: number;
}

export interface IHostProcess {
  readonly _serviceBrand: undefined;

  readonly pid: number;
  readonly exitCode: number | null;
  readonly stdin: Writable;
  readonly stdout: Readable;
  readonly stderr: Readable;
  wait(): Promise<number>;
  kill(signal?: NodeJS.Signals): Promise<void>;
  dispose(): void | Promise<void>;
}

export interface IHostProcessService {
  readonly _serviceBrand: undefined;

  spawn(
    command: string,
    args?: readonly string[],
    options?: HostProcessOptions,
  ): Promise<IHostProcess>;
}

export const IHostProcessService: ServiceIdentifier<IHostProcessService> =
  createDecorator<IHostProcessService>('hostProcessService');

export const OsProcessErrors = {
  codes: {
    OS_PROCESS_SPAWN_FAILED: 'os.process.spawn_failed',
    OS_PROCESS_KILL_FAILED: 'os.process.kill_failed',
    SHELL_GIT_BASH_NOT_FOUND: 'shell.git_bash_not_found',
  },
  info: {
    'os.process.spawn_failed': {
      title: 'Failed to spawn process',
      retryable: false,
      public: true,
      action: 'Check that the command exists and is executable.',
    },
    'os.process.kill_failed': {
      title: 'Failed to kill process',
      retryable: false,
      public: true,
    },
    'shell.git_bash_not_found': {
      title: 'Git Bash not found',
      retryable: false,
      public: true,
      action: 'Install Git for Windows so shell commands can run under Git Bash.',
    },
  },
} as const satisfies ErrorDomain;

registerErrorDomain(OsProcessErrors);

export const HostProcessErrorCode = {
  SpawnFailed: OsProcessErrors.codes.OS_PROCESS_SPAWN_FAILED,
  KillFailed: OsProcessErrors.codes.OS_PROCESS_KILL_FAILED,
  ShellGitBashNotFound: OsProcessErrors.codes.SHELL_GIT_BASH_NOT_FOUND,
} as const;

export type HostProcessErrorCode = (typeof HostProcessErrorCode)[keyof typeof HostProcessErrorCode];

export class HostProcessError extends Error2 {
  constructor(code: HostProcessErrorCode, message: string, options?: Error2Options) {
    super(code, message, options);
    this.name = 'HostProcessError';
  }
}