From c1a4f8834e5687fd1327991496535b4e746a85e3 Mon Sep 17 00:00:00 2001 From: Andrzej Szombierski Date: Sat, 9 Mar 2019 17:04:57 +0100 Subject: [PATCH 01/13] Revert "Use a less strict check on encoding to avoid if" This reverts commit 16a36a86fcfe6e3fd86fdc52618b3f30e23db585. That commit introduced a bug where Pty.open would return an UTF8-encoded stream regardless of specified options. --- src/unixTerminal.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/unixTerminal.ts b/src/unixTerminal.ts index ae791ad05..dfed1e245 100644 --- a/src/unixTerminal.ts +++ b/src/unixTerminal.ts @@ -169,17 +169,21 @@ export class UnixTerminal extends Terminal { const cols = opt.cols || DEFAULT_COLS; const rows = opt.rows || DEFAULT_ROWS; - const encoding = opt.encoding ? 'utf8' : opt.encoding; + const encoding = (opt.encoding === undefined ? 'utf8' : opt.encoding); // open const term: IUnixOpenProcess = pty.open(cols, rows); self._master = new PipeSocket(term.master); - self._master.setEncoding(encoding); + if (encoding !== null) { + self._master.setEncoding(encoding); + } self._master.resume(); self._slave = new PipeSocket(term.slave); - self._slave.setEncoding(encoding); + if (encoding !== null) { + self._slave.setEncoding(encoding); + } self._slave.resume(); self._socket = self._master; From cb3b3f6a9fb2d94525181c796623181692682974 Mon Sep 17 00:00:00 2001 From: Eugene Pankov Date: Sun, 28 Apr 2019 20:12:50 +0200 Subject: [PATCH 02/13] node 12 compat wip --- package.json | 2 +- src/win/conpty.cc | 39 +++++++++++++++++----------------- src/win/conpty_console_list.cc | 4 ++-- src/win/path_util.cc | 2 +- src/win/path_util.h | 2 +- src/win/winpty.cc | 34 ++++++++++++++--------------- src/windowsPtyAgent.ts | 5 ++++- 7 files changed, 45 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 20272fc8a..ef220f58d 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "prepublish": "npm run tsc" }, "dependencies": { - "nan": "2.12.1" + "nan": "^2.13.2" }, "devDependencies": { "@types/mocha": "^5.0.0", diff --git a/src/win/conpty.cc b/src/win/conpty.cc index 1b5a74949..d512aa91b 100644 --- a/src/win/conpty.cc +++ b/src/win/conpty.cc @@ -18,7 +18,7 @@ #include #include "path_util.h" -extern "C" void init(v8::Handle); +extern "C" void init(v8::Local); // Taken from the RS5 Windows SDK, but redefined here in case we're targeting <= 17134 #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE @@ -170,11 +170,11 @@ static NAN_METHOD(PtyStartProcess) { return; } - const std::wstring filename(path_util::to_wstring(v8::String::Utf8Value(info[0]->ToString()))); - const SHORT cols = info[1]->Uint32Value(); - const SHORT rows = info[2]->Uint32Value(); - const bool debug = info[3]->ToBoolean()->IsTrue(); - const std::wstring pipeName(path_util::to_wstring(v8::String::Utf8Value(info[4]->ToString()))); + const std::wstring filename(path_util::to_wstring(Nan::Utf8String(info[0]))); + const SHORT cols = info[1]->Uint32Value(Nan::GetCurrentContext()).FromJust(); + const SHORT rows = info[2]->Uint32Value(Nan::GetCurrentContext()).FromJust(); + const bool debug = info[3]->ToBoolean(Nan::GetCurrentContext()).ToLocalChecked()->IsTrue(); + const std::wstring pipeName(path_util::to_wstring(Nan::Utf8String(info[4]))); // use environment 'Path' variable to determine location of // the relative path that we have recieved (e.g cmd.exe) @@ -242,12 +242,11 @@ static void OnProcessExit(uv_async_t *async) { GetExitCodeProcess(baton->hShell, &exitCode); // Call function - v8::Handle args[1] = { + v8::Local args[1] = { Nan::New(exitCode) }; - v8::Handle local = Nan::New(baton->cb); - local->Call(Nan::GetCurrentContext()->Global(), 1, args); - + v8::Local local = Nan::New(baton->cb); + local->Call(Nan::GetCurrentContext(), Nan::Null(), 1, args); // Clean up baton->cb.Reset(); } @@ -272,10 +271,10 @@ static NAN_METHOD(PtyConnect) { return; } - const int id = info[0]->Int32Value(); - const std::wstring cmdline(path_util::to_wstring(v8::String::Utf8Value(info[1]->ToString()))); - const std::wstring cwd(path_util::to_wstring(v8::String::Utf8Value(info[2]->ToString()))); - const v8::Handle envValues = info[3].As(); + const int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust(); + const std::wstring cmdline(path_util::to_wstring(Nan::Utf8String(info[1]))); + const std::wstring cwd(path_util::to_wstring(Nan::Utf8String(info[2]))); + const v8::Local envValues = info[3].As(); const v8::Local exitCallback = v8::Local::Cast(info[4]); // Prepare command line @@ -291,7 +290,7 @@ static NAN_METHOD(PtyConnect) { if (!envValues.IsEmpty()) { std::wstringstream envBlock; for(uint32_t i = 0; i < envValues->Length(); i++) { - std::wstring envValue(path_util::to_wstring(v8::String::Utf8Value(envValues->Get(i)->ToString()))); + std::wstring envValue(path_util::to_wstring(Nan::Utf8String(envValues->Get(i)))); envBlock << envValue << L'\0'; } envBlock << L'\0'; @@ -374,9 +373,9 @@ static NAN_METHOD(PtyResize) { return; } - int id = info[0]->Int32Value(); - SHORT cols = info[1]->Uint32Value(); - SHORT rows = info[2]->Uint32Value(); + int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust(); + SHORT cols = info[1]->Uint32Value(Nan::GetCurrentContext()).FromJust(); + SHORT rows = info[2]->Uint32Value(Nan::GetCurrentContext()).FromJust(); const pty_baton* handle = get_pty_baton(id); @@ -404,7 +403,7 @@ static NAN_METHOD(PtyKill) { return; } - int id = info[0]->Int32Value(); + int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust(); const pty_baton* handle = get_pty_baton(id); @@ -428,7 +427,7 @@ static NAN_METHOD(PtyKill) { * Init */ -extern "C" void init(v8::Handle target) { +extern "C" void init(v8::Local target) { Nan::HandleScope scope; Nan::SetMethod(target, "startProcess", PtyStartProcess); Nan::SetMethod(target, "connect", PtyConnect); diff --git a/src/win/conpty_console_list.cc b/src/win/conpty_console_list.cc index 72102360e..b2d3d996f 100644 --- a/src/win/conpty_console_list.cc +++ b/src/win/conpty_console_list.cc @@ -12,7 +12,7 @@ static NAN_METHOD(ApiConsoleProcessList) { return; } - const SHORT pid = info[0]->Uint32Value(); + const SHORT pid = info[0]->Uint32Value(Nan::GetCurrentContext()).FromJust(); if (!FreeConsole()) { Nan::ThrowError("FreeConsole failed"); @@ -35,7 +35,7 @@ static NAN_METHOD(ApiConsoleProcessList) { info.GetReturnValue().Set(result); } -extern "C" void init(v8::Handle target) { +extern "C" void init(v8::Local target) { Nan::HandleScope scope; Nan::SetMethod(target, "getConsoleProcessList", ApiConsoleProcessList); }; diff --git a/src/win/path_util.cc b/src/win/path_util.cc index 4387d2550..4e69f3091 100644 --- a/src/win/path_util.cc +++ b/src/win/path_util.cc @@ -11,7 +11,7 @@ namespace path_util { -const wchar_t* to_wstring(const v8::String::Utf8Value& str) { +const wchar_t* to_wstring(const Nan::Utf8String& str) { const char *bytes = *str; unsigned int sizeOfStr = MultiByteToWideChar(CP_UTF8, 0, bytes, -1, NULL, 0); wchar_t *output = new wchar_t[sizeOfStr]; diff --git a/src/win/path_util.h b/src/win/path_util.h index 2bfcabf19..8dd58d25e 100644 --- a/src/win/path_util.h +++ b/src/win/path_util.h @@ -13,7 +13,7 @@ namespace path_util { -const wchar_t* to_wstring(const v8::String::Utf8Value& str); +const wchar_t* to_wstring(const Nan::Utf8String& str); bool file_exists(std::wstring filename); std::wstring get_shell_path(std::wstring filename); diff --git a/src/win/winpty.cc b/src/win/winpty.cc index 1b5e6b350..089b3fee0 100644 --- a/src/win/winpty.cc +++ b/src/win/winpty.cc @@ -23,7 +23,7 @@ /** * Misc */ -extern "C" void init(v8::Handle); +extern "C" void init(v8::Local); #define WINPTY_DBG_VARIABLE TEXT("WINPTYDBG") @@ -80,7 +80,7 @@ static NAN_METHOD(PtyGetExitCode) { } DWORD exitCode = 0; - GetExitCodeProcess((HANDLE)info[0]->IntegerValue(), &exitCode); + GetExitCodeProcess((HANDLE)info[0]->IntegerValue(Nan::GetCurrentContext()).FromJust(), &exitCode); info.GetReturnValue().Set(Nan::New(exitCode)); } @@ -94,7 +94,7 @@ static NAN_METHOD(PtyGetProcessList) { return; } - int pid = info[0]->Int32Value(); + int pid = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust(); winpty_t *pc = get_pipe_handle(pid); if (pc == nullptr) { @@ -129,19 +129,19 @@ static NAN_METHOD(PtyStartProcess) { std::stringstream why; - const wchar_t *filename = path_util::to_wstring(v8::String::Utf8Value(info[0]->ToString())); - const wchar_t *cmdline = path_util::to_wstring(v8::String::Utf8Value(info[1]->ToString())); - const wchar_t *cwd = path_util::to_wstring(v8::String::Utf8Value(info[3]->ToString())); + const wchar_t *filename = path_util::to_wstring(Nan::Utf8String(info[0])); + const wchar_t *cmdline = path_util::to_wstring(Nan::Utf8String(info[1])); + const wchar_t *cwd = path_util::to_wstring(Nan::Utf8String(info[3])); // create environment block std::wstring env; - const v8::Handle envValues = v8::Handle::Cast(info[2]); + const v8::Local envValues = v8::Local::Cast(info[2]); if (!envValues.IsEmpty()) { std::wstringstream envBlock; for(uint32_t i = 0; i < envValues->Length(); i++) { - std::wstring envValue(path_util::to_wstring(v8::String::Utf8Value(envValues->Get(i)->ToString()))); + std::wstring envValue(path_util::to_wstring(Nan::Utf8String(envValues->Get(i)))); envBlock << envValue << L'\0'; } @@ -165,9 +165,9 @@ static NAN_METHOD(PtyStartProcess) { goto cleanup; } - int cols = info[4]->Int32Value(); - int rows = info[5]->Int32Value(); - bool debug = info[6]->ToBoolean()->IsTrue(); + int cols = info[4]->Int32Value(Nan::GetCurrentContext()).FromJust(); + int rows = info[5]->Int32Value(Nan::GetCurrentContext()).FromJust(); + bool debug = info[6]->ToBoolean(Nan::GetCurrentContext()).ToLocalChecked()->IsTrue(); // Enable/disable debugging SetEnvironmentVariable(WINPTY_DBG_VARIABLE, debug ? "1" : NULL); // NULL = deletes variable @@ -252,9 +252,9 @@ static NAN_METHOD(PtyResize) { return; } - int handle = info[0]->Int32Value(); - int cols = info[1]->Int32Value(); - int rows = info[2]->Int32Value(); + int handle = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust(); + int cols = info[1]->Int32Value(Nan::GetCurrentContext()).FromJust(); + int rows = info[2]->Int32Value(Nan::GetCurrentContext()).FromJust(); winpty_t *pc = get_pipe_handle(handle); @@ -281,8 +281,8 @@ static NAN_METHOD(PtyKill) { return; } - int handle = info[0]->Int32Value(); - HANDLE innerPidHandle = (HANDLE)info[1]->Int32Value(); + int handle = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust(); + HANDLE innerPidHandle = (HANDLE)info[1]->Int32Value(Nan::GetCurrentContext()).FromJust(); winpty_t *pc = get_pipe_handle(handle); if (pc == nullptr) { @@ -300,7 +300,7 @@ static NAN_METHOD(PtyKill) { * Init */ -extern "C" void init(v8::Handle target) { +extern "C" void init(v8::Local target) { Nan::HandleScope scope; Nan::SetMethod(target, "startProcess", PtyStartProcess); Nan::SetMethod(target, "resize", PtyResize); diff --git a/src/windowsPtyAgent.ts b/src/windowsPtyAgent.ts index 8584aaf56..19dd8222a 100644 --- a/src/windowsPtyAgent.ts +++ b/src/windowsPtyAgent.ts @@ -115,7 +115,10 @@ export class WindowsPtyAgent { // TODO: Wait for ready event? if (this._useConpty) { - const connect = (this._ptyNative as IConptyNative).connect(this._pty, commandLine, cwd, env, this._$onProcessExit.bind(this)); + const connect = (this._ptyNative as IConptyNative).connect(this._pty, commandLine, cwd, env, c => { + console.warn('callback', c) + this._$onProcessExit(c) + }); this._innerPid = connect.pid; } } From c38e930ab69420fe716006bc110c87cd507b23db Mon Sep 17 00:00:00 2001 From: Eugene Pankov Date: Sat, 4 May 2019 13:33:31 +0200 Subject: [PATCH 03/13] callback and deprecation fixes --- src/win/conpty.cc | 27 ++++++++++++++------------- src/win/conpty_console_list.cc | 2 +- src/win/winpty.cc | 16 ++++++++-------- src/windowsPtyAgent.ts | 6 ++---- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/win/conpty.cc b/src/win/conpty.cc index d512aa91b..c3213ba32 100644 --- a/src/win/conpty.cc +++ b/src/win/conpty.cc @@ -40,7 +40,7 @@ struct pty_baton { HANDLE hShell; HANDLE hWait; - Nan::Persistent cb; + Nan::Callback cb; uv_async_t async; uv_thread_t tid; @@ -204,20 +204,20 @@ static NAN_METHOD(PtyStartProcess) { if (SUCCEEDED(hr)) { // We were able to instantiate a conpty const int ptyId = InterlockedIncrement(&ptyCounter); - marshal->Set(Nan::New("pty").ToLocalChecked(), Nan::New(ptyId)); + Nan::Set(marshal, Nan::New("pty").ToLocalChecked(), Nan::New(ptyId)); ptyHandles.insert(ptyHandles.end(), new pty_baton(ptyId, hIn, hOut, hpc)); } else { Nan::ThrowError("Cannot launch conpty"); return; } - marshal->Set(Nan::New("fd").ToLocalChecked(), Nan::New(-1)); + Nan::Set(marshal, Nan::New("fd").ToLocalChecked(), Nan::New(-1)); { std::string coninPipeNameStr(inName.begin(), inName.end()); - marshal->Set(Nan::New("conin").ToLocalChecked(), Nan::New(coninPipeNameStr).ToLocalChecked()); + Nan::Set(marshal, Nan::New("conin").ToLocalChecked(), Nan::New(coninPipeNameStr).ToLocalChecked()); std::string conoutPipeNameStr(outName.begin(), outName.end()); - marshal->Set(Nan::New("conout").ToLocalChecked(), Nan::New(conoutPipeNameStr).ToLocalChecked()); + Nan::Set(marshal, Nan::New("conout").ToLocalChecked(), Nan::New(conoutPipeNameStr).ToLocalChecked()); } info.GetReturnValue().Set(marshal); } @@ -245,8 +245,9 @@ static void OnProcessExit(uv_async_t *async) { v8::Local args[1] = { Nan::New(exitCode) }; - v8::Local local = Nan::New(baton->cb); - local->Call(Nan::GetCurrentContext(), Nan::Null(), 1, args); + + Nan::AsyncResource asyncResource("node-pty.callback"); + baton->cb.Call(1, args, &asyncResource); // Clean up baton->cb.Reset(); } @@ -290,7 +291,7 @@ static NAN_METHOD(PtyConnect) { if (!envValues.IsEmpty()) { std::wstringstream envBlock; for(uint32_t i = 0; i < envValues->Length(); i++) { - std::wstring envValue(path_util::to_wstring(Nan::Utf8String(envValues->Get(i)))); + std::wstring envValue(path_util::to_wstring(Nan::Utf8String(Nan::Get(envValues, i).ToLocalChecked()))); envBlock << envValue << L'\0'; } envBlock << L'\0'; @@ -308,12 +309,12 @@ static NAN_METHOD(PtyConnect) { // Attach the pseudoconsole to the client application we're creating STARTUPINFOEXW siEx{0}; siEx.StartupInfo.cb = sizeof(STARTUPINFOEXW); - PSIZE_T size; - InitializeProcThreadAttributeList(NULL, 1, 0, size); - BYTE *attrList = new BYTE[*size]; + SIZE_T size = 0; + InitializeProcThreadAttributeList(NULL, 1, 0, &size); + BYTE *attrList = new BYTE[size]; siEx.lpAttributeList = reinterpret_cast(attrList); - fSuccess = InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, size); + fSuccess = InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size); if (!fSuccess) { return throwNanError(&info, "InitializeProcThreadAttributeList failed", true); } @@ -358,7 +359,7 @@ static NAN_METHOD(PtyConnect) { // Return v8::Local marshal = Nan::New(); - marshal->Set(Nan::New("pid").ToLocalChecked(), Nan::New(piClient.dwProcessId)); + Nan::Set(marshal, Nan::New("pid").ToLocalChecked(), Nan::New(piClient.dwProcessId)); info.GetReturnValue().Set(marshal); } diff --git a/src/win/conpty_console_list.cc b/src/win/conpty_console_list.cc index b2d3d996f..be135ba02 100644 --- a/src/win/conpty_console_list.cc +++ b/src/win/conpty_console_list.cc @@ -30,7 +30,7 @@ static NAN_METHOD(ApiConsoleProcessList) { v8::Local result = Nan::New(); for (DWORD i = 0; i < processCount; i++) { - result->Set(i, Nan::New(processList[i])); + Nan::Set(result, i, Nan::New(processList[i])); } info.GetReturnValue().Set(result); } diff --git a/src/win/winpty.cc b/src/win/winpty.cc index 089b3fee0..614938a35 100644 --- a/src/win/winpty.cc +++ b/src/win/winpty.cc @@ -141,7 +141,7 @@ static NAN_METHOD(PtyStartProcess) { std::wstringstream envBlock; for(uint32_t i = 0; i < envValues->Length(); i++) { - std::wstring envValue(path_util::to_wstring(Nan::Utf8String(envValues->Get(i)))); + std::wstring envValue(path_util::to_wstring(Nan::Utf8String(Nan::Get(envValues, i).ToLocalChecked()))); envBlock << envValue << L'\0'; } @@ -216,20 +216,20 @@ static NAN_METHOD(PtyStartProcess) { // Set return values v8::Local marshal = Nan::New(); - marshal->Set(Nan::New("innerPid").ToLocalChecked(), Nan::New((int)GetProcessId(handle))); - marshal->Set(Nan::New("innerPidHandle").ToLocalChecked(), Nan::New((int)handle)); - marshal->Set(Nan::New("pid").ToLocalChecked(), Nan::New((int)winpty_agent_process(pc))); - marshal->Set(Nan::New("pty").ToLocalChecked(), Nan::New(InterlockedIncrement(&ptyCounter))); - marshal->Set(Nan::New("fd").ToLocalChecked(), Nan::New(-1)); + Nan::Set(marshal, Nan::New("innerPid").ToLocalChecked(), Nan::New((int)GetProcessId(handle))); + Nan::Set(marshal, Nan::New("innerPidHandle").ToLocalChecked(), Nan::New((int)handle)); + Nan::Set(marshal, Nan::New("pid").ToLocalChecked(), Nan::New((int)winpty_agent_process(pc))); + Nan::Set(marshal, Nan::New("pty").ToLocalChecked(), Nan::New(InterlockedIncrement(&ptyCounter))); + Nan::Set(marshal, Nan::New("fd").ToLocalChecked(), Nan::New(-1)); { LPCWSTR coninPipeName = winpty_conin_name(pc); std::wstring coninPipeNameWStr(coninPipeName); std::string coninPipeNameStr(coninPipeNameWStr.begin(), coninPipeNameWStr.end()); - marshal->Set(Nan::New("conin").ToLocalChecked(), Nan::New(coninPipeNameStr).ToLocalChecked()); + Nan::Set(marshal, Nan::New("conin").ToLocalChecked(), Nan::New(coninPipeNameStr).ToLocalChecked()); LPCWSTR conoutPipeName = winpty_conout_name(pc); std::wstring conoutPipeNameWStr(conoutPipeName); std::string conoutPipeNameStr(conoutPipeNameWStr.begin(), conoutPipeNameWStr.end()); - marshal->Set(Nan::New("conout").ToLocalChecked(), Nan::New(conoutPipeNameStr).ToLocalChecked()); + Nan::Set(marshal, Nan::New("conout").ToLocalChecked(), Nan::New(conoutPipeNameStr).ToLocalChecked()); } info.GetReturnValue().Set(marshal); diff --git a/src/windowsPtyAgent.ts b/src/windowsPtyAgent.ts index 19dd8222a..217142903 100644 --- a/src/windowsPtyAgent.ts +++ b/src/windowsPtyAgent.ts @@ -115,10 +115,8 @@ export class WindowsPtyAgent { // TODO: Wait for ready event? if (this._useConpty) { - const connect = (this._ptyNative as IConptyNative).connect(this._pty, commandLine, cwd, env, c => { - console.warn('callback', c) - this._$onProcessExit(c) - }); + const connect = (this._ptyNative as IConptyNative).connect(this._pty, commandLine, cwd, env, c => this._$onProcessExit(c) +); this._innerPid = connect.pid; } } From 563857ea4a7c582bb4b9053172c527b880a39bd5 Mon Sep 17 00:00:00 2001 From: Eugene Pankov Date: Tue, 7 May 2019 11:52:03 +0200 Subject: [PATCH 04/13] unix/pty.cc node 12 compatibility --- src/unix/pty.cc | 48 ++++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/src/unix/pty.cc b/src/unix/pty.cc index 57121b678..df3972526 100644 --- a/src/unix/pty.cc +++ b/src/unix/pty.cc @@ -151,7 +151,7 @@ NAN_METHOD(PtyFork) { signal(SIGINT, SIG_DFL); // file - v8::String::Utf8Value file(info[0]->ToString()); + Nan::Utf8String file(info[0]); // args int i = 0; @@ -162,7 +162,7 @@ NAN_METHOD(PtyFork) { argv[0] = strdup(*file); argv[argl-1] = NULL; for (; i < argc; i++) { - v8::String::Utf8Value arg(argv_->Get(Nan::New(i))->ToString()); + Nan::Utf8String arg(Nan::Get(argv_, i).ToLocalChecked()); argv[i+1] = strdup(*arg); } @@ -173,18 +173,18 @@ NAN_METHOD(PtyFork) { char **env = new char*[envc+1]; env[envc] = NULL; for (; i < envc; i++) { - v8::String::Utf8Value pair(env_->Get(Nan::New(i))->ToString()); + Nan::Utf8String pair(Nan::Get(env_, i).ToLocalChecked()); env[i] = strdup(*pair); } // cwd - v8::String::Utf8Value cwd_(info[3]->ToString()); + Nan::Utf8String cwd_(info[3]); char *cwd = strdup(*cwd_); // size struct winsize winp; - winp.ws_col = info[4]->IntegerValue(); - winp.ws_row = info[5]->IntegerValue(); + winp.ws_col = info[4]->IntegerValue(Nan::GetCurrentContext()).FromJust(); + winp.ws_row = info[5]->IntegerValue(Nan::GetCurrentContext()).FromJust(); winp.ws_xpixel = 0; winp.ws_ypixel = 0; @@ -192,7 +192,7 @@ NAN_METHOD(PtyFork) { struct termios t = termios(); struct termios *term = &t; term->c_iflag = ICRNL | IXON | IXANY | IMAXBEL | BRKINT; - if (info[8]->ToBoolean()->Value()) { + if (info[8]->BooleanValue(info.GetIsolate())) { #if defined(IUTF8) term->c_iflag |= IUTF8; #endif @@ -227,8 +227,8 @@ NAN_METHOD(PtyFork) { cfsetospeed(term, B38400); // uid / gid - int uid = info[6]->IntegerValue(); - int gid = info[7]->IntegerValue(); + int uid = info[6]->IntegerValue(Nan::GetCurrentContext()).FromJust(); + int gid = info[7]->IntegerValue(Nan::GetCurrentContext()).FromJust(); // fork the pty int master = -1; @@ -312,8 +312,8 @@ NAN_METHOD(PtyOpen) { // size struct winsize winp; - winp.ws_col = info[0]->IntegerValue(); - winp.ws_row = info[1]->IntegerValue(); + winp.ws_col = info[0]->IntegerValue(Nan::GetCurrentContext()).FromJust(); + winp.ws_row = info[1]->IntegerValue(Nan::GetCurrentContext()).FromJust(); winp.ws_xpixel = 0; winp.ws_ypixel = 0; @@ -357,11 +357,11 @@ NAN_METHOD(PtyResize) { return Nan::ThrowError("Usage: pty.resize(fd, cols, rows)"); } - int fd = info[0]->IntegerValue(); + int fd = info[0]->IntegerValue(Nan::GetCurrentContext()).FromJust(); struct winsize winp; - winp.ws_col = info[1]->IntegerValue(); - winp.ws_row = info[2]->IntegerValue(); + winp.ws_col = info[1]->IntegerValue(Nan::GetCurrentContext()).FromJust(); + winp.ws_row = info[2]->IntegerValue(Nan::GetCurrentContext()).FromJust(); winp.ws_xpixel = 0; winp.ws_ypixel = 0; @@ -384,9 +384,9 @@ NAN_METHOD(PtyGetProc) { return Nan::ThrowError("Usage: pty.process(fd, tty)"); } - int fd = info[0]->IntegerValue(); + int fd = info[0]->IntegerValue(Nan::GetCurrentContext()).FromJust(); - v8::String::Utf8Value tty_(info[1]->ToString()); + Nan::Utf8String tty_(info[1]); char *tty = strdup(*tty_); char *name = pty_getproc(fd, tty); free(tty); @@ -700,18 +700,10 @@ pty_forkpty(int *amaster, NAN_MODULE_INIT(init) { Nan::HandleScope scope; - Nan::Set(target, - Nan::New("fork").ToLocalChecked(), - Nan::New(PtyFork)->GetFunction()); - Nan::Set(target, - Nan::New("open").ToLocalChecked(), - Nan::New(PtyOpen)->GetFunction()); - Nan::Set(target, - Nan::New("resize").ToLocalChecked(), - Nan::New(PtyResize)->GetFunction()); - Nan::Set(target, - Nan::New("process").ToLocalChecked(), - Nan::New(PtyGetProc)->GetFunction()); + Nan::Export(target, "fork", PtyFork); + Nan::Export(target, "open", PtyOpen); + Nan::Export(target, "resize", PtyResize); + Nan::Export(target, "process", PtyGetProc); } NODE_MODULE(pty, init) From c54e0ddd57696ed07050e99c282763b4e20bcbce Mon Sep 17 00:00:00 2001 From: Eugene Pankov Date: Tue, 7 May 2019 12:06:59 +0200 Subject: [PATCH 05/13] node 10/12 compat fix --- src/unix/pty.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/pty.cc b/src/unix/pty.cc index df3972526..56581e7cf 100644 --- a/src/unix/pty.cc +++ b/src/unix/pty.cc @@ -192,7 +192,7 @@ NAN_METHOD(PtyFork) { struct termios t = termios(); struct termios *term = &t; term->c_iflag = ICRNL | IXON | IXANY | IMAXBEL | BRKINT; - if (info[8]->BooleanValue(info.GetIsolate())) { + if (info[8]->BooleanValue(Nan::GetCurrentContext()).FromJust()) { #if defined(IUTF8) term->c_iflag |= IUTF8; #endif From 1d3c1efb588bac558c525ad38402bd442227af61 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 7 May 2019 20:36:35 -0700 Subject: [PATCH 06/13] Expose cols and rows APIs Fixes #289 --- src/terminal.ts | 2 ++ src/unixTerminal.ts | 8 +++++--- src/windowsTerminal.ts | 8 +++++--- typings/node-pty.d.ts | 10 ++++++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/terminal.ts b/src/terminal.ts index dff737f9f..992ca5115 100644 --- a/src/terminal.ts +++ b/src/terminal.ts @@ -35,6 +35,8 @@ export abstract class Terminal implements ITerminal { public get onExit(): IEvent { return this._onExit.event; } public get pid(): number { return this._pid; } + public get cols(): number { return this._cols; } + public get rows(): number { return this._rows; } constructor(opt?: IPtyForkOptions) { // for 'close' diff --git a/src/unixTerminal.ts b/src/unixTerminal.ts index 860f3660b..b2b0b5161 100644 --- a/src/unixTerminal.ts +++ b/src/unixTerminal.ts @@ -52,8 +52,8 @@ export class UnixTerminal extends Terminal { opt = opt || {}; opt.env = opt.env || process.env; - const cols = opt.cols || DEFAULT_COLS; - const rows = opt.rows || DEFAULT_ROWS; + this._cols = opt.cols || DEFAULT_COLS; + this._rows = opt.rows || DEFAULT_ROWS; const uid = opt.uid || -1; const gid = opt.gid || -1; const env = assign({}, opt.env); @@ -97,7 +97,7 @@ export class UnixTerminal extends Terminal { }; // fork - const term = pty.fork(file, args, parsedEnv, cwd, cols, rows, uid, gid, (encoding === 'utf8'), onexit); + const term = pty.fork(file, args, parsedEnv, cwd, this._cols, this._rows, uid, gid, (encoding === 'utf8'), onexit); this._socket = new PipeSocket(term.fd); if (encoding !== null) { @@ -249,6 +249,8 @@ export class UnixTerminal extends Terminal { public resize(cols: number, rows: number): void { pty.resize(this._fd, cols, rows); + this._cols = cols; + this._rows = rows; } private _sanitizeEnv(env: IProcessEnv): void { diff --git a/src/windowsTerminal.ts b/src/windowsTerminal.ts index cc9444eb8..a02e71edd 100644 --- a/src/windowsTerminal.ts +++ b/src/windowsTerminal.ts @@ -33,8 +33,8 @@ export class WindowsTerminal extends Terminal { } const env = assign({}, opt.env); - const cols = opt.cols || DEFAULT_COLS; - const rows = opt.rows || DEFAULT_ROWS; + this._cols = opt.cols || DEFAULT_COLS; + this._rows = opt.rows || DEFAULT_ROWS; const cwd = opt.cwd || process.cwd(); const name = opt.name || env.TERM || DEFAULT_NAME; const parsedEnv = this._parseEnv(env); @@ -46,7 +46,7 @@ export class WindowsTerminal extends Terminal { this._deferreds = []; // Create new termal. - this._agent = new WindowsPtyAgent(file, args, parsedEnv, cwd, cols, rows, false, opt.experimentalUseConpty); + this._agent = new WindowsPtyAgent(file, args, parsedEnv, cwd, this._cols, this._rows, false, opt.experimentalUseConpty); this._socket = this._agent.outSocket; // Not available until `ready` event emitted. @@ -149,6 +149,8 @@ export class WindowsTerminal extends Terminal { } this._defer(() => { this._agent.resize(cols, rows); + this._cols = cols; + this._rows = rows; }); } diff --git a/typings/node-pty.d.ts b/typings/node-pty.d.ts index 741b7b58b..be87c2269 100644 --- a/typings/node-pty.d.ts +++ b/typings/node-pty.d.ts @@ -45,6 +45,16 @@ declare module 'node-pty' { */ pid: number; + /** + * The column size in characters. + */ + cols: number; + + /** + * The row size in characters. + */ + rows: number; + /** * The title of the active process. */ From 5464b285a824f84e4eee117374b43f7f7377890e Mon Sep 17 00:00:00 2001 From: Eugene Pankov Date: Wed, 8 May 2019 15:46:45 +0200 Subject: [PATCH 07/13] potential net.Socket handle fix for node 12 --- src/unixTerminal.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/unixTerminal.ts b/src/unixTerminal.ts index 860f3660b..17a5c5aec 100644 --- a/src/unixTerminal.ts +++ b/src/unixTerminal.ts @@ -3,7 +3,6 @@ * Copyright (c) 2016, Daniel Imms (MIT License). * Copyright (c) 2018, Microsoft Corporation (MIT License). */ - import * as net from 'net'; import { Terminal, DEFAULT_COLS, DEFAULT_ROWS } from './terminal'; import { IProcessEnv, IPtyForkOptions, IPtyOpenOptions } from './interfaces'; @@ -276,11 +275,10 @@ export class UnixTerminal extends Terminal { */ class PipeSocket extends net.Socket { constructor(fd: number) { - const tty = (process).binding('tty_wrap'); - const guessHandleType = tty.guessHandleType; - tty.guessHandleType = () => 'PIPE'; + const { Pipe, constants } = (process).binding('pipe_wrap') // @types/node has fd as string? https://github.com/DefinitelyTyped/DefinitelyTyped/pull/18275 - super({ fd: fd }); - tty.guessHandleType = guessHandleType; + const handle = new Pipe(constants.SOCKET); + handle.open(fd); + super({ handle }); } } From 23d3517188e27ee36074400f950ff770fa9b9a3e Mon Sep 17 00:00:00 2001 From: Eugene Pankov Date: Wed, 8 May 2019 15:54:37 +0200 Subject: [PATCH 08/13] lint --- src/unixTerminal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unixTerminal.ts b/src/unixTerminal.ts index 17a5c5aec..f734653ea 100644 --- a/src/unixTerminal.ts +++ b/src/unixTerminal.ts @@ -275,7 +275,7 @@ export class UnixTerminal extends Terminal { */ class PipeSocket extends net.Socket { constructor(fd: number) { - const { Pipe, constants } = (process).binding('pipe_wrap') + const { Pipe, constants } = (process).binding('pipe_wrap'); // tslint:disable-line // @types/node has fd as string? https://github.com/DefinitelyTyped/DefinitelyTyped/pull/18275 const handle = new Pipe(constants.SOCKET); handle.open(fd); From 2115fc54006492ca4a8faf22fed1c7eabb43267f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 9 May 2019 09:50:26 -0700 Subject: [PATCH 09/13] Update xterm.js in electron demo to 3.13 --- examples/electron/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/electron/package.json b/examples/electron/package.json index dd560db5f..ebc0c747a 100644 --- a/examples/electron/package.json +++ b/examples/electron/package.json @@ -11,6 +11,6 @@ "dependencies": { "electron": "^4.0.1", "node-pty": "^0.8.0", - "xterm": "^3.12.1" + "xterm": "^3.13.0" } } From 663462aa50b0b374e92a018feb91ffcd85435a87 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 9 May 2019 14:08:31 -0700 Subject: [PATCH 10/13] Ignore VS Code C++ ext data folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bf051c8f2..fde49a551 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ npm-debug.log package-lock.json fixtures/space folder/ .vscode/settings.json +.vscode/ipch/ From 03479d06d1294bb738e200d6eac66411cd7f9add Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 10 May 2019 07:43:37 -0700 Subject: [PATCH 11/13] Publish beta and stable builds to npm automatically --- azure-pipelines.yml | 26 +++++++++++++++++++ scripts/publish.js | 62 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 scripts/publish.js diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b078d70d6..169374311 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,6 +21,7 @@ jobs: - script: | npm run lint displayName: 'Lint' + - job: macOS pool: vmImage: 'xcode9-macos10.13' @@ -38,6 +39,7 @@ jobs: - script: | npm run lint displayName: 'Lint' + - job: Windows pool: vmImage: 'vs2017-win2016' @@ -55,3 +57,27 @@ jobs: - script: | npm run lint displayName: 'Lint' + +- job: Release + dependsOn: + - Linux + - macOS + - Windows + condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: NodeTool@0 + inputs: + versionSpec: '8.x' + displayName: 'Install Node.js' + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.9.4" + displayName: 'Install Yarn' + - script: | + npm i + displayName: 'Install dependencies and build' + - script: | + NPM_AUTH_TOKEN="$(NPM_AUTH_TOKEN)" node ./scripts/publish.js + displayName: 'Publish to npm' diff --git a/scripts/publish.js b/scripts/publish.js new file mode 100644 index 000000000..968531e14 --- /dev/null +++ b/scripts/publish.js @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2019, Microsoft Corporation (MIT License). + */ + +const cp = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const packageJson = require('../package.json'); + +// Setup auth +fs.writeFileSync(`${process.env['HOME']}/.npmrc`, `//registry.npmjs.org/:_authToken=${process.env['NPM_AUTH_TOKEN']}`); + +// Determine if this is a stable or beta release +const publishedVersions = getPublishedVersions(); +const isStableRelease = publishedVersions.indexOf(packageJson.version) === -1; + +// Get the next version +let nextVersion = isStableRelease ? packageJson.version : getNextBetaVersion(); +console.log(`Publishing version: ${nextVersion}`); + +// Set the version in package.json +const packageJsonFile = path.resolve(__dirname, '..', 'package.json'); +packageJson.version = nextVersion; +fs.writeFileSync(packageJsonFile, JSON.stringify(packageJson, null, 2)); + +// Publish +const args = ['publish']; +if (!isStableRelease) { + args.push('--tag', 'beta'); +} +const result = cp.spawn('npm', args, { stdio: 'inherit' }); +result.on('exit', code => process.exit(code)); + +function getNextBetaVersion() { + if (!/^[0-9]+\.[0-9]+\.[0-9]+$/.exec(packageJson.version)) { + console.error('The package.json version must be of the form x.y.z'); + process.exit(1); + } + const tag = 'beta'; + const stableVersion = packageJson.version.split('.'); + const nextStableVersion = `${stableVersion[0]}.${parseInt(stableVersion[1]) + 1}.0`; + const publishedVersions = getPublishedVersions(nextStableVersion, tag); + if (publishedVersions.length === 0) { + return `${nextStableVersion}-${tag}1`; + } + const latestPublishedVersion = publishedVersions.sort((a, b) => { + const aVersion = parseInt(a.substr(a.search(/[0-9]+$/))); + const bVersion = parseInt(b.substr(b.search(/[0-9]+$/))); + return aVersion > bVersion ? -1 : 1; + })[0]; + const latestTagVersion = parseInt(latestPublishedVersion.substr(latestPublishedVersion.search(/[0-9]+$/)), 10); + return `${nextStableVersion}-${tag}${latestTagVersion + 1}`; +} + +function getPublishedVersions(version, tag) { + const versionsProcess = cp.spawnSync('npm', ['view', packageJson.name, 'versions', '--json']); + const versionsJson = JSON.parse(versionsProcess.stdout); + if (tag) { + return versionsJson.filter(v => !v.search(new RegExp(`${version}-${tag}[0-9]+`))); + } + return versionsJson; +} From b5f3e222399b1c91f57159e41916e21472a48f1c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 10 May 2019 07:50:48 -0700 Subject: [PATCH 12/13] Fix badge link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de4610d8a..664058ba0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # node-pty -[![Build Status](https://dev.azure.com/vscode/node-pty/_apis/build/status/Microsoft.node-pty)](https://dev.azure.com/vscode/node-pty/_apis/build/status/Microsoft.node-pty?branchName=master) +[![Build Status](https://dev.azure.com/vscode/node-pty/_apis/build/status/Microsoft.node-pty)](https://dev.azure.com/vscode/node-pty/_build/latest?definitionId=11) `forkpty(3)` bindings for node.js. This allows you to fork processes with pseudoterminal file descriptors. It returns a terminal object which allows reads and writes. From ddb8239e65cb3c20048e1813d46307077f9bbdb1 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 10 May 2019 07:52:33 -0700 Subject: [PATCH 13/13] Don't install yarn in release step --- azure-pipelines.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 169374311..eeded92ad 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -71,10 +71,6 @@ jobs: inputs: versionSpec: '8.x' displayName: 'Install Node.js' - - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.9.4" - displayName: 'Install Yarn' - script: | npm i displayName: 'Install dependencies and build'