File size: 3,642 Bytes
4e23b01
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import * as posixPath from 'node:path/posix';
import * as win32Path from 'node:path/win32';

import { Emitter } from '#/_base/event';
import { IHostEnvironment } from '#/os/interface/hostEnvironment';
import { IHostFileSystem } from '#/os/interface/hostFileSystem';
import { IHostProcessService } from '#/os/interface/hostProcess';
import { IHostTerminalService } from '#/os/interface/terminal';

import type { Runtime, RuntimeCapability, RuntimePath, RuntimeStatus } from './runtime';
import type { RuntimeProviderAttachment, RuntimeProviderContext, RuntimeProviderFactory } from './runtimeProvider';
import type { RuntimeProviderHost } from './runtimeUnitHost';

let nextGeneration = 1;

export class LocalRuntime implements Runtime {
  readonly identity;
  readonly capabilities: ReadonlySet<RuntimeCapability>;
  readonly environment;
  readonly path: RuntimePath;
  readonly workspace: Runtime['workspace'];
  readonly fs;
  readonly process;
  readonly terminal;
  private currentStatus: RuntimeStatus = 'ready';
  private readonly statusEmitter = new Emitter<RuntimeStatus>();
  readonly onDidChangeStatus = this.statusEmitter.event;

  constructor(
    workspaceId: string,
    environment: IHostEnvironment,
    fs: IHostFileSystem | undefined,
    process: IHostProcessService | undefined,
    terminal: IHostTerminalService | undefined,
  ) {
    this.identity = { workspaceId, runtimeId: 'local', generation: `local-${nextGeneration++}` };
    const capabilities = new Set<RuntimeCapability>();
    if (fs !== undefined) capabilities.add('fs');
    if (process !== undefined) capabilities.add('process');
    if (terminal !== undefined) capabilities.add('terminal');
    this.capabilities = capabilities;
    this.environment = {
      osKind: environment.osKind,
      osArch: environment.osArch,
      osVersion: environment.osVersion,
      shellName: environment.shellName,
      shellPath: environment.shellPath,
      pathClass: environment.pathClass,
      homeDir: environment.homeDir,
    };
    const path = environment.pathClass === 'win32' ? win32Path : posixPath;
    this.path = {
      separator: path.sep as '/' | '\\',
      delimiter: path.delimiter as ':' | ';',
      isAbsolute: (p) => path.isAbsolute(p),
      join: (...paths) => path.join(...paths),
      relative: (from, to) => path.relative(from, to),
      resolve: (...paths) => path.resolve(...paths),
      basename: (p) => path.basename(p),
      dirname: (p) => path.dirname(p),
    };
    this.workspace = {
      mapRoots: (roots) => ({
        workDir: path.resolve(roots.workDir),
        additionalDirs: roots.additionalDirs?.map((root) => path.resolve(root)),
      }),
    };
    this.fs = fs;
    this.process = process;
    this.terminal = terminal;
  }

  get status(): RuntimeStatus {
    return this.currentStatus;
  }

  dispose(): void {
    this.currentStatus = 'disposed';
    this.statusEmitter.fire('disposed');
    this.statusEmitter.dispose();
  }
}

export class LocalRuntimeProviderFactory implements RuntimeProviderFactory {
  readonly id = 'local';
  readonly imports = {
    root: [
      IHostEnvironment,
      IHostFileSystem,
      IHostProcessService,
      IHostTerminalService,
    ],
    imports: [],
    local: [],
  };

  async attach(context: RuntimeProviderContext, host: RuntimeProviderHost): Promise<RuntimeProviderAttachment> {
    const handle = host.registerRuntime(new LocalRuntime(
      context.id,
      host.get(IHostEnvironment),
      host.get(IHostFileSystem),
      host.get(IHostProcessService),
      host.get(IHostTerminalService),
    ));
    return { dispose: () => handle.remove() };
  }
}