Compare commits

..

1 Commits

Author SHA1 Message Date
Ryan Prichard
3338e421c2 Localized fix for issue 124. It compiles, but it's not really tested 2017-07-17 16:44:38 -05:00
13 changed files with 97 additions and 276 deletions

17
.drone.yml Normal file
View File

@ -0,0 +1,17 @@
# Build configure for https://www.tea-ci.org (fork of Drone CI with Msys2 support)
build:
image: teaci/msys$$arch
pull: true
shell: msys$$arch
commands:
- pacman -S --needed --noconfirm --noprogressbar mingw-w64-cross-gcc mingw-w64-cross-crt-git
- ./configure
- make
- make tests
- build/trivial_test.exe
- mintty --log - --exec build/winpty.exe cmd /c ver | grep Windows
matrix:
arch:
- 64
- 32

1
.gitignore vendored
View File

@ -10,7 +10,6 @@ winpty.opensdf
/build-gyp
/build-libpty
/ship/packages
/ship/tmp
/src/Default
/src/Release
/src/gen

View File

@ -1,6 +1,6 @@
# winpty
[![Build Status](https://ci.appveyor.com/api/projects/status/69tb9gylsph1ee1x/branch/master?svg=true)](https://ci.appveyor.com/project/rprichard/winpty/branch/master)
[![Build Status](https://tea-ci.org/api/badges/rprichard/winpty/status.svg)](https://tea-ci.org/rprichard/winpty)
winpty is a Windows software package providing an interface similar to a Unix
pty-master for communicating with Windows console programs. The package

View File

@ -1,16 +0,0 @@
image: Visual Studio 2015
init:
- C:\msys64\usr\bin\bash --login -c "pacman -S --needed --noconfirm --noprogressbar msys/make msys/tar msys/gcc mingw-w64-cross-toolchain"
- C:\cygwin\setup-x86 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make
- C:\cygwin64\setup-x86_64 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make
build_script:
- C:\Python27-x64\python.exe ship\ship.py --kind msys2 --arch x64 --syspath C:\msys64
- C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch ia32 --syspath C:\cygwin
- C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch x64 --syspath C:\cygwin64
- C:\Python27-x64\python.exe ship\make_msvc_package.py
artifacts:
- path: ship\packages\*.tar.gz
- path: ship\packages\*.zip

View File

@ -1,90 +0,0 @@
#include <windows.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "TestUtil.cc"
static void usage() {
printf("usage: SetBufInfo [-set] [-buf W H] [-win W H] [-pos X Y]\n");
}
int main(int argc, char *argv[]) {
const HANDLE conout = CreateFileW(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
ASSERT(conout != INVALID_HANDLE_VALUE);
bool change = false;
BOOL success;
CONSOLE_SCREEN_BUFFER_INFOEX info = {};
info.cbSize = sizeof(info);
success = GetConsoleScreenBufferInfoEx(conout, &info);
ASSERT(success && "GetConsoleScreenBufferInfoEx failed");
for (int i = 1; i < argc; ) {
std::string arg = argv[i];
if (arg == "-buf" && (i + 2) < argc) {
info.dwSize.X = atoi(argv[i + 1]);
info.dwSize.Y = atoi(argv[i + 2]);
i += 3;
change = true;
} else if (arg == "-pos" && (i + 2) < argc) {
int dx = info.srWindow.Right - info.srWindow.Left;
int dy = info.srWindow.Bottom - info.srWindow.Top;
info.srWindow.Left = atoi(argv[i + 1]);
info.srWindow.Top = atoi(argv[i + 2]);
i += 3;
info.srWindow.Right = info.srWindow.Left + dx;
info.srWindow.Bottom = info.srWindow.Top + dy;
change = true;
} else if (arg == "-win" && (i + 2) < argc) {
info.srWindow.Right = info.srWindow.Left + atoi(argv[i + 1]) - 1;
info.srWindow.Bottom = info.srWindow.Top + atoi(argv[i + 2]) - 1;
i += 3;
change = true;
} else if (arg == "-set") {
change = true;
++i;
} else if (arg == "--help" || arg == "-help") {
usage();
exit(0);
} else {
fprintf(stderr, "error: unrecognized argument: %s\n", arg.c_str());
usage();
exit(1);
}
}
if (change) {
success = SetConsoleScreenBufferInfoEx(conout, &info);
if (success) {
printf("success\n");
} else {
printf("SetConsoleScreenBufferInfoEx call failed\n");
}
success = GetConsoleScreenBufferInfoEx(conout, &info);
ASSERT(success && "GetConsoleScreenBufferInfoEx failed");
}
auto dump = [](const char *fmt, ...) {
char msg[256];
va_list ap;
va_start(ap, fmt);
vsprintf(msg, fmt, ap);
va_end(ap);
trace("%s", msg);
printf("%s\n", msg);
};
dump("buffer-size: %d x %d", info.dwSize.X, info.dwSize.Y);
dump("window-size: %d x %d",
info.srWindow.Right - info.srWindow.Left + 1,
info.srWindow.Bottom - info.srWindow.Top + 1);
dump("window-pos: %d, %d", info.srWindow.Left, info.srWindow.Top);
return 0;
}

View File

@ -1,17 +1,12 @@
import os
import sys
# These scripts need to continue using Python 2 rather than 3, because
# make_msvc_package.py puts the current Python interpreter on the PATH for the
# sake of gyp, and gyp doesn't work with Python 3 yet.
# https://bugs.chromium.org/p/gyp/issues/detail?id=36
if os.name != "nt":
sys.exit("Error: ship scripts require native Python 2.7. (wrong os.name)")
if sys.version_info[0:2] != (2,7):
sys.exit("Error: ship scripts require native Python 2.7. (wrong version)")
import glob
import hashlib
import shutil
import subprocess
from distutils.spawn import find_executable
@ -25,11 +20,11 @@ def rmrf(patterns):
for pattern in patterns:
for path in glob.glob(pattern):
if os.path.isdir(path) and not os.path.islink(path):
print("+ rm -r " + path)
print "+ rm -r " + path
sys.stdout.flush()
shutil.rmtree(path)
elif os.path.isfile(path):
print("+ rm " + path)
print "+ rm " + path
sys.stdout.flush()
os.remove(path)
@ -42,48 +37,17 @@ def requireExe(name, guesses):
for guess in guesses:
if os.path.exists(guess):
newDir = os.path.dirname(guess)
print("Adding " + newDir + " to Path to provide " + name)
print "Adding " + newDir + " to Path to provide " + name
os.environ["Path"] = newDir + ";" + os.environ["Path"]
ret = find_executable(name)
if ret is None:
sys.exit("Error: required EXE is missing from Path: " + name)
return ret
class ModifyEnv:
def __init__(self, **kwargs):
self._changes = dict(kwargs)
self._original = dict()
def __enter__(self):
for var, val in self._changes.items():
self._original[var] = os.environ[var]
os.environ[var] = val
def __exit__(self, type, value, traceback):
for var, val in self._original.items():
os.environ[var] = val
def sha256(path):
with open(path, "rb") as fp:
return hashlib.sha256(fp.read()).hexdigest()
def checkSha256(path, expected):
actual = sha256(path)
if actual != expected:
sys.exit("error: sha256 hash mismatch on {}: expected {}, found {}".format(
path, expected, actual))
requireExe("git.exe", [
"C:\\Program Files\\Git\\cmd\\git.exe",
"C:\\Program Files (x86)\\Git\\cmd\\git.exe"
])
commitHash = subprocess.check_output(["git.exe", "rev-parse", "HEAD"]).strip()
commitHash = subprocess.check_output(["git.exe", "rev-parse", "HEAD"]).decode().strip()
defaultPathEnviron = "C:\\Windows\\System32;C:\\Windows"
ZIP_TOOL = requireExe("7z.exe", [
"C:\\Program Files\\7-Zip\\7z.exe",
"C:\\Program Files (x86)\\7-Zip\\7z.exe",
])
requireExe("curl.exe", [])

View File

@ -36,6 +36,10 @@ import subprocess
import sys
os.chdir(common_ship.topDir)
ZIP_TOOL = common_ship.requireExe("7z.exe", [
"C:\\Program Files\\7-Zip\\7z.exe",
"C:\\Program Files (x86)\\7-Zip\\7z.exe",
])
MSVC_VERSION_TABLE = {
"2015" : {
@ -96,16 +100,14 @@ def build(arch, packageDir, xp=False):
if not os.path.isfile(devCmdPath):
sys.exit("Error: MSVC environment script missing: " + devCmdPath)
toolsetArgument = " --toolset {}".format(versionInfo["xp_toolset"]) if xp else ""
newEnv = os.environ.copy()
newEnv["PATH"] = os.path.dirname(sys.executable) + ";" + common_ship.defaultPathEnviron
commandLine = (
'"' + devCmdPath + '" && ' +
'"' + devCmdPath + '" && '
" vcbuild.bat" +
" --gyp-msvs-version " + versionInfo["gyp_version"] +
" --msvc-platform " + archInfo["msvc_platform"] +
" --commit-hash " + common_ship.commitHash +
toolsetArgument
" --commit-hash " + common_ship.commitHash
)
subprocess.check_call(commandLine, shell=True, env=newEnv)
@ -157,7 +159,7 @@ def buildPackage():
shutil.copy(topDir + "/README.md", packageDir)
shutil.copy(topDir + "/RELEASES.md", packageDir)
subprocess.check_call([common_ship.ZIP_TOOL, "a", packageFile, "."], cwd=packageDir)
subprocess.check_call([ZIP_TOOL, "a", packageFile, "."], cwd=packageDir)
if __name__ == "__main__":
buildPackage()

View File

@ -23,16 +23,20 @@
#
# Run with native CPython 2.7 on a 64-bit computer.
#
# Each of the targets in BUILD_TARGETS must be installed to the default
# location. Each target must have the appropriate MinGW and non-MinGW
# compilers installed, as well as make and tar.
#
import common_ship
from optparse import OptionParser
import multiprocessing
import os
import shutil
import subprocess
import sys
os.chdir(common_ship.topDir)
def dllVersion(path):
version = subprocess.check_output(
@ -40,40 +44,46 @@ def dllVersion(path):
"[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"" + path + "\").FileVersion"])
return version.strip()
os.chdir(common_ship.topDir)
# Determine other build parameters.
BUILD_KINDS = {
"cygwin": {
"path": ["bin"],
"dll": "bin\\cygwin1.dll",
print "Determining Cygwin/MSYS2 DLL versions..."
sys.stdout.flush()
BUILD_TARGETS = [
# {
# "name": "msys",
# "path": "C:\\MinGW\\bin;C:\\MinGW\\msys\\1.0\\bin",
# # The parallel make.exe in the original MSYS/MinGW project hangs.
# "make_binary": "mingw32-make.exe",
# },
{
"name": "msys2-" + dllVersion("C:\\msys32\\usr\\bin\\msys-2.0.dll") + "-ia32",
"path": "C:\\msys32\\mingw32\\bin;C:\\msys32\\usr\\bin",
},
"msys2": {
"path": ["opt\\bin", "usr\\bin"],
"dll": "usr\\bin\\msys-2.0.dll",
{
"name": "msys2-" + dllVersion("C:\\msys64\\usr\\bin\\msys-2.0.dll") + "-x64",
"path": "C:\\msys64\\mingw64\\bin;C:\\msys64\\usr\\bin",
},
}
{
"name": "cygwin-" + dllVersion("C:\\cygwin\\bin\\cygwin1.dll") + "-ia32",
"path": "C:\\cygwin\\bin",
},
{
"name": "cygwin-" + dllVersion("C:\\cygwin64\\bin\\cygwin1.dll") + "-x64",
"path": "C:\\cygwin64\\bin",
},
]
def buildTarget(kind, syspath, arch):
binPaths = [os.path.join(syspath, p) for p in BUILD_KINDS[kind]["path"]]
binPaths += common_ship.defaultPathEnviron.split(";")
newPath = ";".join(binPaths)
dllver = dllVersion(os.path.join(syspath, BUILD_KINDS[kind]["dll"]))
packageName = "winpty-{}-{}-{}-{}".format(common_ship.winptyVersion, kind, dllver, arch)
def buildTarget(target):
packageName = "winpty-" + common_ship.winptyVersion + "-" + target["name"]
if os.path.exists("ship\\packages\\" + packageName):
shutil.rmtree("ship\\packages\\" + packageName)
print("+ Setting PATH to: {}".format(newPath))
with common_ship.ModifyEnv(PATH=newPath):
oldPath = os.environ["PATH"]
os.environ["PATH"] = target["path"] + ";" + common_ship.defaultPathEnviron
subprocess.check_call(["sh.exe", "configure"])
subprocess.check_call(["make.exe", "clean"])
makeBinary = target.get("make_binary", "make.exe")
subprocess.check_call([makeBinary, "clean"])
makeBaseCmd = [
"make.exe",
makeBinary,
"USE_PCH=0",
"COMMIT_HASH=" + common_ship.commitHash,
"PREFIX=ship/packages/" + packageName
]
@ -83,22 +93,16 @@ def buildTarget(kind, syspath, arch):
subprocess.check_call(["tar.exe", "cvfz",
packageName + ".tar.gz",
packageName], cwd=os.path.join(os.getcwd(), "ship", "packages"))
os.environ["PATH"] = oldPath
def main():
parser = OptionParser()
parser.add_option("--kind", type="choice", choices=["cygwin", "msys2"])
parser.add_option("--syspath")
parser.add_option("--arch", type="choice", choices=["ia32", "x64"])
(args, extra) = parser.parse_args()
args.kind or parser.error("--kind must be specified")
args.arch or parser.error("--arch must be specified")
args.syspath or parser.error("--syspath must be specified")
extra and parser.error("unexpected positional argument(s)")
buildTarget(args.kind, args.syspath, args.arch)
oldPath = os.environ["PATH"]
for t in BUILD_TARGETS:
os.environ["PATH"] = t["path"] + ";" + common_ship.defaultPathEnviron
subprocess.check_output(["tar.exe", "--help"])
subprocess.check_output(["make.exe", "--help"])
for t in BUILD_TARGETS:
buildTarget(t)
if __name__ == "__main__":
main()

View File

@ -27,7 +27,6 @@
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <string>
#include <utility>
#include <vector>
@ -333,9 +332,6 @@ void Agent::handlePacket(ReadBuffer &packet)
// at once, we can ignore the early ones.
handleSetSizePacket(packet);
break;
case AgentMsg::GetConsoleProcessList:
handleGetConsoleProcessListPacket(packet);
break;
default:
trace("Unrecognized message, id:%d", type);
}
@ -430,33 +426,6 @@ void Agent::handleSetSizePacket(ReadBuffer &packet)
writePacket(reply);
}
void Agent::handleGetConsoleProcessListPacket(ReadBuffer &packet)
{
packet.assertEof();
auto processList = std::vector<DWORD>(64);
auto processCount = GetConsoleProcessList(&processList[0], processList.size());
// The process list can change while we're trying to read it
while (processList.size() < processCount) {
// Multiplying by two caps the number of iterations
const auto newSize = std::max<DWORD>(processList.size() * 2, processCount);
processList.resize(newSize);
processCount = GetConsoleProcessList(&processList[0], processList.size());
}
if (processCount == 0) {
trace("GetConsoleProcessList failed");
}
auto reply = newPacket();
reply.putInt32(processCount);
for (DWORD i = 0; i < processCount; i++) {
reply.putInt32(processList[i]);
}
writePacket(reply);
}
void Agent::pollConinPipe()
{
const std::string newData = m_coninPipe->readAllToString();
@ -602,11 +571,9 @@ void Agent::syncConsoleTitle()
{
std::wstring newTitle = m_console.title();
if (newTitle != m_currentTitle) {
if (!m_plainMode && !m_conoutPipe->isClosed()) {
std::string command = std::string("\x1b]0;") +
utf8FromWide(newTitle) + "\x07";
m_conoutPipe->write(command.c_str());
}
m_currentTitle = newTitle;
}
}

View File

@ -59,7 +59,6 @@ private:
void writePacket(WriteBuffer &packet);
void handleStartProcessPacket(ReadBuffer &packet);
void handleSetSizePacket(ReadBuffer &packet);
void handleGetConsoleProcessListPacket(ReadBuffer &packet);
void pollConinPipe();
protected:

View File

@ -218,11 +218,6 @@ WINPTY_API BOOL
winpty_set_size(winpty_t *wp, int cols, int rows,
winpty_error_ptr_t *err /*OPTIONAL*/);
/* Gets a list of processes attached to the console. */
WINPTY_API int
winpty_get_console_process_list(winpty_t *wp, int *processList, const int processCount,
winpty_error_ptr_t *err /*OPTIONAL*/);
/* Frees the winpty_t object and the OS resources contained in it. This
* call breaks the connection with the agent, which should then close its
* console, terminating the processes attached to it.

View File

@ -130,9 +130,17 @@ static void translateException(winpty_error_ptr_t *&err) {
} catch (...) {
ret = const_cast<winpty_error_ptr_t>(&kUncaughtException);
}
std::string utf8Dynamic;
const char *utf8Ptr = "";
try {
utf8Dynamic = utf8FromWide(winpty_error_msg(ret));
utf8Ptr = utf8Dynamic.c_str();
} catch (const std::bad_alloc&) {
utf8Ptr = "Out of memory converting winpty error message to UTF-8";
}
trace("libwinpty error: code=%u msg='%s'",
static_cast<unsigned>(ret->code),
utf8FromWide(winpty_error_msg(ret)).c_str());
utf8Ptr);
if (err != nullptr) {
*err = ret;
} else {
@ -935,33 +943,6 @@ winpty_set_size(winpty_t *wp, int cols, int rows,
} API_CATCH(FALSE)
}
WINPTY_API int
winpty_get_console_process_list(winpty_t *wp, int *processList, const int processCount,
winpty_error_ptr_t *err /*OPTIONAL*/) {
API_TRY {
ASSERT(wp != nullptr);
ASSERT(processList != nullptr);
LockGuard<Mutex> lock(wp->mutex);
RpcOperation rpc(*wp);
auto packet = newPacket();
packet.putInt32(AgentMsg::GetConsoleProcessList);
writePacket(*wp, packet);
auto reply = readPacket(*wp);
auto actualProcessCount = reply.getInt32();
if (actualProcessCount <= processCount) {
for (auto i = 0; i < actualProcessCount; i++) {
processList[i] = reply.getInt32();
}
}
reply.assertEof();
rpc.success();
return actualProcessCount;
} API_CATCH(0)
}
WINPTY_API void winpty_free(winpty_t *wp) {
// At least in principle, CloseHandle can fail, so this deletion can
// fail. It won't throw an exception, but maybe there's an error that

View File

@ -26,7 +26,6 @@ struct AgentMsg
enum Type {
StartProcess,
SetSize,
GetConsoleProcessList,
};
};