@shitiandmw/node-pty 1.1.0-agent.0
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 +69 -0
- package/README.md +170 -0
- package/binding.gyp +111 -0
- package/deps/.editorconfig +2 -0
- package/deps/winpty/.drone.yml +17 -0
- package/deps/winpty/.gitattributes +19 -0
- package/deps/winpty/LICENSE +21 -0
- package/deps/winpty/Makefile +166 -0
- package/deps/winpty/README.md +151 -0
- package/deps/winpty/RELEASES.md +280 -0
- package/deps/winpty/VERSION.txt +1 -0
- package/deps/winpty/configure +167 -0
- package/deps/winpty/misc/BufferResizeTests.cc +90 -0
- package/deps/winpty/misc/ChangeScreenBuffer.cc +53 -0
- package/deps/winpty/misc/ClearConsole.cc +72 -0
- package/deps/winpty/misc/ConinMode.cc +117 -0
- package/deps/winpty/misc/ConinMode.ps1 +116 -0
- package/deps/winpty/misc/ConoutMode.cc +113 -0
- package/deps/winpty/misc/DebugClient.py +42 -0
- package/deps/winpty/misc/DebugServer.py +63 -0
- package/deps/winpty/misc/DumpLines.py +5 -0
- package/deps/winpty/misc/EnableExtendedFlags.txt +46 -0
- package/deps/winpty/misc/Font-Report-June2016/CP437-Consolas.txt +528 -0
- package/deps/winpty/misc/Font-Report-June2016/CP437-Lucida.txt +633 -0
- package/deps/winpty/misc/Font-Report-June2016/CP932.txt +630 -0
- package/deps/winpty/misc/Font-Report-June2016/CP936.txt +630 -0
- package/deps/winpty/misc/Font-Report-June2016/CP949.txt +630 -0
- package/deps/winpty/misc/Font-Report-June2016/CP950.txt +630 -0
- package/deps/winpty/misc/Font-Report-June2016/MinimumWindowWidths.txt +16 -0
- package/deps/winpty/misc/Font-Report-June2016/Results.txt +4 -0
- package/deps/winpty/misc/Font-Report-June2016/Windows10SetFontBugginess.txt +144 -0
- package/deps/winpty/misc/FontSurvey.cc +100 -0
- package/deps/winpty/misc/FormatChar.h +21 -0
- package/deps/winpty/misc/FreezePerfTest.cc +62 -0
- package/deps/winpty/misc/GetCh.cc +20 -0
- package/deps/winpty/misc/GetConsolePos.cc +41 -0
- package/deps/winpty/misc/GetFont.cc +261 -0
- package/deps/winpty/misc/IdentifyConsoleWindow.ps1 +51 -0
- package/deps/winpty/misc/IsNewConsole.cc +87 -0
- package/deps/winpty/misc/MouseInputNotes.txt +90 -0
- package/deps/winpty/misc/MoveConsoleWindow.cc +34 -0
- package/deps/winpty/misc/Notes.txt +219 -0
- package/deps/winpty/misc/OSVersion.cc +27 -0
- package/deps/winpty/misc/ScreenBufferFreezeInactive.cc +101 -0
- package/deps/winpty/misc/ScreenBufferTest.cc +671 -0
- package/deps/winpty/misc/ScreenBufferTest2.cc +151 -0
- package/deps/winpty/misc/SelectAllTest.cc +45 -0
- package/deps/winpty/misc/SetBufferSize.cc +32 -0
- package/deps/winpty/misc/SetCursorPos.cc +10 -0
- package/deps/winpty/misc/SetFont.cc +145 -0
- package/deps/winpty/misc/SetWindowRect.cc +36 -0
- package/deps/winpty/misc/ShowArgv.cc +12 -0
- package/deps/winpty/misc/ShowConsoleInput.cc +40 -0
- package/deps/winpty/misc/Spew.py +5 -0
- package/deps/winpty/misc/TestUtil.cc +172 -0
- package/deps/winpty/misc/UnicodeDoubleWidthTest.cc +102 -0
- package/deps/winpty/misc/UnicodeWideTest1.cc +246 -0
- package/deps/winpty/misc/UnicodeWideTest2.cc +130 -0
- package/deps/winpty/misc/UnixEcho.cc +89 -0
- package/deps/winpty/misc/Utf16Echo.cc +46 -0
- package/deps/winpty/misc/VeryLargeRead.cc +122 -0
- package/deps/winpty/misc/VkEscapeTest.cc +56 -0
- package/deps/winpty/misc/Win10ResizeWhileFrozen.cc +52 -0
- package/deps/winpty/misc/Win10WrapTest1.cc +57 -0
- package/deps/winpty/misc/Win10WrapTest2.cc +30 -0
- package/deps/winpty/misc/Win32Echo1.cc +26 -0
- package/deps/winpty/misc/Win32Echo2.cc +19 -0
- package/deps/winpty/misc/Win32Test1.cc +46 -0
- package/deps/winpty/misc/Win32Test2.cc +70 -0
- package/deps/winpty/misc/Win32Test3.cc +78 -0
- package/deps/winpty/misc/Win32Write1.cc +44 -0
- package/deps/winpty/misc/WindowsBugCrashReader.cc +27 -0
- package/deps/winpty/misc/WriteConsole.cc +106 -0
- package/deps/winpty/misc/build32.sh +9 -0
- package/deps/winpty/misc/build64.sh +9 -0
- package/deps/winpty/misc/color-test.sh +212 -0
- package/deps/winpty/misc/font-notes.txt +300 -0
- package/deps/winpty/misc/winbug-15048.cc +201 -0
- package/deps/winpty/ship/build-pty4j-libpty.bat +36 -0
- package/deps/winpty/ship/common_ship.py +53 -0
- package/deps/winpty/ship/make_msvc_package.py +165 -0
- package/deps/winpty/ship/ship.py +108 -0
- package/deps/winpty/src/agent/Agent.cc +613 -0
- package/deps/winpty/src/agent/Agent.h +103 -0
- package/deps/winpty/src/agent/AgentCreateDesktop.cc +84 -0
- package/deps/winpty/src/agent/AgentCreateDesktop.h +28 -0
- package/deps/winpty/src/agent/ConsoleFont.cc +632 -0
- package/deps/winpty/src/agent/ConsoleFont.h +28 -0
- package/deps/winpty/src/agent/ConsoleInput.cc +852 -0
- package/deps/winpty/src/agent/ConsoleInput.h +109 -0
- package/deps/winpty/src/agent/ConsoleInputReencoding.cc +121 -0
- package/deps/winpty/src/agent/ConsoleInputReencoding.h +36 -0
- package/deps/winpty/src/agent/ConsoleLine.cc +152 -0
- package/deps/winpty/src/agent/ConsoleLine.h +41 -0
- package/deps/winpty/src/agent/Coord.h +87 -0
- package/deps/winpty/src/agent/DebugShowInput.cc +239 -0
- package/deps/winpty/src/agent/DebugShowInput.h +32 -0
- package/deps/winpty/src/agent/DefaultInputMap.cc +422 -0
- package/deps/winpty/src/agent/DefaultInputMap.h +28 -0
- package/deps/winpty/src/agent/DsrSender.h +30 -0
- package/deps/winpty/src/agent/EventLoop.cc +99 -0
- package/deps/winpty/src/agent/EventLoop.h +47 -0
- package/deps/winpty/src/agent/InputMap.cc +246 -0
- package/deps/winpty/src/agent/InputMap.h +114 -0
- package/deps/winpty/src/agent/LargeConsoleRead.cc +71 -0
- package/deps/winpty/src/agent/LargeConsoleRead.h +68 -0
- package/deps/winpty/src/agent/NamedPipe.cc +378 -0
- package/deps/winpty/src/agent/NamedPipe.h +125 -0
- package/deps/winpty/src/agent/Scraper.cc +699 -0
- package/deps/winpty/src/agent/Scraper.h +103 -0
- package/deps/winpty/src/agent/SimplePool.h +75 -0
- package/deps/winpty/src/agent/SmallRect.h +143 -0
- package/deps/winpty/src/agent/Terminal.cc +535 -0
- package/deps/winpty/src/agent/Terminal.h +69 -0
- package/deps/winpty/src/agent/UnicodeEncoding.h +157 -0
- package/deps/winpty/src/agent/UnicodeEncodingTest.cc +189 -0
- package/deps/winpty/src/agent/Win32Console.cc +107 -0
- package/deps/winpty/src/agent/Win32Console.h +67 -0
- package/deps/winpty/src/agent/Win32ConsoleBuffer.cc +193 -0
- package/deps/winpty/src/agent/Win32ConsoleBuffer.h +99 -0
- package/deps/winpty/src/agent/main.cc +114 -0
- package/deps/winpty/src/agent/subdir.mk +61 -0
- package/deps/winpty/src/configurations.gypi +60 -0
- package/deps/winpty/src/debugserver/DebugServer.cc +117 -0
- package/deps/winpty/src/debugserver/subdir.mk +41 -0
- package/deps/winpty/src/include/winpty.h +242 -0
- package/deps/winpty/src/include/winpty_constants.h +131 -0
- package/deps/winpty/src/libwinpty/AgentLocation.cc +75 -0
- package/deps/winpty/src/libwinpty/AgentLocation.h +28 -0
- package/deps/winpty/src/libwinpty/LibWinptyException.h +54 -0
- package/deps/winpty/src/libwinpty/WinptyInternal.h +72 -0
- package/deps/winpty/src/libwinpty/subdir.mk +46 -0
- package/deps/winpty/src/libwinpty/winpty.cc +970 -0
- package/deps/winpty/src/shared/AgentMsg.h +38 -0
- package/deps/winpty/src/shared/BackgroundDesktop.cc +122 -0
- package/deps/winpty/src/shared/BackgroundDesktop.h +73 -0
- package/deps/winpty/src/shared/Buffer.cc +103 -0
- package/deps/winpty/src/shared/Buffer.h +102 -0
- package/deps/winpty/src/shared/DebugClient.cc +187 -0
- package/deps/winpty/src/shared/DebugClient.h +38 -0
- package/deps/winpty/src/shared/GenRandom.cc +138 -0
- package/deps/winpty/src/shared/GenRandom.h +55 -0
- package/deps/winpty/src/shared/GetCommitHash.bat +13 -0
- package/deps/winpty/src/shared/Mutex.h +54 -0
- package/deps/winpty/src/shared/OsModule.h +63 -0
- package/deps/winpty/src/shared/OwnedHandle.cc +36 -0
- package/deps/winpty/src/shared/OwnedHandle.h +45 -0
- package/deps/winpty/src/shared/PrecompiledHeader.h +43 -0
- package/deps/winpty/src/shared/StringBuilder.h +227 -0
- package/deps/winpty/src/shared/StringBuilderTest.cc +114 -0
- package/deps/winpty/src/shared/StringUtil.cc +55 -0
- package/deps/winpty/src/shared/StringUtil.h +80 -0
- package/deps/winpty/src/shared/TimeMeasurement.h +63 -0
- package/deps/winpty/src/shared/UnixCtrlChars.h +45 -0
- package/deps/winpty/src/shared/UpdateGenVersion.bat +20 -0
- package/deps/winpty/src/shared/WindowsSecurity.cc +460 -0
- package/deps/winpty/src/shared/WindowsSecurity.h +104 -0
- package/deps/winpty/src/shared/WindowsVersion.cc +252 -0
- package/deps/winpty/src/shared/WindowsVersion.h +29 -0
- package/deps/winpty/src/shared/WinptyAssert.cc +55 -0
- package/deps/winpty/src/shared/WinptyAssert.h +64 -0
- package/deps/winpty/src/shared/WinptyException.cc +57 -0
- package/deps/winpty/src/shared/WinptyException.h +43 -0
- package/deps/winpty/src/shared/WinptyVersion.cc +42 -0
- package/deps/winpty/src/shared/WinptyVersion.h +27 -0
- package/deps/winpty/src/shared/winpty_snprintf.h +99 -0
- package/deps/winpty/src/subdir.mk +5 -0
- package/deps/winpty/src/tests/subdir.mk +28 -0
- package/deps/winpty/src/tests/trivial_test.cc +158 -0
- package/deps/winpty/src/unix-adapter/InputHandler.cc +114 -0
- package/deps/winpty/src/unix-adapter/InputHandler.h +56 -0
- package/deps/winpty/src/unix-adapter/OutputHandler.cc +80 -0
- package/deps/winpty/src/unix-adapter/OutputHandler.h +53 -0
- package/deps/winpty/src/unix-adapter/Util.cc +86 -0
- package/deps/winpty/src/unix-adapter/Util.h +31 -0
- package/deps/winpty/src/unix-adapter/WakeupFd.cc +70 -0
- package/deps/winpty/src/unix-adapter/WakeupFd.h +42 -0
- package/deps/winpty/src/unix-adapter/main.cc +729 -0
- package/deps/winpty/src/unix-adapter/subdir.mk +41 -0
- package/deps/winpty/src/winpty.gyp +234 -0
- package/deps/winpty/vcbuild.bat +83 -0
- package/lib/conpty_console_list_agent.js +16 -0
- package/lib/conpty_console_list_agent.js.map +1 -0
- package/lib/eventEmitter2.js +47 -0
- package/lib/eventEmitter2.js.map +1 -0
- package/lib/eventEmitter2.test.js +30 -0
- package/lib/eventEmitter2.test.js.map +1 -0
- package/lib/index.js +52 -0
- package/lib/index.js.map +1 -0
- package/lib/interfaces.js +7 -0
- package/lib/interfaces.js.map +1 -0
- package/lib/shared/conout.js +11 -0
- package/lib/shared/conout.js.map +1 -0
- package/lib/terminal.js +190 -0
- package/lib/terminal.js.map +1 -0
- package/lib/terminal.test.js +139 -0
- package/lib/terminal.test.js.map +1 -0
- package/lib/testUtils.test.js +28 -0
- package/lib/testUtils.test.js.map +1 -0
- package/lib/types.js +7 -0
- package/lib/types.js.map +1 -0
- package/lib/unixTerminal.js +346 -0
- package/lib/unixTerminal.js.map +1 -0
- package/lib/unixTerminal.test.js +351 -0
- package/lib/unixTerminal.test.js.map +1 -0
- package/lib/utils.js +39 -0
- package/lib/utils.js.map +1 -0
- package/lib/windowsConoutConnection.js +125 -0
- package/lib/windowsConoutConnection.js.map +1 -0
- package/lib/windowsPtyAgent.js +320 -0
- package/lib/windowsPtyAgent.js.map +1 -0
- package/lib/windowsPtyAgent.test.js +90 -0
- package/lib/windowsPtyAgent.test.js.map +1 -0
- package/lib/windowsTerminal.js +199 -0
- package/lib/windowsTerminal.js.map +1 -0
- package/lib/windowsTerminal.test.js +219 -0
- package/lib/windowsTerminal.test.js.map +1 -0
- package/lib/worker/conoutSocketWorker.js +22 -0
- package/lib/worker/conoutSocketWorker.js.map +1 -0
- package/package.json +68 -0
- package/prebuilds/darwin-arm64/pty.node +0 -0
- package/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/prebuilds/darwin-x64/pty.node +0 -0
- package/prebuilds/darwin-x64/spawn-helper +0 -0
- package/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
- package/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
- package/prebuilds/win32-arm64/conpty.node +0 -0
- package/prebuilds/win32-arm64/conpty.pdb +0 -0
- package/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/prebuilds/win32-arm64/conpty_console_list.pdb +0 -0
- package/prebuilds/win32-arm64/pty.node +0 -0
- package/prebuilds/win32-arm64/pty.pdb +0 -0
- package/prebuilds/win32-arm64/winpty-agent.exe +0 -0
- package/prebuilds/win32-arm64/winpty-agent.pdb +0 -0
- package/prebuilds/win32-arm64/winpty.dll +0 -0
- package/prebuilds/win32-arm64/winpty.pdb +0 -0
- package/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
- package/prebuilds/win32-x64/conpty/conpty.dll +0 -0
- package/prebuilds/win32-x64/conpty.node +0 -0
- package/prebuilds/win32-x64/conpty.pdb +0 -0
- package/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/prebuilds/win32-x64/conpty_console_list.pdb +0 -0
- package/prebuilds/win32-x64/pty.node +0 -0
- package/prebuilds/win32-x64/pty.pdb +0 -0
- package/prebuilds/win32-x64/winpty-agent.exe +0 -0
- package/prebuilds/win32-x64/winpty-agent.pdb +0 -0
- package/prebuilds/win32-x64/winpty.dll +0 -0
- package/prebuilds/win32-x64/winpty.pdb +0 -0
- package/scripts/gen-compile-commands.js +8 -0
- package/scripts/increment-version.js +54 -0
- package/scripts/post-install.js +99 -0
- package/scripts/prebuild.js +39 -0
- package/scripts/sync-prebuild.js +31 -0
- package/scripts/verify-darwin-fd-leak.js +63 -0
- package/src/conpty_console_list_agent.ts +15 -0
- package/src/eventEmitter2.test.ts +30 -0
- package/src/eventEmitter2.ts +48 -0
- package/src/index.ts +52 -0
- package/src/interfaces.ts +130 -0
- package/src/native.d.ts +54 -0
- package/src/shared/conout.ts +15 -0
- package/src/terminal.test.ts +119 -0
- package/src/terminal.ts +211 -0
- package/src/testUtils.test.ts +23 -0
- package/src/tsconfig.json +22 -0
- package/src/types.ts +15 -0
- package/src/unix/pty.cc +808 -0
- package/src/unix/spawn-helper.cc +23 -0
- package/src/unixTerminal.test.ts +367 -0
- package/src/unixTerminal.ts +388 -0
- package/src/utils.ts +29 -0
- package/src/win/conpty.cc +583 -0
- package/src/win/conpty.h +41 -0
- package/src/win/conpty_console_list.cc +44 -0
- package/src/win/path_util.cc +95 -0
- package/src/win/path_util.h +26 -0
- package/src/win/winpty.cc +333 -0
- package/src/windowsConoutConnection.ts +82 -0
- package/src/windowsPtyAgent.test.ts +94 -0
- package/src/windowsPtyAgent.ts +321 -0
- package/src/windowsTerminal.test.ts +229 -0
- package/src/windowsTerminal.ts +203 -0
- package/src/worker/conoutSocketWorker.ts +22 -0
- package/third_party/conpty/1.23.251008001/win10-arm64/OpenConsole.exe +0 -0
- package/third_party/conpty/1.23.251008001/win10-arm64/conpty.dll +0 -0
- package/third_party/conpty/1.23.251008001/win10-x64/OpenConsole.exe +0 -0
- package/third_party/conpty/1.23.251008001/win10-x64/conpty.dll +0 -0
- package/typings/node-pty.d.ts +211 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2012-2015, Christopher Jeffrey, Peter Sunde (MIT License)
|
|
3
|
+
* Copyright (c) 2016, Daniel Imms (MIT License).
|
|
4
|
+
* Copyright (c) 2018, Microsoft Corporation (MIT License).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as os from 'os';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import { fork } from 'child_process';
|
|
11
|
+
import { Socket } from 'net';
|
|
12
|
+
import { ArgvOrCommandLine } from './types';
|
|
13
|
+
import { ConoutConnection } from './windowsConoutConnection';
|
|
14
|
+
import { loadNativeModule } from './utils';
|
|
15
|
+
|
|
16
|
+
let conptyNative: IConptyNative;
|
|
17
|
+
let winptyNative: IWinptyNative;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The amount of time to wait for additional data after the conpty shell process has exited before
|
|
21
|
+
* shutting down the socket. The timer will be reset if a new data event comes in after the timer
|
|
22
|
+
* has started.
|
|
23
|
+
*/
|
|
24
|
+
const FLUSH_DATA_INTERVAL = 1000;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* This agent sits between the WindowsTerminal class and provides a common interface for both conpty
|
|
28
|
+
* and winpty.
|
|
29
|
+
*/
|
|
30
|
+
export class WindowsPtyAgent {
|
|
31
|
+
private _inSocket: Socket;
|
|
32
|
+
private _outSocket: Socket;
|
|
33
|
+
private _pid: number = 0;
|
|
34
|
+
private _innerPid: number = 0;
|
|
35
|
+
private _closeTimeout: NodeJS.Timer | undefined;
|
|
36
|
+
private _exitCode: number | undefined;
|
|
37
|
+
private _conoutSocketWorker: ConoutConnection;
|
|
38
|
+
|
|
39
|
+
private _fd: any;
|
|
40
|
+
private _pty: number;
|
|
41
|
+
private _ptyNative: IConptyNative | IWinptyNative;
|
|
42
|
+
|
|
43
|
+
public get inSocket(): Socket { return this._inSocket; }
|
|
44
|
+
public get outSocket(): Socket { return this._outSocket; }
|
|
45
|
+
public get fd(): any { return this._fd; }
|
|
46
|
+
public get innerPid(): number { return this._innerPid; }
|
|
47
|
+
public get pty(): number { return this._pty; }
|
|
48
|
+
|
|
49
|
+
constructor(
|
|
50
|
+
file: string,
|
|
51
|
+
args: ArgvOrCommandLine,
|
|
52
|
+
env: string[],
|
|
53
|
+
cwd: string,
|
|
54
|
+
cols: number,
|
|
55
|
+
rows: number,
|
|
56
|
+
debug: boolean,
|
|
57
|
+
private _useConpty: boolean | undefined,
|
|
58
|
+
private _useConptyDll: boolean = false,
|
|
59
|
+
conptyInheritCursor: boolean = false
|
|
60
|
+
) {
|
|
61
|
+
if (this._useConpty === undefined || this._useConpty === true) {
|
|
62
|
+
this._useConpty = this._getWindowsBuildNumber() >= 18309;
|
|
63
|
+
}
|
|
64
|
+
if (this._useConpty) {
|
|
65
|
+
if (!conptyNative) {
|
|
66
|
+
conptyNative = loadNativeModule('conpty').module;
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
if (!winptyNative) {
|
|
70
|
+
winptyNative = loadNativeModule('pty').module;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
this._ptyNative = this._useConpty ? conptyNative : winptyNative;
|
|
74
|
+
|
|
75
|
+
// Sanitize input variable.
|
|
76
|
+
cwd = path.resolve(cwd);
|
|
77
|
+
|
|
78
|
+
// Compose command line
|
|
79
|
+
const commandLine = argsToCommandLine(file, args);
|
|
80
|
+
|
|
81
|
+
// Open pty session.
|
|
82
|
+
let term: IConptyProcess | IWinptyProcess;
|
|
83
|
+
if (this._useConpty) {
|
|
84
|
+
term = (this._ptyNative as IConptyNative).startProcess(file, cols, rows, debug, this._generatePipeName(), conptyInheritCursor, this._useConptyDll);
|
|
85
|
+
} else {
|
|
86
|
+
term = (this._ptyNative as IWinptyNative).startProcess(file, commandLine, env, cwd, cols, rows, debug);
|
|
87
|
+
this._pid = (term as IWinptyProcess).pid;
|
|
88
|
+
this._innerPid = (term as IWinptyProcess).innerPid;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Not available on windows.
|
|
92
|
+
this._fd = term.fd;
|
|
93
|
+
|
|
94
|
+
// Generated incremental number that has no real purpose besides using it
|
|
95
|
+
// as a terminal id.
|
|
96
|
+
this._pty = term.pty;
|
|
97
|
+
|
|
98
|
+
// Create terminal pipe IPC channel and forward to a local unix socket.
|
|
99
|
+
this._outSocket = new Socket();
|
|
100
|
+
this._outSocket.setEncoding('utf8');
|
|
101
|
+
// The conout socket must be ready out on another thread to avoid deadlocks
|
|
102
|
+
this._conoutSocketWorker = new ConoutConnection(term.conout, this._useConptyDll);
|
|
103
|
+
this._conoutSocketWorker.onReady(() => {
|
|
104
|
+
this._conoutSocketWorker.connectSocket(this._outSocket);
|
|
105
|
+
});
|
|
106
|
+
this._outSocket.on('connect', () => {
|
|
107
|
+
this._outSocket.emit('ready_datapipe');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const inSocketFD = fs.openSync(term.conin, 'w');
|
|
111
|
+
this._inSocket = new Socket({
|
|
112
|
+
fd: inSocketFD,
|
|
113
|
+
readable: false,
|
|
114
|
+
writable: true
|
|
115
|
+
});
|
|
116
|
+
this._inSocket.setEncoding('utf8');
|
|
117
|
+
|
|
118
|
+
if (this._useConpty) {
|
|
119
|
+
const connect = (this._ptyNative as IConptyNative).connect(this._pty, commandLine, cwd, env, this._useConptyDll, c => this._$onProcessExit(c));
|
|
120
|
+
this._innerPid = connect.pid;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public resize(cols: number, rows: number): void {
|
|
125
|
+
if (this._useConpty) {
|
|
126
|
+
if (this._exitCode !== undefined) {
|
|
127
|
+
throw new Error('Cannot resize a pty that has already exited');
|
|
128
|
+
}
|
|
129
|
+
(this._ptyNative as IConptyNative).resize(this._pty, cols, rows, this._useConptyDll);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
(this._ptyNative as IWinptyNative).resize(this._pid, cols, rows);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public clear(): void {
|
|
136
|
+
if (this._useConpty) {
|
|
137
|
+
(this._ptyNative as IConptyNative).clear(this._pty, this._useConptyDll);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public kill(): void {
|
|
142
|
+
// Tell the agent to kill the pty, this releases handles to the process
|
|
143
|
+
if (this._useConpty) {
|
|
144
|
+
if (!this._useConptyDll) {
|
|
145
|
+
this._inSocket.readable = false;
|
|
146
|
+
this._outSocket.readable = false;
|
|
147
|
+
this._getConsoleProcessList().then(consoleProcessList => {
|
|
148
|
+
consoleProcessList.forEach((pid: number) => {
|
|
149
|
+
try {
|
|
150
|
+
process.kill(pid);
|
|
151
|
+
} catch (e) {
|
|
152
|
+
// Ignore if process cannot be found (kill ESRCH error)
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
(this._ptyNative as IConptyNative).kill(this._pty, this._useConptyDll);
|
|
157
|
+
this._conoutSocketWorker.dispose();
|
|
158
|
+
} else {
|
|
159
|
+
// Close the input write handle to signal the end of session.
|
|
160
|
+
this._inSocket.destroy();
|
|
161
|
+
(this._ptyNative as IConptyNative).kill(this._pty, this._useConptyDll);
|
|
162
|
+
this._outSocket.on('data', () => {
|
|
163
|
+
this._conoutSocketWorker.dispose();
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
// Because pty.kill closes the handle, it will kill most processes by itself.
|
|
168
|
+
// Process IDs can be reused as soon as all handles to them are
|
|
169
|
+
// dropped, so we want to immediately kill the entire console process list.
|
|
170
|
+
// If we do not force kill all processes here, node servers in particular
|
|
171
|
+
// seem to become detached and remain running (see
|
|
172
|
+
// Microsoft/vscode#26807).
|
|
173
|
+
const processList: number[] = (this._ptyNative as IWinptyNative).getProcessList(this._pid);
|
|
174
|
+
(this._ptyNative as IWinptyNative).kill(this._pid, this._innerPid);
|
|
175
|
+
processList.forEach(pid => {
|
|
176
|
+
try {
|
|
177
|
+
process.kill(pid);
|
|
178
|
+
} catch (e) {
|
|
179
|
+
// Ignore if process cannot be found (kill ESRCH error)
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private _getConsoleProcessList(): Promise<number[]> {
|
|
186
|
+
return new Promise<number[]>(resolve => {
|
|
187
|
+
const agent = fork(path.join(__dirname, 'conpty_console_list_agent'), [ this._innerPid.toString() ]);
|
|
188
|
+
agent.on('message', message => {
|
|
189
|
+
clearTimeout(timeout);
|
|
190
|
+
resolve(message.consoleProcessList);
|
|
191
|
+
});
|
|
192
|
+
const timeout = setTimeout(() => {
|
|
193
|
+
// Something went wrong, just send back the shell PID
|
|
194
|
+
agent.kill();
|
|
195
|
+
resolve([ this._innerPid ]);
|
|
196
|
+
}, 5000);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public get exitCode(): number | undefined {
|
|
201
|
+
if (this._useConpty) {
|
|
202
|
+
return this._exitCode;
|
|
203
|
+
}
|
|
204
|
+
const winptyExitCode = (this._ptyNative as IWinptyNative).getExitCode(this._innerPid);
|
|
205
|
+
return winptyExitCode === -1 ? undefined : winptyExitCode;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private _getWindowsBuildNumber(): number {
|
|
209
|
+
const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release());
|
|
210
|
+
let buildNumber: number = 0;
|
|
211
|
+
if (osVersion && osVersion.length === 4) {
|
|
212
|
+
buildNumber = parseInt(osVersion[3]);
|
|
213
|
+
}
|
|
214
|
+
return buildNumber;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private _generatePipeName(): string {
|
|
218
|
+
return `conpty-${Math.random() * 10000000}`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Triggered from the native side when a contpy process exits.
|
|
223
|
+
*/
|
|
224
|
+
private _$onProcessExit(exitCode: number): void {
|
|
225
|
+
this._exitCode = exitCode;
|
|
226
|
+
if (!this._useConptyDll) {
|
|
227
|
+
this._flushDataAndCleanUp();
|
|
228
|
+
this._outSocket.on('data', () => this._flushDataAndCleanUp());
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private _flushDataAndCleanUp(): void {
|
|
233
|
+
if (this._useConptyDll) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (this._closeTimeout) {
|
|
237
|
+
clearTimeout(this._closeTimeout);
|
|
238
|
+
}
|
|
239
|
+
this._closeTimeout = setTimeout(() => this._cleanUpProcess(), FLUSH_DATA_INTERVAL);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private _cleanUpProcess(): void {
|
|
243
|
+
if (this._useConptyDll) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
this._inSocket.readable = false;
|
|
247
|
+
this._outSocket.readable = false;
|
|
248
|
+
this._outSocket.destroy();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Convert argc/argv into a Win32 command-line following the escaping convention
|
|
253
|
+
// documented on MSDN (e.g. see CommandLineToArgvW documentation). Copied from
|
|
254
|
+
// winpty project.
|
|
255
|
+
export function argsToCommandLine(file: string, args: ArgvOrCommandLine): string {
|
|
256
|
+
if (isCommandLine(args)) {
|
|
257
|
+
if (args.length === 0) {
|
|
258
|
+
return file;
|
|
259
|
+
}
|
|
260
|
+
return `${argsToCommandLine(file, [])} ${args}`;
|
|
261
|
+
}
|
|
262
|
+
const argv = [file];
|
|
263
|
+
Array.prototype.push.apply(argv, args);
|
|
264
|
+
let result = '';
|
|
265
|
+
for (let argIndex = 0; argIndex < argv.length; argIndex++) {
|
|
266
|
+
if (argIndex > 0) {
|
|
267
|
+
result += ' ';
|
|
268
|
+
}
|
|
269
|
+
const arg = argv[argIndex];
|
|
270
|
+
// if it is empty or it contains whitespace and is not already quoted
|
|
271
|
+
const hasLopsidedEnclosingQuote = xOr((arg[0] !== '"'), (arg[arg.length - 1] !== '"'));
|
|
272
|
+
const hasNoEnclosingQuotes = ((arg[0] !== '"') && (arg[arg.length - 1] !== '"'));
|
|
273
|
+
const quote =
|
|
274
|
+
arg === '' ||
|
|
275
|
+
(arg.indexOf(' ') !== -1 ||
|
|
276
|
+
arg.indexOf('\t') !== -1) &&
|
|
277
|
+
((arg.length > 1) &&
|
|
278
|
+
(hasLopsidedEnclosingQuote || hasNoEnclosingQuotes));
|
|
279
|
+
if (quote) {
|
|
280
|
+
result += '\"';
|
|
281
|
+
}
|
|
282
|
+
let bsCount = 0;
|
|
283
|
+
for (let i = 0; i < arg.length; i++) {
|
|
284
|
+
const p = arg[i];
|
|
285
|
+
if (p === '\\') {
|
|
286
|
+
bsCount++;
|
|
287
|
+
} else if (p === '"') {
|
|
288
|
+
result += repeatText('\\', bsCount * 2 + 1);
|
|
289
|
+
result += '"';
|
|
290
|
+
bsCount = 0;
|
|
291
|
+
} else {
|
|
292
|
+
result += repeatText('\\', bsCount);
|
|
293
|
+
bsCount = 0;
|
|
294
|
+
result += p;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (quote) {
|
|
298
|
+
result += repeatText('\\', bsCount * 2);
|
|
299
|
+
result += '\"';
|
|
300
|
+
} else {
|
|
301
|
+
result += repeatText('\\', bsCount);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function isCommandLine(args: ArgvOrCommandLine): args is string {
|
|
308
|
+
return typeof args === 'string';
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function repeatText(text: string, count: number): string {
|
|
312
|
+
let result = '';
|
|
313
|
+
for (let i = 0; i < count; i++) {
|
|
314
|
+
result += text;
|
|
315
|
+
}
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function xOr(arg1: boolean, arg2: boolean): boolean {
|
|
320
|
+
return ((arg1 && !arg2) || (!arg1 && arg2));
|
|
321
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2017, Daniel Imms (MIT License).
|
|
3
|
+
* Copyright (c) 2018, Microsoft Corporation (MIT License).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as assert from 'assert';
|
|
8
|
+
import { WindowsTerminal } from './windowsTerminal';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import * as psList from 'ps-list';
|
|
11
|
+
|
|
12
|
+
interface IProcessState {
|
|
13
|
+
// Whether the PID must exist or must not exist
|
|
14
|
+
[pid: number]: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface IWindowsProcessTreeResult {
|
|
18
|
+
name: string;
|
|
19
|
+
pid: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function pollForProcessState(desiredState: IProcessState, intervalMs: number = 100, timeoutMs: number = 2000): Promise<void> {
|
|
23
|
+
return new Promise<void>(resolve => {
|
|
24
|
+
let tries = 0;
|
|
25
|
+
const interval = setInterval(() => {
|
|
26
|
+
psList({ all: true }).then(ps => {
|
|
27
|
+
let success = true;
|
|
28
|
+
const pids = Object.keys(desiredState).map(k => parseInt(k, 10));
|
|
29
|
+
console.log('expected pids', JSON.stringify(pids));
|
|
30
|
+
pids.forEach(pid => {
|
|
31
|
+
if (desiredState[pid]) {
|
|
32
|
+
if (!ps.some(p => p.pid === pid)) {
|
|
33
|
+
console.log(`pid ${pid} does not exist`);
|
|
34
|
+
success = false;
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
if (ps.some(p => p.pid === pid)) {
|
|
38
|
+
console.log(`pid ${pid} still exists`);
|
|
39
|
+
success = false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
if (success) {
|
|
44
|
+
clearInterval(interval);
|
|
45
|
+
resolve();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
tries++;
|
|
49
|
+
if (tries * intervalMs >= timeoutMs) {
|
|
50
|
+
clearInterval(interval);
|
|
51
|
+
const processListing = pids.map(k => `${k}: ${desiredState[k]}`).join('\n');
|
|
52
|
+
assert.fail(`Bad process state, expected:\n${processListing}`);
|
|
53
|
+
resolve();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}, intervalMs);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function pollForProcessTreeSize(pid: number, size: number, intervalMs: number = 100, timeoutMs: number = 2000): Promise<IWindowsProcessTreeResult[]> {
|
|
61
|
+
return new Promise<IWindowsProcessTreeResult[]>(resolve => {
|
|
62
|
+
let tries = 0;
|
|
63
|
+
const interval = setInterval(() => {
|
|
64
|
+
psList({ all: true }).then(ps => {
|
|
65
|
+
const openList: IWindowsProcessTreeResult[] = [];
|
|
66
|
+
openList.push(ps.filter(p => p.pid === pid).map(p => {
|
|
67
|
+
return { name: p.name, pid: p.pid };
|
|
68
|
+
})[0]);
|
|
69
|
+
const list: IWindowsProcessTreeResult[] = [];
|
|
70
|
+
while (openList.length) {
|
|
71
|
+
const current = openList.shift()!;
|
|
72
|
+
ps.filter(p => p.ppid === current.pid).map(p => {
|
|
73
|
+
return { name: p.name, pid: p.pid };
|
|
74
|
+
}).forEach(p => openList.push(p));
|
|
75
|
+
list.push(current);
|
|
76
|
+
}
|
|
77
|
+
console.log('list', JSON.stringify(list));
|
|
78
|
+
const success = list.length === size;
|
|
79
|
+
if (success) {
|
|
80
|
+
clearInterval(interval);
|
|
81
|
+
resolve(list);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
tries++;
|
|
85
|
+
if (tries * intervalMs >= timeoutMs) {
|
|
86
|
+
clearInterval(interval);
|
|
87
|
+
assert.fail(`Bad process state, expected: ${size}, actual: ${list.length}`);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}, intervalMs);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (process.platform === 'win32') {
|
|
95
|
+
[[false, false], [true, false], [true, true]].forEach(([useConpty, useConptyDll]) => {
|
|
96
|
+
describe(`WindowsTerminal (useConpty = ${useConpty}, useConptyDll = ${useConptyDll})`, () => {
|
|
97
|
+
describe('kill', () => {
|
|
98
|
+
it('should not crash parent process', function (done) {
|
|
99
|
+
this.timeout(20000);
|
|
100
|
+
const term = new WindowsTerminal('cmd.exe', [], { useConpty, useConptyDll });
|
|
101
|
+
term.on('exit', () => done());
|
|
102
|
+
term.kill();
|
|
103
|
+
});
|
|
104
|
+
it('should kill the process tree', function (done: Mocha.Done): void {
|
|
105
|
+
this.timeout(20000);
|
|
106
|
+
const term = new WindowsTerminal('cmd.exe', [], { useConpty, useConptyDll });
|
|
107
|
+
// Start sub-processes
|
|
108
|
+
term.write('powershell.exe\r');
|
|
109
|
+
term.write('node.exe\r');
|
|
110
|
+
console.log('start poll for tree size');
|
|
111
|
+
pollForProcessTreeSize(term.pid, 3, 500, 5000).then(list => {
|
|
112
|
+
assert.strictEqual(list[0].name.toLowerCase(), 'cmd.exe');
|
|
113
|
+
assert.strictEqual(list[1].name.toLowerCase(), 'powershell.exe');
|
|
114
|
+
assert.strictEqual(list[2].name.toLowerCase(), 'node.exe');
|
|
115
|
+
term.kill();
|
|
116
|
+
const desiredState: IProcessState = {};
|
|
117
|
+
desiredState[list[0].pid] = false;
|
|
118
|
+
desiredState[list[1].pid] = false;
|
|
119
|
+
desiredState[list[2].pid] = false;
|
|
120
|
+
term.on('exit', () => {
|
|
121
|
+
pollForProcessState(desiredState, 1000, 5000).then(() => {
|
|
122
|
+
done();
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('resize', () => {
|
|
130
|
+
it('should throw a non-native exception when resizing an invalid value', function(done) {
|
|
131
|
+
this.timeout(20000);
|
|
132
|
+
const term = new WindowsTerminal('cmd.exe', [], { useConpty, useConptyDll });
|
|
133
|
+
assert.throws(() => term.resize(-1, -1));
|
|
134
|
+
assert.throws(() => term.resize(0, 0));
|
|
135
|
+
assert.doesNotThrow(() => term.resize(1, 1));
|
|
136
|
+
term.on('exit', () => {
|
|
137
|
+
done();
|
|
138
|
+
});
|
|
139
|
+
term.kill();
|
|
140
|
+
});
|
|
141
|
+
it('should throw a non-native exception when resizing a killed terminal', function(done) {
|
|
142
|
+
this.timeout(20000);
|
|
143
|
+
const term = new WindowsTerminal('cmd.exe', [], { useConpty, useConptyDll });
|
|
144
|
+
(<any>term)._defer(() => {
|
|
145
|
+
term.once('exit', () => {
|
|
146
|
+
assert.throws(() => term.resize(1, 1));
|
|
147
|
+
done();
|
|
148
|
+
});
|
|
149
|
+
term.destroy();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe('Args as CommandLine', () => {
|
|
155
|
+
it('should not fail running a file containing a space in the path', function (done) {
|
|
156
|
+
this.timeout(10000);
|
|
157
|
+
const spaceFolder = path.resolve(__dirname, '..', 'fixtures', 'space folder');
|
|
158
|
+
if (!fs.existsSync(spaceFolder)) {
|
|
159
|
+
fs.mkdirSync(spaceFolder);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const cmdCopiedPath = path.resolve(spaceFolder, 'cmd.exe');
|
|
163
|
+
const data = fs.readFileSync(`${process.env.windir}\\System32\\cmd.exe`);
|
|
164
|
+
fs.writeFileSync(cmdCopiedPath, data);
|
|
165
|
+
|
|
166
|
+
if (!fs.existsSync(cmdCopiedPath)) {
|
|
167
|
+
// Skip test if git bash isn't installed
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const term = new WindowsTerminal(cmdCopiedPath, '/c echo "hello world"', { useConpty, useConptyDll });
|
|
171
|
+
let result = '';
|
|
172
|
+
term.on('data', (data) => {
|
|
173
|
+
result += data;
|
|
174
|
+
});
|
|
175
|
+
term.on('exit', () => {
|
|
176
|
+
assert.ok(result.indexOf('hello world') >= 1);
|
|
177
|
+
done();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe('env', () => {
|
|
183
|
+
it('should set environment variables of the shell', function (done) {
|
|
184
|
+
this.timeout(10000);
|
|
185
|
+
const term = new WindowsTerminal('cmd.exe', '/C echo %FOO%', { useConpty, useConptyDll, env: { FOO: 'BAR' }});
|
|
186
|
+
let result = '';
|
|
187
|
+
term.on('data', (data) => {
|
|
188
|
+
result += data;
|
|
189
|
+
});
|
|
190
|
+
term.on('exit', () => {
|
|
191
|
+
assert.ok(result.indexOf('BAR') >= 0);
|
|
192
|
+
done();
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe('On close', () => {
|
|
198
|
+
it('should return process zero exit codes', function (done) {
|
|
199
|
+
this.timeout(10000);
|
|
200
|
+
const term = new WindowsTerminal('cmd.exe', '/C exit', { useConpty, useConptyDll });
|
|
201
|
+
term.on('exit', (code) => {
|
|
202
|
+
assert.strictEqual(code, 0);
|
|
203
|
+
done();
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should return process non-zero exit codes', function (done) {
|
|
208
|
+
this.timeout(10000);
|
|
209
|
+
const term = new WindowsTerminal('cmd.exe', '/C exit 2', { useConpty, useConptyDll });
|
|
210
|
+
term.on('exit', (code) => {
|
|
211
|
+
assert.strictEqual(code, 2);
|
|
212
|
+
done();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
describe('Write', () => {
|
|
218
|
+
it('should accept input', function (done) {
|
|
219
|
+
this.timeout(10000);
|
|
220
|
+
const term = new WindowsTerminal('cmd.exe', '', { useConpty, useConptyDll });
|
|
221
|
+
term.write('exit\r');
|
|
222
|
+
term.on('exit', () => {
|
|
223
|
+
done();
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
}
|