From dd36dd55e64bc24da5f7e6c026df818616fad6bb Mon Sep 17 00:00:00 2001 From: Frank Celler Date: Thu, 10 Mar 2016 09:25:54 +0000 Subject: [PATCH] fixes for windows --- arangod/RestServer/WindowsServiceUtils.cpp | 1 + arangosh/Shell/V8ShellFeature.cpp | 8 +- js/client/modules/@arangodb/testing.js | 10 +- lib/ApplicationFeatures/ClientFeature.cpp | 12 +- lib/ApplicationFeatures/ConsoleFeature.cpp | 229 ++++++++++++++++----- lib/ApplicationFeatures/ConsoleFeature.h | 12 +- lib/Basics/shell-colors.h | 29 --- 7 files changed, 207 insertions(+), 94 deletions(-) diff --git a/arangod/RestServer/WindowsServiceUtils.cpp b/arangod/RestServer/WindowsServiceUtils.cpp index 73543298a6..bd748cb021 100644 --- a/arangod/RestServer/WindowsServiceUtils.cpp +++ b/arangod/RestServer/WindowsServiceUtils.cpp @@ -24,6 +24,7 @@ #include #include "Basics/Common.h" +#include "Basics/build.h" #include "Basics/files.h" #include "Basics/messages.h" #include "Logger/Logger.h" diff --git a/arangosh/Shell/V8ShellFeature.cpp b/arangosh/Shell/V8ShellFeature.cpp index 0b31836a3b..2bfb68a681 100644 --- a/arangosh/Shell/V8ShellFeature.cpp +++ b/arangosh/Shell/V8ShellFeature.cpp @@ -178,8 +178,8 @@ bool V8ShellFeature::printHello(V8ClientConnection* v8connection) { s << "arangosh (" << rest::Version::getVerboseVersionString() << ")\n" << "Copyright (c) ArangoDB GmbH"; - _console->printLine(s.str(), true); - _console->printLine("", true); + _console->printLine(s.str()); + _console->printLine(""); _console->printWelcomeInfo(); @@ -194,7 +194,7 @@ bool V8ShellFeature::printHello(V8ClientConnection* v8connection) { << v8connection->databaseName() << "', username: '" << v8connection->username() << "'"; - _console->printLine(is.str(), true); + _console->printLine(is.str()); } else { std::ostringstream is; @@ -216,7 +216,7 @@ bool V8ShellFeature::printHello(V8ClientConnection* v8connection) { promptError = true; } - _console->printLine("", true); + _console->printLine(""); } } diff --git a/js/client/modules/@arangodb/testing.js b/js/client/modules/@arangodb/testing.js index 20c6acae26..96cff3414f 100644 --- a/js/client/modules/@arangodb/testing.js +++ b/js/client/modules/@arangodb/testing.js @@ -101,6 +101,7 @@ const optionsDocumentation = [ ' - `benchargs`: additional commandline arguments to arangob', '', ' - `build`: the directory containing the binaries', + ' - `buildType`: Windows build type (Debug, Release), leave empty on linux', '', ' - `sanitizer`: if set the programs are run with enabled sanitizer', ' and need longer tomeouts', @@ -121,6 +122,7 @@ const optionsDocumentation = [ const optionsDefaults = { "build": "", + "buildType": "", "cleanup": true, "cluster": false, "clusterNodes": 2, @@ -4164,6 +4166,13 @@ function unitTest(cases, options) { } BIN_DIR = fs.join(TOP_DIR, builddir, "bin"); + UNITTESTS_DIR = fs.join(TOP_DIR, fs.join(builddir, "tests")); + + if (options.buildType !== "") { + BIN_DIR = fs.join(BIN_DIR, options.buildType); + UNITTESTS_DIR = fs.join(UNITTESTS_DIR, options.buildType); + } + CONFIG_DIR = fs.join(TOP_DIR, builddir, "etc", "arangodb"); ARANGOB_BIN = fs.join(BIN_DIR, "arangob"); ARANGODUMP_BIN = fs.join(BIN_DIR, "arangodump"); @@ -4176,7 +4185,6 @@ function unitTest(cases, options) { JS_DIR = fs.join(TOP_DIR, "js"); LOGS_DIR = fs.join(TOP_DIR, "logs"); PEM_FILE = fs.join(TOP_DIR, "UnitTests", "server.pem"); - UNITTESTS_DIR = fs.join(TOP_DIR, fs.join(builddir, "tests")); const jsonReply = options.jsonReply; delete options.jsonReply; diff --git a/lib/ApplicationFeatures/ClientFeature.cpp b/lib/ApplicationFeatures/ClientFeature.cpp index e6277be52f..5f1789d633 100644 --- a/lib/ApplicationFeatures/ClientFeature.cpp +++ b/lib/ApplicationFeatures/ClientFeature.cpp @@ -22,6 +22,7 @@ #include "ApplicationFeatures/ClientFeature.h" +#include "ApplicationFeatures/ApplicationServer.h" #include "ApplicationFeatures/ConsoleFeature.h" #include "Logger/Logger.h" #include "ProgramOptions2/ProgramOptions.h" @@ -31,6 +32,7 @@ #include "SimpleHttpClient/SimpleHttpClient.h" using namespace arangodb; +using namespace arangodb::application_features; using namespace arangodb::httpclient; using namespace arangodb::options; using namespace arangodb::rest; @@ -134,7 +136,15 @@ void ClientFeature::validateOptions(std::shared_ptr options) { if (_authentication && !options->processingResult().touched(_section + ".password")) { usleep(10 * 1000); - _password = ConsoleFeature::readPassword("Please specify a password: "); + + ConsoleFeature* console = dynamic_cast(ApplicationServer::lookupFeature("ConsoleFeature")); + + if (console != nullptr) { + _password = console->readPassword("Please specify a password: "); + } else { + std::cout << "Please specify a password: " << std::flush; + std::getline(std::cin, _password); + } } } diff --git a/lib/ApplicationFeatures/ConsoleFeature.cpp b/lib/ApplicationFeatures/ConsoleFeature.cpp index a0eeff8bad..b635f3e661 100644 --- a/lib/ApplicationFeatures/ConsoleFeature.cpp +++ b/lib/ApplicationFeatures/ConsoleFeature.cpp @@ -23,6 +23,7 @@ #include "ApplicationFeatures/ConsoleFeature.h" #include "ApplicationFeatures/ClientFeature.h" +#include "Basics/StringUtils.h" #include "Basics/messages.h" #include "Basics/shell-colors.h" #include "Basics/terminal-utils.h" @@ -31,6 +32,7 @@ #include "ProgramOptions2/Section.h" using namespace arangodb; +using namespace arangodb::basics; using namespace arangodb::options; ConsoleFeature::ConsoleFeature(application_features::ApplicationServer* server) @@ -48,12 +50,20 @@ ConsoleFeature::ConsoleFeature(application_features::ApplicationServer* server) _pagerCommand("less -X -R -F -L"), _prompt("%E@%d> "), _promptError(false), - _supportsColors(isatty(STDIN_FILENO)), + _supportsColors(isatty(STDIN_FILENO) != 0), _toPager(stdout), _toAuditFile(nullptr) { setOptional(false); requiresElevatedPrivileges(false); startsAfter("LoggerFeature"); + + if (!_supportsColors) { + _colors = false; + } + +#if _WIN32 + _codePage = GetConsoleOutputCP(); +#endif } void ConsoleFeature::collectOptions(std::shared_ptr options) { @@ -107,6 +117,12 @@ void ConsoleFeature::start() { LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start"; openLog(); + +#if _WIN32 + if (_codePage != -1) { + SetConsoleOutputCP(_codePage); + } +#endif } void ConsoleFeature::stop() { @@ -115,25 +131,13 @@ void ConsoleFeature::stop() { closeLog(); } -// prints a string to stdout, without a newline (Non-Windows only) on -// Windows, we'll print the line and a newline. No, we cannot use -// std::cout as this doesn't support UTF-8 on Windows. - -void ConsoleFeature::printContinuous(std::string const& s) { -#ifdef _WIN32 - // On Windows, we just print the line followed by a newline - printLine(s, true); -#else - fprintf(stdout, "%s", s.c_str()); - fflush(stdout); -#endif -} - #ifdef _WIN32 static bool _newLine() { COORD pos; CONSOLE_SCREEN_BUFFER_INFO bufferInfo; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &bufferInfo); + auto handle = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(handle, &bufferInfo); + if (bufferInfo.dwCursorPosition.Y + 1 >= bufferInfo.dwSize.Y) { // when we are at the last visible line of the console // the first line of console is deleted (the content of the console @@ -143,51 +147,55 @@ static bool _newLine() { srctScrollRect.Bottom = bufferInfo.dwCursorPosition.Y + 1; srctScrollRect.Left = 0; srctScrollRect.Right = bufferInfo.dwSize.X; + COORD coordDest; coordDest.X = 0; coordDest.Y = -1; + CONSOLE_SCREEN_BUFFER_INFO consoleScreenBufferInfo; CHAR_INFO chiFill; chiFill.Char.AsciiChar = (char)' '; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), - &consoleScreenBufferInfo)) { + + if (GetConsoleScreenBufferInfo(handle, &consoleScreenBufferInfo)) { chiFill.Attributes = consoleScreenBufferInfo.wAttributes; } else { // Fill the bottom row with green blanks. chiFill.Attributes = BACKGROUND_GREEN | FOREGROUND_RED; } - ScrollConsoleScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE), &srctScrollRect, + ScrollConsoleScreenBuffer(handle, &srctScrollRect, nullptr, coordDest, &chiFill); pos.Y = bufferInfo.dwCursorPosition.Y; pos.X = 0; - SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + SetConsoleCursorPosition(handle, pos); return true; } else { pos.Y = bufferInfo.dwCursorPosition.Y + 1; pos.X = 0; - SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + SetConsoleCursorPosition(handle, pos); return false; } } #endif #ifdef _WIN32 -static void _printLine(std::string const& s) { - LPWSTR wBuf = (LPWSTR)TRI_Allocate(TRI_CORE_MEM_ZONE, - (sizeof WCHAR) * (s.size() + 1), true); +static void _print2(std::string const& s, int attr) { + size_t sLen = s.size(); + LPWSTR wBuf = new WCHAR[sLen + 1]; int wLen = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, wBuf, - (int)((sizeof WCHAR) * (s.size() + 1))); + (int)((sizeof WCHAR) * (sLen + 1))); if (wLen) { DWORD n; COORD pos; CONSOLE_SCREEN_BUFFER_INFO bufferInfo; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &bufferInfo); + auto handle = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(handle, &bufferInfo); + // save old cursor position pos = bufferInfo.dwCursorPosition; - size_t newX = static_cast(pos.X) + s.size(); - // size_t oldY = static_cast(pos.Y); + size_t newX = static_cast(pos.X) + wLen; + if (newX >= static_cast(bufferInfo.dwSize.X)) { for (size_t i = 0; i <= newX / bufferInfo.dwSize.X; ++i) { // insert as many newlines as we need. this prevents running out of @@ -200,62 +208,179 @@ static void _printLine(std::string const& s) { } // save new cursor position - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &bufferInfo); + GetConsoleScreenBufferInfo(handle, &bufferInfo); auto newPos = bufferInfo.dwCursorPosition; // print the actual string. note: printing does not advance the cursor // position - SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); - WriteConsoleOutputCharacterW(GetStdHandle(STD_OUTPUT_HANDLE), wBuf, - (DWORD)s.size(), pos, &n); + SetConsoleCursorPosition(handle, pos); + SetConsoleTextAttribute(handle, attr); + WriteConsoleOutputCharacterW(handle, wBuf, (DWORD)wLen, pos, &n); // finally set the cursor position to where the printing should have // stopped - SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), newPos); + SetConsoleCursorPosition(handle, newPos); } else { fprintf(stdout, "window error: '%d' \r\n", GetLastError()); fprintf(stdout, "%s\r\n", s.c_str()); } if (wBuf) { - TRI_Free(TRI_CORE_MEM_ZONE, wBuf); + delete[] wBuf; } } + +static void _print(std::string const& s) { + auto pos = s.find_first_of("\x1b"); + + if (pos == std::string::npos) { + int color = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE; + _print2(s, color); + } + else { + std::vector lines = StringUtils::split(s, '\x1b', '\0'); + + int i = 0; + int color = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE; + int attr = 0; + + for (auto line : lines) { + size_t pos = 0; + + if (i++ != 0 && !line.empty()) { + char c = line[0]; + + if (c == '[') { + int code = 0; + + for (++pos; pos < line.size(); ++pos) { + c = line[pos]; + + if ('0' <= c && c <= '9') { + code = code * 10 + (c - '0'); + } + else if (c == 'm' || c == ';') { + switch (code) { + case 0: + attr = 0; + color = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE; + break; + + case 1: // BOLD + case 5: // BLINK + attr = FOREGROUND_INTENSITY; + break; + + case 30: + color = BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN; + break; + + case 31: + color = FOREGROUND_RED; + break; + + case 32: + color = FOREGROUND_GREEN; + break; + + case 33: + color = FOREGROUND_RED | FOREGROUND_GREEN; + break; + + case 34: + color = FOREGROUND_BLUE; + break; + + case 35: + color = FOREGROUND_BLUE | FOREGROUND_RED; + break; + + case 36: + color = FOREGROUND_BLUE | FOREGROUND_GREEN; + break; + + case 37: + color = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE; + break; + + case 39: + color = 0; + break; + } + + code = 0; + } + + if (c == 'm') { + ++pos; + break; + } + } + } + } + + + _print2(line.substr(pos), attr | color); + } + } +} + #endif -void ConsoleFeature::printLine(std::string const& s, bool forceNewLine) { +// prints a string to stdout, without a newline +void ConsoleFeature::printContinuous(std::string const& s) { #ifdef _WIN32 -//#warning do we need forceNewLine + // no, we cannot use std::cout as this doesn't support UTF-8 on Windows - if (!cygwinShell) { + if (s.empty()) { + return; + } + + if (/*!_cygwinShell*/ true) { // no, we cannot use std::cout as this doesn't support UTF-8 on Windows // fprintf(stdout, "%s\r\n", s.c_str()); - TRI_vector_string_t subStrings = TRI_SplitString(s.c_str(), '\n'); - bool hasNewLines = (s.find("\n") != std::string::npos) | forceNewLine; - if (hasNewLines) { - for (size_t i = 0; i < subStrings._length; i++) { - _printLine(subStrings._buffer[i]); - _newLine(); - } - } else { - _printLine(s); + std::vector lines = StringUtils::split(s, '\n', '\0'); + + auto last = lines.back(); + lines.pop_back(); + + for (auto& line : lines) { + _print(line); + _newLine(); + } + + _print(last); + } else +#endif + { + fprintf(stdout, "%s", s.c_str()); + fflush(stdout); + } +} + +void ConsoleFeature::printLine(std::string const& s) { +#ifdef _WIN32 + // no, we cannot use std::cout as this doesn't support UTF-8 on Windows + + if (/*!_cygwinShell*/ true) { + + std::vector lines = StringUtils::split(s, '\n', '\0'); + + for (auto& line : lines) { + _print(line); + _newLine(); } - TRI_DestroyVectorString(&subStrings); } else #endif { fprintf(stdout, "%s\n", s.c_str()); + fflush(stdout); } } void ConsoleFeature::printErrorLine(std::string const& s) { -#ifdef _WIN32 - // no, we can use std::cerr as this doesn't support UTF-8 on Windows printLine(s); -#else - fprintf(stderr, "%s\n", s.c_str()); -#endif } std::string ConsoleFeature::readPassword(std::string const& message) { diff --git a/lib/ApplicationFeatures/ConsoleFeature.h b/lib/ApplicationFeatures/ConsoleFeature.h index efdd640598..937738a0cf 100644 --- a/lib/ApplicationFeatures/ConsoleFeature.h +++ b/lib/ApplicationFeatures/ConsoleFeature.h @@ -50,7 +50,7 @@ class ConsoleFeature final : public application_features::ApplicationFeature { std::string const& prompt() const { return _prompt; } private: -#ifdef WIN32 +#ifdef _WIN32 int16_t _codePage; bool _cygwinShell; #endif @@ -63,17 +63,15 @@ class ConsoleFeature final : public application_features::ApplicationFeature { std::string _pagerCommand; std::string _prompt; - public: - static void printContinuous(std::string const&); - static void printLine(std::string const&, bool forceNewLine = false); - static void printErrorLine(std::string const&); - static std::string readPassword(std::string const& message); - public: void setPromptError(bool value) { _promptError = value; } void setSupportsColors(bool value) { _supportsColors = value; } void printWelcomeInfo(); void printByeBye(); + std::string readPassword(std::string const& message); + void printContinuous(std::string const&); + void printLine(std::string const&); + void printErrorLine(std::string const&); void print(std::string const&); void openLog(); void closeLog(); diff --git a/lib/Basics/shell-colors.h b/lib/Basics/shell-colors.h index 93ea56b45e..31203c3d5c 100644 --- a/lib/Basics/shell-colors.h +++ b/lib/Basics/shell-colors.h @@ -24,8 +24,6 @@ #ifndef LIB_BASICS_SHELL_COLORS_H #define LIB_BASICS_SHELL_COLORS_H 1 -#ifndef _WIN32 - //////////////////////////////////////////////////////////////////////////////// /// @brief color red //////////////////////////////////////////////////////////////////////////////// @@ -140,31 +138,4 @@ #define TRI_SHELL_COLOR_RESET "\x1b[0m" -#else -// ............................................................................. -// Quick hack for windows -// ............................................................................. - -#define TRI_SHELL_COLOR_RED "" -#define TRI_SHELL_COLOR_BOLD_RED "" -#define TRI_SHELL_COLOR_GREEN "" -#define TRI_SHELL_COLOR_BOLD_GREEN "" -#define TRI_SHELL_COLOR_BLUE "" -#define TRI_SHELL_COLOR_BOLD_BLUE "" -#define TRI_SHELL_COLOR_YELLOW "" -#define TRI_SHELL_COLOR_BOLD_YELLOW "" -#define TRI_SHELL_COLOR_WHITE "" -#define TRI_SHELL_COLOR_BOLD_WHITE "" -#define TRI_SHELL_COLOR_CYAN "" -#define TRI_SHELL_COLOR_BOLD_CYAN "" -#define TRI_SHELL_COLOR_MAGENTA "" -#define TRI_SHELL_COLOR_BOLD_MAGENTA "" -#define TRI_SHELL_COLOR_BLACK "" -#define TRI_SHELL_COLOR_BOLD_BLACK "" -#define TRI_SHELL_COLOR_BLINK "" -#define TRI_SHELL_COLOR_BRIGHT "" -#define TRI_SHELL_COLOR_RESET "" - -#endif - #endif