diff --git a/arangosh/Dump/DumpFeature.cpp b/arangosh/Dump/DumpFeature.cpp index ffb0dc63bc..3b439d3af8 100644 --- a/arangosh/Dump/DumpFeature.cpp +++ b/arangosh/Dump/DumpFeature.cpp @@ -67,14 +67,14 @@ DumpFeature::DumpFeature(application_features::ApplicationServer* server, _result(result), _batchId(0), _clusterMode(false), - _stats{ 0, 0, 0 } { + _stats{0, 0, 0} { requiresElevatedPrivileges(false); setOptional(false); startsAfter("Client"); startsAfter("Logger"); _outputDirectory = - FileUtils::buildFilename(FileUtils::currentDirectory(), "dump"); + FileUtils::buildFilename(FileUtils::currentDirectory().result(), "dump"); } void DumpFeature::collectOptions( @@ -117,8 +117,9 @@ void DumpFeature::collectOptions( options->addOption("--tick-end", "last tick to be included in data dump", new UInt64Parameter(&_tickEnd)); - - options->addOption("--compat28", "produce a dump compatible with ArangoDB 2.8", + + options->addOption("--compat28", + "produce a dump compatible with ArangoDB 2.8", new BooleanParameter(&_compat28)); } @@ -130,8 +131,9 @@ void DumpFeature::validateOptions( if (1 == n) { _outputDirectory = positionals[0]; } else if (1 < n) { - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "expecting at most one directory, got " + - StringUtils::join(positionals, ", "); + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << "expecting at most one directory, got " + + StringUtils::join(positionals, ", "); FATAL_ERROR_EXIT(); } @@ -144,7 +146,8 @@ void DumpFeature::validateOptions( } if (_tickStart < _tickEnd) { - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "invalid values for --tick-start or --tick-end"; + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << "invalid values for --tick-start or --tick-end"; FATAL_ERROR_EXIT(); } @@ -165,23 +168,28 @@ void DumpFeature::prepare() { isDirectory = TRI_IsDirectory(_outputDirectory.c_str()); if (isDirectory) { - std::vector files(TRI_FullTreeDirectory(_outputDirectory.c_str())); + std::vector files( + TRI_FullTreeDirectory(_outputDirectory.c_str())); // we don't care if the target directory is empty - isEmptyDirectory = (files.size() <= 1); // TODO: TRI_FullTreeDirectory always returns at least one element (""), even if directory is empty? + isEmptyDirectory = (files.size() <= 1); // TODO: TRI_FullTreeDirectory + // always returns at least one + // element (""), even if + // directory is empty? } } if (_outputDirectory.empty() || (TRI_ExistsFile(_outputDirectory.c_str()) && !isDirectory)) { - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "cannot write to output directory '" << _outputDirectory - << "'"; + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << "cannot write to output directory '" << _outputDirectory << "'"; FATAL_ERROR_EXIT(); } if (isDirectory && !isEmptyDirectory && !_overwrite) { - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "output directory '" << _outputDirectory - << "' already exists. use \"--overwrite true\" to " - "overwrite data in it"; + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << "output directory '" << _outputDirectory + << "' already exists. use \"--overwrite true\" to " + "overwrite data in it"; FATAL_ERROR_EXIT(); } @@ -192,8 +200,9 @@ void DumpFeature::prepare() { errorMessage); if (res != TRI_ERROR_NO_ERROR) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "unable to create output directory '" << _outputDirectory - << "': " << errorMessage; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "unable to create output directory '" << _outputDirectory + << "': " << errorMessage; FATAL_ERROR_EXIT(); } } @@ -209,9 +218,8 @@ int DumpFeature::startBatch(std::string DBserver, std::string& errorMsg) { urlExt = "?DBserver=" + DBserver; } - std::unique_ptr response( - _httpClient->request(rest::RequestType::POST, url + urlExt, - body.c_str(), body.size())); + std::unique_ptr response(_httpClient->request( + rest::RequestType::POST, url + urlExt, body.c_str(), body.size())); if (response == nullptr || !response->isComplete()) { errorMsg = @@ -262,9 +270,8 @@ void DumpFeature::extendBatch(std::string DBserver) { urlExt = "?DBserver=" + DBserver; } - std::unique_ptr response( - _httpClient->request(rest::RequestType::PUT, url + urlExt, - body.c_str(), body.size())); + std::unique_ptr response(_httpClient->request( + rest::RequestType::PUT, url + urlExt, body.c_str(), body.size())); // ignore any return value } @@ -294,8 +301,8 @@ int DumpFeature::dumpCollection(int fd, std::string const& cid, std::string& errorMsg) { uint64_t chunkSize = _chunkSize; - std::string const baseUrl = "/_api/replication/dump?collection=" + cid + - "&ticks=false&flush=false"; + std::string const baseUrl = + "/_api/replication/dump?collection=" + cid + "&ticks=false&flush=false"; uint64_t fromTick = _tickStart; @@ -313,8 +320,8 @@ int DumpFeature::dumpCollection(int fd, std::string const& cid, _stats._totalBatches++; - std::unique_ptr response(_httpClient->request( - rest::RequestType::GET, url, nullptr, 0)); + std::unique_ptr response( + _httpClient->request(rest::RequestType::GET, url, nullptr, 0)); if (response == nullptr || !response->isComplete()) { errorMsg = @@ -543,7 +550,8 @@ int DumpFeature::runDump(std::string& dbName, std::string& errorMsg) { return TRI_ERROR_INTERNAL; } - uint64_t const cid = arangodb::basics::VelocyPackHelper::extractIdValue(parameters); + uint64_t const cid = + arangodb::basics::VelocyPackHelper::extractIdValue(parameters); std::string const name = arangodb::basics::VelocyPackHelper::getStringValue( parameters, "name", ""); bool const deleted = arangodb::basics::VelocyPackHelper::getBooleanValue( @@ -642,7 +650,8 @@ int DumpFeature::runDump(std::string& dbName, std::string& errorMsg) { } extendBatch(""); - int res = dumpCollection(fd, std::to_string(cid), name, maxTick, errorMsg); + int res = + dumpCollection(fd, std::to_string(cid), name, maxTick, errorMsg); TRI_CLOSE(fd); @@ -664,8 +673,7 @@ int DumpFeature::dumpShard(int fd, std::string const& DBserver, std::string const& name, std::string& errorMsg) { std::string const baseUrl = "/_api/replication/dump?DBserver=" + DBserver + "&collection=" + name + "&chunkSize=" + - StringUtils::itoa(_chunkSize) + - "&ticks=false"; + StringUtils::itoa(_chunkSize) + "&ticks=false"; uint64_t fromTick = 0; uint64_t maxTick = UINT64_MAX; @@ -679,8 +687,8 @@ int DumpFeature::dumpShard(int fd, std::string const& DBserver, _stats._totalBatches++; - std::unique_ptr response(_httpClient->request( - rest::RequestType::GET, url, nullptr, 0)); + std::unique_ptr response( + _httpClient->request(rest::RequestType::GET, url, nullptr, 0)); if (response == nullptr || !response->isComplete()) { errorMsg = @@ -825,7 +833,8 @@ int DumpFeature::runClusterDump(std::string& errorMsg) { return TRI_ERROR_INTERNAL; } - uint64_t const cid = arangodb::basics::VelocyPackHelper::extractIdValue(parameters); + uint64_t const cid = + arangodb::basics::VelocyPackHelper::extractIdValue(parameters); std::string const name = arangodb::basics::VelocyPackHelper::getStringValue( parameters, "name", ""); bool const deleted = arangodb::basics::VelocyPackHelper::getBooleanValue( @@ -967,7 +976,9 @@ int DumpFeature::runClusterDump(std::string& errorMsg) { } void DumpFeature::start() { - ClientFeature* client = application_features::ApplicationServer::getFeature("Client"); + ClientFeature* client = + application_features::ApplicationServer::getFeature( + "Client"); int ret = EXIT_SUCCESS; *_result = ret; @@ -975,22 +986,26 @@ void DumpFeature::start() { try { _httpClient = client->createHttpClient(); } catch (...) { - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "cannot create server connection, giving up!"; + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << "cannot create server connection, giving up!"; FATAL_ERROR_EXIT(); } std::string dbName = client->databaseName(); - _httpClient->setLocationRewriter(static_cast(client), &rewriteLocation); + _httpClient->setLocationRewriter(static_cast(client), + &rewriteLocation); _httpClient->setUserNamePassword("/", client->username(), client->password()); std::string const versionString = _httpClient->getServerVersion(); if (!_httpClient->isConnected()) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Could not connect to endpoint '" << client->endpoint() - << "', database: '" << dbName << "', username: '" - << client->username() << "'"; - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "Error message: '" << _httpClient->getErrorMessage() << "'"; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "Could not connect to endpoint '" << client->endpoint() + << "', database: '" << dbName << "', username: '" << client->username() + << "'"; + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << "Error message: '" << _httpClient->getErrorMessage() << "'"; FATAL_ERROR_EXIT(); } @@ -1003,8 +1018,8 @@ void DumpFeature::start() { if (version.first < 3) { // we can connect to 3.x - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Error: got incompatible server version '" << versionString - << "'"; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "Error: got incompatible server version '" << versionString << "'"; if (!_force) { FATAL_ERROR_EXIT(); @@ -1015,16 +1030,19 @@ void DumpFeature::start() { if (_clusterMode) { if (_tickStart != 0 || _tickEnd != 0) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Error: cannot use tick-start or tick-end on a cluster"; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "Error: cannot use tick-start or tick-end on a cluster"; FATAL_ERROR_EXIT(); } } if (!_httpClient->isConnected()) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Lost connection to endpoint '" << client->endpoint() - << "', database: '" << dbName << "', username: '" - << client->username() << "'"; - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "Error message: '" << _httpClient->getErrorMessage() << "'"; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "Lost connection to endpoint '" << client->endpoint() + << "', database: '" << dbName << "', username: '" << client->username() + << "'"; + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << "Error message: '" << _httpClient->getErrorMessage() << "'"; FATAL_ERROR_EXIT(); } @@ -1063,7 +1081,8 @@ void DumpFeature::start() { LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "caught exception " << ex.what(); res = TRI_ERROR_INTERNAL; } catch (...) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Error: caught unknown exception"; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "Error: caught unknown exception"; res = TRI_ERROR_INTERNAL; } diff --git a/arangosh/Export/ExportFeature.cpp b/arangosh/Export/ExportFeature.cpp index 71c2d7916c..efac07e661 100644 --- a/arangosh/Export/ExportFeature.cpp +++ b/arangosh/Export/ExportFeature.cpp @@ -32,9 +32,9 @@ #include "SimpleHttpClient/SimpleHttpClient.h" #include "SimpleHttpClient/SimpleHttpResult.h" -#include -#include #include +#include +#include using namespace arangodb; using namespace arangodb::basics; @@ -67,8 +67,8 @@ ExportFeature::ExportFeature(application_features::ApplicationServer* server, startsAfter("Config"); startsAfter("Logger"); - _outputDirectory = - FileUtils::buildFilename(FileUtils::currentDirectory(), "export"); + _outputDirectory = FileUtils::buildFilename( + FileUtils::currentDirectory().result(), "export"); } void ExportFeature::collectOptions( @@ -84,7 +84,8 @@ void ExportFeature::collectOptions( options->addOption("--xgmml-label-only", "export only xgmml label", new BooleanParameter(&_xgmmlLabelOnly)); - options->addOption("--xgmml-label-attribute", "specify document attribute that will be the xgmml label", + options->addOption("--xgmml-label-attribute", + "specify document attribute that will be the xgmml label", new StringParameter(&_xgmmlLabelAttribute)); options->addOption("--output-directory", "output directory", @@ -96,12 +97,15 @@ void ExportFeature::collectOptions( options->addOption("--progress", "show progress", new BooleanParameter(&_progress)); - options->addOption("--fields", "comma separated list of fileds to export into a csv file", + options->addOption("--fields", + "comma separated list of fileds to export into a csv file", new StringParameter(&_csvFieldOptions)); - std::unordered_set exports = {"csv", "json", "jsonl", "xgmml", "xml"}; + std::unordered_set exports = {"csv", "json", "jsonl", "xgmml", + "xml"}; options->addOption( - "--type", "type of export", new DiscreteValuesParameter(&_typeExport, exports)); + "--type", "type of export", + new DiscreteValuesParameter(&_typeExport, exports)); } void ExportFeature::validateOptions( @@ -112,8 +116,9 @@ void ExportFeature::validateOptions( if (1 == n) { _outputDirectory = positionals[0]; } else if (1 < n) { - LOG_TOPIC(FATAL, Logger::CONFIG) << "expecting at most one directory, got " + - StringUtils::join(positionals, ", "); + LOG_TOPIC(FATAL, Logger::CONFIG) + << "expecting at most one directory, got " + + StringUtils::join(positionals, ", "); FATAL_ERROR_EXIT(); } @@ -126,24 +131,28 @@ void ExportFeature::validateOptions( } if (_graphName.empty() && _collections.empty()) { - LOG_TOPIC(FATAL, Logger::CONFIG) << "expecting at least one collection or one graph name"; + LOG_TOPIC(FATAL, Logger::CONFIG) + << "expecting at least one collection or one graph name"; FATAL_ERROR_EXIT(); } if (_typeExport == "xgmml" && _graphName.empty()) { - LOG_TOPIC(FATAL, Logger::CONFIG) << "expecting a graph name to dump a graph"; + LOG_TOPIC(FATAL, Logger::CONFIG) + << "expecting a graph name to dump a graph"; FATAL_ERROR_EXIT(); } - if ( (_typeExport == "json" || _typeExport == "jsonl" || _typeExport == "csv") && - _collections.empty()) { - LOG_TOPIC(FATAL, Logger::CONFIG) << "expecting at least one collection"; - FATAL_ERROR_EXIT(); + if ((_typeExport == "json" || _typeExport == "jsonl" || + _typeExport == "csv") && + _collections.empty()) { + LOG_TOPIC(FATAL, Logger::CONFIG) << "expecting at least one collection"; + FATAL_ERROR_EXIT(); } if (_typeExport == "csv") { if (_csvFieldOptions.empty()) { - LOG_TOPIC(FATAL, Logger::CONFIG) << "expecting at least one field definition"; + LOG_TOPIC(FATAL, Logger::CONFIG) + << "expecting at least one field definition"; FATAL_ERROR_EXIT(); } @@ -159,23 +168,28 @@ void ExportFeature::prepare() { isDirectory = TRI_IsDirectory(_outputDirectory.c_str()); if (isDirectory) { - std::vector files(TRI_FullTreeDirectory(_outputDirectory.c_str())); + std::vector files( + TRI_FullTreeDirectory(_outputDirectory.c_str())); // we don't care if the target directory is empty - isEmptyDirectory = (files.size() <= 1); // TODO: TRI_FullTreeDirectory always returns at least one element (""), even if directory is empty? + isEmptyDirectory = (files.size() <= 1); // TODO: TRI_FullTreeDirectory + // always returns at least one + // element (""), even if + // directory is empty? } } if (_outputDirectory.empty() || (TRI_ExistsFile(_outputDirectory.c_str()) && !isDirectory)) { - LOG_TOPIC(FATAL, Logger::SYSCALL) << "cannot write to output directory '" << _outputDirectory - << "'"; + LOG_TOPIC(FATAL, Logger::SYSCALL) << "cannot write to output directory '" + << _outputDirectory << "'"; FATAL_ERROR_EXIT(); } if (isDirectory && !isEmptyDirectory && !_overwrite) { - LOG_TOPIC(FATAL, Logger::SYSCALL) << "output directory '" << _outputDirectory - << "' already exists. use \"--overwrite true\" to " - "overwrite data in it"; + LOG_TOPIC(FATAL, Logger::SYSCALL) + << "output directory '" << _outputDirectory + << "' already exists. use \"--overwrite true\" to " + "overwrite data in it"; FATAL_ERROR_EXIT(); } @@ -186,15 +200,18 @@ void ExportFeature::prepare() { errorMessage); if (res != TRI_ERROR_NO_ERROR) { - LOG_TOPIC(ERR, Logger::SYSCALL) << "unable to create output directory '" << _outputDirectory - << "': " << errorMessage; + LOG_TOPIC(ERR, Logger::SYSCALL) << "unable to create output directory '" + << _outputDirectory + << "': " << errorMessage; FATAL_ERROR_EXIT(); } } } void ExportFeature::start() { - ClientFeature* client = application_features::ApplicationServer::getFeature("Client"); + ClientFeature* client = + application_features::ApplicationServer::getFeature( + "Client"); int ret = EXIT_SUCCESS; *_result = ret; @@ -204,7 +221,8 @@ void ExportFeature::start() { try { httpClient = client->createHttpClient(); } catch (...) { - LOG_TOPIC(FATAL, Logger::COMMUNICATION) << "cannot create server connection, giving up!"; + LOG_TOPIC(FATAL, Logger::COMMUNICATION) + << "cannot create server connection, giving up!"; FATAL_ERROR_EXIT(); } @@ -215,10 +233,12 @@ void ExportFeature::start() { httpClient->getServerVersion(); if (!httpClient->isConnected()) { - LOG_TOPIC(ERR, Logger::COMMUNICATION) << "Could not connect to endpoint '" << client->endpoint() - << "', database: '" << client->databaseName() << "', username: '" - << client->username() << "'"; - LOG_TOPIC(FATAL, Logger::COMMUNICATION) << httpClient->getErrorMessage() << "'"; + LOG_TOPIC(ERR, Logger::COMMUNICATION) + << "Could not connect to endpoint '" << client->endpoint() + << "', database: '" << client->databaseName() << "', username: '" + << client->username() << "'"; + LOG_TOPIC(FATAL, Logger::COMMUNICATION) << httpClient->getErrorMessage() + << "'"; FATAL_ERROR_EXIT(); } @@ -231,12 +251,14 @@ void ExportFeature::start() { uint64_t exportedSize = 0; - if (_typeExport == "json" || _typeExport == "jsonl" || _typeExport == "xml" || _typeExport == "csv") { + if (_typeExport == "json" || _typeExport == "jsonl" || _typeExport == "xml" || + _typeExport == "csv") { if (_collections.size()) { collectionExport(httpClient.get()); for (auto const& collection : _collections) { - std::string filePath = _outputDirectory + TRI_DIR_SEPARATOR_STR + collection + "." + _typeExport; + std::string filePath = _outputDirectory + TRI_DIR_SEPARATOR_STR + + collection + "." + _typeExport; int64_t fileSize = TRI_SizeFile(filePath.c_str()); if (0 < fileSize) { @@ -246,7 +268,8 @@ void ExportFeature::start() { } } else if (_typeExport == "xgmml" && _graphName.size()) { graphExport(httpClient.get()); - std::string filePath = _outputDirectory + TRI_DIR_SEPARATOR_STR + _graphName + "." + _typeExport; + std::string filePath = _outputDirectory + TRI_DIR_SEPARATOR_STR + + _graphName + "." + _typeExport; int64_t fileSize = TRI_SizeFile(filePath.c_str()); if (0 < fileSize) { @@ -254,7 +277,9 @@ void ExportFeature::start() { } } - std::cout << "Processed " << _collections.size() << " collection(s), wrote " << exportedSize << " byte(s), " << _httpRequestsDone << " HTTP request(s)" << std::endl; + std::cout << "Processed " << _collections.size() << " collection(s), wrote " + << exportedSize << " byte(s), " << _httpRequestsDone + << " HTTP request(s)" << std::endl; *_result = ret; } @@ -264,13 +289,14 @@ void ExportFeature::collectionExport(SimpleHttpClient* httpClient) { for (auto const& collection : _collections) { if (_progress) { - std::cout << "# Exporting collection '" << collection << "'..." << std::endl; + std::cout << "# Exporting collection '" << collection << "'..." + << std::endl; } _currentCollection = collection; - std::string fileName = - _outputDirectory + TRI_DIR_SEPARATOR_STR + collection + "." + _typeExport; + std::string fileName = _outputDirectory + TRI_DIR_SEPARATOR_STR + + collection + "." + _typeExport; // remove an existing file first if (TRI_ExistsFile(fileName.c_str())) { @@ -287,17 +313,19 @@ void ExportFeature::collectionExport(SimpleHttpClient* httpClient) { post.close(); post.close(); - std::shared_ptr parsedBody = httpCall(httpClient, url, rest::RequestType::POST, post.toJson()); + std::shared_ptr parsedBody = + httpCall(httpClient, url, rest::RequestType::POST, post.toJson()); VPackSlice body = parsedBody->slice(); - int fd = TRI_CREATE(fileName.c_str(), O_CREAT | O_EXCL | O_RDWR | TRI_O_CLOEXEC, - S_IRUSR | S_IWUSR); + int fd = + TRI_CREATE(fileName.c_str(), O_CREAT | O_EXCL | O_RDWR | TRI_O_CLOEXEC, + S_IRUSR | S_IWUSR); if (fd < 0) { errorMsg = "cannot write to file '" + fileName + "'"; THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_CANNOT_WRITE_FILE, errorMsg); } - + TRI_DEFER(TRI_CLOSE(fd)); _firstLine = true; @@ -306,8 +334,9 @@ void ExportFeature::collectionExport(SimpleHttpClient* httpClient) { writeToFile(fd, openingBracket, fileName); } else if (_typeExport == "xml") { - std::string xmlHeader = "\n" - "\n" + "\n"); writeToFile(fd, xmlHeader, fileName); @@ -315,7 +344,7 @@ void ExportFeature::collectionExport(SimpleHttpClient* httpClient) { } else if (_typeExport == "csv") { std::string firstLine = ""; bool isFirstValue = true; - for(auto const& str : _csvFields) { + for (auto const& str : _csvFields) { if (isFirstValue) { firstLine += str; isFirstValue = false; @@ -334,7 +363,8 @@ void ExportFeature::collectionExport(SimpleHttpClient* httpClient) { parsedBody = httpCall(httpClient, url, rest::RequestType::PUT); body = parsedBody->slice(); - writeCollectionBatch(fd, VPackArrayIterator(body.get("result")), fileName); + writeCollectionBatch(fd, VPackArrayIterator(body.get("result")), + fileName); } if (_typeExport == "json") { @@ -347,7 +377,8 @@ void ExportFeature::collectionExport(SimpleHttpClient* httpClient) { } } -void ExportFeature::writeCollectionBatch(int fd, VPackArrayIterator it, std::string const& fileName) { +void ExportFeature::writeCollectionBatch(int fd, VPackArrayIterator it, + std::string const& fileName) { std::string line; line.reserve(1024); @@ -375,7 +406,7 @@ void ExportFeature::writeCollectionBatch(int fd, VPackArrayIterator it, std::str line.clear(); bool isFirstValue = true; - for(auto const& key : _csvFields) { + for (auto const& key : _csvFields) { std::string value = ""; if (isFirstValue) { @@ -399,7 +430,8 @@ void ExportFeature::writeCollectionBatch(int fd, VPackArrayIterator it, std::str value = std::regex_replace(value, std::regex("\""), "\"\""); - if (value.find(",") != std::string::npos || value.find("\"\"") != std::string::npos) { + if (value.find(",") != std::string::npos || + value.find("\"\"") != std::string::npos) { value = "\"" + value; value.append("\""); } @@ -426,14 +458,17 @@ void ExportFeature::writeCollectionBatch(int fd, VPackArrayIterator it, std::str } } -void ExportFeature::writeToFile(int fd, std::string const& line, std::string const& fileName) { +void ExportFeature::writeToFile(int fd, std::string const& line, + std::string const& fileName) { if (!TRI_WritePointer(fd, line.c_str(), line.size())) { std::string errorMsg = "cannot write to file '" + fileName + "'"; THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_CANNOT_WRITE_FILE, errorMsg); } } -std::shared_ptr ExportFeature::httpCall(SimpleHttpClient* httpClient, std::string const& url, rest::RequestType requestType, std::string postBody) { +std::shared_ptr ExportFeature::httpCall( + SimpleHttpClient* httpClient, std::string const& url, + rest::RequestType requestType, std::string postBody) { std::string errorMsg; std::unique_ptr response( @@ -449,12 +484,13 @@ std::shared_ptr ExportFeature::httpCall(SimpleHttpClient* httpClie std::shared_ptr parsedBody; if (response->wasHttpError()) { - if (response->getHttpReturnCode() == 404) { if (_currentGraph.size()) { - LOG_TOPIC(FATAL, Logger::CONFIG) << "Graph '" << _currentGraph << "' not found."; + LOG_TOPIC(FATAL, Logger::CONFIG) << "Graph '" << _currentGraph + << "' not found."; } else if (_currentCollection.size()) { - LOG_TOPIC(FATAL, Logger::CONFIG) << "Collection " << _currentCollection << " not found."; + LOG_TOPIC(FATAL, Logger::CONFIG) << "Collection " << _currentCollection + << " not found."; } FATAL_ERROR_EXIT(); @@ -462,8 +498,8 @@ std::shared_ptr ExportFeature::httpCall(SimpleHttpClient* httpClie parsedBody = response->getBodyVelocyPack(); std::cout << parsedBody->toJson() << std::endl; errorMsg = "got invalid response from server: HTTP " + - StringUtils::itoa(response->getHttpReturnCode()) + ": " + - response->getHttpReturnMessage(); + StringUtils::itoa(response->getHttpReturnCode()) + ": " + + response->getHttpReturnMessage(); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, errorMsg); } } @@ -494,20 +530,23 @@ void ExportFeature::graphExport(SimpleHttpClient* httpClient) { if (_progress) { std::cout << "# Export graph '" << _graphName << "'" << std::endl; } - std::string const url = "/_api/gharial/" + StringUtils::urlEncode(_graphName); - std::shared_ptr parsedBody = httpCall(httpClient, url, rest::RequestType::GET); + std::string const url = + "/_api/gharial/" + StringUtils::urlEncode(_graphName); + std::shared_ptr parsedBody = + httpCall(httpClient, url, rest::RequestType::GET); VPackSlice body = parsedBody->slice(); std::unordered_set collections; - for(auto const& edgeDefs : VPackArrayIterator(body.get("graph").get("edgeDefinitions"))) { + for (auto const& edgeDefs : + VPackArrayIterator(body.get("graph").get("edgeDefinitions"))) { collections.insert(edgeDefs.get("collection").copyString()); - for(auto const& from : VPackArrayIterator(edgeDefs.get("from"))) { + for (auto const& from : VPackArrayIterator(edgeDefs.get("from"))) { collections.insert(from.copyString()); } - for(auto const& to : VPackArrayIterator(edgeDefs.get("to"))) { + for (auto const& to : VPackArrayIterator(edgeDefs.get("to"))) { collections.insert(to.copyString()); } } @@ -517,18 +556,23 @@ void ExportFeature::graphExport(SimpleHttpClient* httpClient) { } } else { if (_progress) { - std::cout << "# Export graph with collections " << StringUtils::join(_collections, ", ") << " as '" << _graphName << "'" << std::endl; + std::cout << "# Export graph with collections " + << StringUtils::join(_collections, ", ") << " as '" + << _graphName << "'" << std::endl; } } - std::string fileName = _outputDirectory + TRI_DIR_SEPARATOR_STR + _graphName + "." + _typeExport; + std::string fileName = + _outputDirectory + TRI_DIR_SEPARATOR_STR + _graphName + "." + _typeExport; // remove an existing file first if (TRI_ExistsFile(fileName.c_str())) { TRI_UnlinkFile(fileName.c_str()); } - int fd = TRI_CREATE(fileName.c_str(), O_CREAT | O_EXCL | O_RDWR | TRI_O_CLOEXEC, S_IRUSR | S_IWUSR); + int fd = + TRI_CREATE(fileName.c_str(), O_CREAT | O_EXCL | O_RDWR | TRI_O_CLOEXEC, + S_IRUSR | S_IWUSR); if (fd < 0) { errorMsg = "cannot write to file '" + fileName + "'"; @@ -536,7 +580,8 @@ void ExportFeature::graphExport(SimpleHttpClient* httpClient) { } TRI_DEFER(TRI_CLOSE(fd)); - std::string xmlHeader = R"( + std::string xmlHeader = + R"( for (auto const& collection : _collections) { if (_progress) { - std::cout << "# Exporting collection '" << collection << "'..." << std::endl; + std::cout << "# Exporting collection '" << collection << "'..." + << std::endl; } std::string const url = "_api/cursor"; @@ -562,7 +608,8 @@ directed="1"> post.close(); post.close(); - std::shared_ptr parsedBody = httpCall(httpClient, url, rest::RequestType::POST, post.toJson()); + std::shared_ptr parsedBody = + httpCall(httpClient, url, rest::RequestType::POST, post.toJson()); VPackSlice body = parsedBody->slice(); writeGraphBatch(fd, VPackArrayIterator(body.get("result")), fileName); @@ -579,17 +626,26 @@ directed="1"> writeToFile(fd, closingGraphTag, fileName); if (_skippedDeepNested) { - std::cout << "skipped " << _skippedDeepNested << " deep nested objects / arrays" << std::endl; + std::cout << "skipped " << _skippedDeepNested + << " deep nested objects / arrays" << std::endl; } } -void ExportFeature::writeGraphBatch(int fd, VPackArrayIterator it, std::string const& fileName) { +void ExportFeature::writeGraphBatch(int fd, VPackArrayIterator it, + std::string const& fileName) { std::string xmlTag; - for(auto const& doc : it) { + for (auto const& doc : it) { if (doc.hasKey("_from")) { - xmlTag = "\n"; + xmlTag = " \n"; writeToFile(fd, xmlTag, fileName); return; } if (!type.empty()) { - xmlTag = " \n"; + xmlTag = " \n"; writeToFile(fd, xmlTag, fileName); } else if (slice.isArray()) { - xmlTag = " \n"; + xmlTag = + " \n"; writeToFile(fd, xmlTag, fileName); for (auto const& val : VPackArrayIterator(slice)) { @@ -685,7 +752,8 @@ void ExportFeature::xgmmlWriteOneAtt(int fd, std::string const& fileName, VPackS writeToFile(fd, xmlTag, fileName); } else if (slice.isObject()) { - xmlTag = " \n"; + xmlTag = + " \n"; writeToFile(fd, xmlTag, fileName); for (auto const& it : VPackObjectIterator(slice)) { diff --git a/arangosh/Restore/RestoreFeature.cpp b/arangosh/Restore/RestoreFeature.cpp index a03c43869e..de7fbb39b6 100644 --- a/arangosh/Restore/RestoreFeature.cpp +++ b/arangosh/Restore/RestoreFeature.cpp @@ -68,14 +68,14 @@ RestoreFeature::RestoreFeature(application_features::ApplicationServer* server, _defaultNumberOfShards(1), _defaultReplicationFactor(1), _result(result), - _stats{ 0, 0, 0 } { + _stats{0, 0, 0} { requiresElevatedPrivileges(false); setOptional(false); startsAfter("Client"); startsAfter("Logger"); _inputDirectory = - FileUtils::buildFilename(FileUtils::currentDirectory(), "dump"); + FileUtils::buildFilename(FileUtils::currentDirectory().result(), "dump"); } void RestoreFeature::collectOptions( @@ -112,8 +112,7 @@ void RestoreFeature::collectOptions( options->addOption("--overwrite", "overwrite collections if they exist", new BooleanParameter(&_overwrite)); - options->addOption("--recycle-ids", - "recycle collection ids from dump", + options->addOption("--recycle-ids", "recycle collection ids from dump", new BooleanParameter(&_recycleIds)); options->addOption("--default-number-of-shards", @@ -137,8 +136,9 @@ void RestoreFeature::validateOptions( if (1 == n) { _inputDirectory = positionals[0]; } else if (1 < n) { - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "expecting at most one directory, got " + - StringUtils::join(positionals, ", "); + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << "expecting at most one directory, got " + + StringUtils::join(positionals, ", "); FATAL_ERROR_EXIT(); } @@ -162,7 +162,8 @@ void RestoreFeature::prepare() { // ............................................................................. if (_inputDirectory == "" || !TRI_IsDirectory(_inputDirectory.c_str())) { - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "input directory '" << _inputDirectory << "' does not exist"; + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << "input directory '" << _inputDirectory << "' does not exist"; FATAL_ERROR_EXIT(); } @@ -188,9 +189,8 @@ int RestoreFeature::tryCreateDatabase(ClientFeature* client, std::string const body = builder.slice().toJson(); - std::unique_ptr response( - _httpClient->request(rest::RequestType::POST, "/_api/database", - body.c_str(), body.size())); + std::unique_ptr response(_httpClient->request( + rest::RequestType::POST, "/_api/database", body.c_str(), body.size())); if (response == nullptr || !response->isComplete()) { return TRI_ERROR_INTERNAL; @@ -202,7 +202,7 @@ int RestoreFeature::tryCreateDatabase(ClientFeature* client, returnCode == static_cast(rest::ResponseCode::CREATED)) { // all ok return TRI_ERROR_NO_ERROR; - } + } if (returnCode == static_cast(rest::ResponseCode::UNAUTHORIZED) || returnCode == static_cast(rest::ResponseCode::FORBIDDEN)) { // invalid authorization @@ -238,14 +238,14 @@ int RestoreFeature::sendRestoreCollection(VPackSlice const& slice, << _defaultNumberOfShards << std::endl; url += "&numberOfShards=" + std::to_string(_defaultNumberOfShards); } - if (!slice.hasKey(std::vector({"parameters", "replicationFactor"}))) { + if (!slice.hasKey( + std::vector({"parameters", "replicationFactor"}))) { // No replication factor given, so take the default: std::cerr << "# no replication information specified for collection '" << name << "', using default replication factor " << _defaultReplicationFactor << std::endl; url += "&replicationFactor=" + std::to_string(_defaultReplicationFactor); } - } std::string const body = slice.toJson(); @@ -312,8 +312,8 @@ int RestoreFeature::sendRestoreData(std::string const& cname, (_recycleIds ? "true" : "false") + "&force=" + (_force ? "true" : "false"); - std::unique_ptr response(_httpClient->request( - rest::RequestType::PUT, url, buffer, bufferSize)); + std::unique_ptr response( + _httpClient->request(rest::RequestType::PUT, url, buffer, bufferSize)); if (response == nullptr || !response->isComplete()) { errorMsg = @@ -344,7 +344,7 @@ static bool SortCollections(VPackSlice const& l, VPackSlice const& r) { // We first have to create collections defining the distribution. VPackSlice leftDist = left.get("distributeShardsLike"); VPackSlice rightDist = right.get("distributeShardsLike"); - + if (leftDist.isNone() && !rightDist.isNone()) { return true; } @@ -471,7 +471,7 @@ int RestoreFeature::processInputDirectory(std::string& errorMsg) { } std::sort(collections.begin(), collections.end(), SortCollections); - + StringBuffer buffer(TRI_UNKNOWN_MEM_ZONE); // step2: run the actual import @@ -654,7 +654,9 @@ int RestoreFeature::processInputDirectory(std::string& errorMsg) { } void RestoreFeature::start() { - ClientFeature* client = application_features::ApplicationServer::getFeature("Client"); + ClientFeature* client = + application_features::ApplicationServer::getFeature( + "Client"); int ret = EXIT_SUCCESS; *_result = ret; @@ -662,13 +664,15 @@ void RestoreFeature::start() { try { _httpClient = client->createHttpClient(); } catch (...) { - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "cannot create server connection, giving up!"; + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << "cannot create server connection, giving up!"; FATAL_ERROR_EXIT(); } std::string dbName = client->databaseName(); - _httpClient->setLocationRewriter(static_cast(client), &rewriteLocation); + _httpClient->setLocationRewriter(static_cast(client), + &rewriteLocation); _httpClient->setUserNamePassword("/", client->username(), client->password()); int err = TRI_ERROR_NO_ERROR; @@ -683,8 +687,10 @@ void RestoreFeature::start() { int res = tryCreateDatabase(client, dbName); if (res != TRI_ERROR_NO_ERROR) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Could not create database '" << dbName << "'"; - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << _httpClient->getErrorMessage() << "'"; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Could not create database '" + << dbName << "'"; + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << _httpClient->getErrorMessage() << "'"; FATAL_ERROR_EXIT(); } @@ -696,9 +702,11 @@ void RestoreFeature::start() { } if (!_httpClient->isConnected()) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Could not connect to endpoint " - << _httpClient->getEndpointSpecification(); - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << _httpClient->getErrorMessage() << "'"; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "Could not connect to endpoint " + << _httpClient->getEndpointSpecification(); + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << _httpClient->getErrorMessage() + << "'"; FATAL_ERROR_EXIT(); } @@ -710,7 +718,8 @@ void RestoreFeature::start() { if (version.first < 3) { // we can connect to 3.x - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "got incompatible server version '" << versionString << "'"; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "got incompatible server version '" << versionString << "'"; if (!_force) { LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "giving up!"; @@ -735,7 +744,8 @@ void RestoreFeature::start() { LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "caught exception " << ex.what(); res = TRI_ERROR_INTERNAL; } catch (...) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Error: caught unknown exception"; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "Error: caught unknown exception"; res = TRI_ERROR_INTERNAL; } @@ -759,6 +769,6 @@ void RestoreFeature::start() { << std::endl; } } - + *_result = ret; } diff --git a/arangosh/Shell/V8ShellFeature.cpp b/arangosh/Shell/V8ShellFeature.cpp index f475104552..bf77c10f5b 100644 --- a/arangosh/Shell/V8ShellFeature.cpp +++ b/arangosh/Shell/V8ShellFeature.cpp @@ -894,7 +894,7 @@ void V8ShellFeature::initGlobals() { } if (_currentModuleDirectory) { - modules += sep + FileUtils::currentDirectory(); + modules += sep + FileUtils::currentDirectory().result(); } // we take the last entry in _startupDirectory as global path; diff --git a/lib/ApplicationFeatures/ConfigFeature.cpp b/lib/ApplicationFeatures/ConfigFeature.cpp index 535b718c50..79d734c9e9 100644 --- a/lib/ApplicationFeatures/ConfigFeature.cpp +++ b/lib/ApplicationFeatures/ConfigFeature.cpp @@ -148,9 +148,9 @@ void ConfigFeature::loadConfigFile(std::shared_ptr options, locations.emplace_back(location); } - locations.emplace_back(FileUtils::currentDirectory()); - locations.emplace_back(FileUtils::buildFilename(FileUtils::currentDirectory(), - "etc", "relative")); + std::string current = FileUtils::currentDirectory().result(); + locations.emplace_back(current); + locations.emplace_back(FileUtils::buildFilename(current, "etc", "relative")); locations.emplace_back( FileUtils::buildFilename(FileUtils::homeDirectory(), ".arangodb")); locations.emplace_back(FileUtils::configDirectory(binaryPath)); diff --git a/lib/ApplicationFeatures/DaemonFeature.cpp b/lib/ApplicationFeatures/DaemonFeature.cpp index dafe4d18d2..7d1798b2aa 100644 --- a/lib/ApplicationFeatures/DaemonFeature.cpp +++ b/lib/ApplicationFeatures/DaemonFeature.cpp @@ -77,8 +77,7 @@ void DaemonFeature::validateOptions(std::shared_ptr options) { logger->setBackgrounded(true); // make the pid filename absolute - int err = 0; - std::string currentDir = FileUtils::currentDirectory(&err); + std::string currentDir = FileUtils::currentDirectory().result(); char* absoluteFile = TRI_GetAbsolutePath(_pidFile.c_str(), currentDir.c_str()); @@ -235,14 +234,16 @@ int DaemonFeature::forkProcess() { } // store current working directory - int err = 0; - _current = FileUtils::currentDirectory(&err); + FileResultString cwd = FileUtils::currentDirectory(); - if (err != 0) { - LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "cannot get current directory"; + if (!cwd.ok()) { + LOG_TOPIC(FATAL, arangodb::Logger::FIXME) + << "cannot get current directory: " << cwd.errorMessage(); FATAL_ERROR_EXIT(); } + _current = cwd.result(); + // change the current working directory if (!_workingDirectory.empty()) { FileResult res = FileUtils::changeDirectory(_workingDirectory); diff --git a/lib/Basics/FileResult.h b/lib/Basics/FileResult.h index d817bd0696..69ecfc0ae0 100644 --- a/lib/Basics/FileResult.h +++ b/lib/Basics/FileResult.h @@ -28,15 +28,16 @@ namespace arangodb { class FileResult : public Result { public: - explicit FileResult(bool state); - FileResult(bool state, int sysErrorNumber); + FileResult() : Result(), _sysErrorNumber(0) {} + + explicit FileResult(int sysErrorNumber) + : Result(TRI_ERROR_SYS_ERROR, strerror(sysErrorNumber)), + _sysErrorNumber(sysErrorNumber) {} public: - bool state() const { return _state; } int sysErrorNumber() const { return _sysErrorNumber; } - private: - bool const _state; + protected: int const _sysErrorNumber; }; } diff --git a/lib/Basics/FileResult.cpp b/lib/Basics/FileResultString.h similarity index 61% rename from lib/Basics/FileResult.cpp rename to lib/Basics/FileResultString.h index 78f51f662d..64bbc36542 100644 --- a/lib/Basics/FileResult.cpp +++ b/lib/Basics/FileResultString.h @@ -20,13 +20,28 @@ /// @author Dr. Frank Celler //////////////////////////////////////////////////////////////////////////////// -#include "FileResult.h" +#ifndef ARANGODB_BASICS_FILE_RESULT_STRING_H +#define ARANGODB_BASICS_FILE_RESULT_STRING_H 1 + +#include "Basics/Result.h" namespace arangodb { -FileResult::FileResult(bool state) - : Result(), _state(state), _sysErrorNumber(0) {} +class FileResultString : public FileResult { + public: + FileResultString(std::string result) : FileResult(), _result(result) {} -FileResult::FileResult(bool state, int sysErrorNumber) - : Result(TRI_ERROR_SYS_ERROR, strerror(sysErrorNumber)), - _state(state), _sysErrorNumber(sysErrorNumber) {} + FileResultString(int sysErrorNumber, std::string result) + : FileResult(sysErrorNumber), _result(result) {} + + FileResultString(int sysErrorNumber) + : FileResult(sysErrorNumber), _result() {} + + public: + std::string const& result() const { return _result; } + + protected: + std::string const _result; +}; } + +#endif diff --git a/lib/Basics/FileUtils.cpp b/lib/Basics/FileUtils.cpp index be670a84fd..a3310d22be 100644 --- a/lib/Basics/FileUtils.cpp +++ b/lib/Basics/FileUtils.cpp @@ -34,8 +34,8 @@ #include "Basics/Exceptions.h" #include "Basics/StringBuffer.h" #include "Basics/files.h" -#include "Logger/Logger.h" #include "Basics/tri-strings.h" +#include "Logger/Logger.h" #if defined(_WIN32) && defined(_MSC_VER) @@ -91,7 +91,8 @@ std::string buildFilename(char const* path, char const* name) { } if (!result.empty() && *name == TRI_DIR_SEPARATOR_CHAR) { - // skip initial forward slash in name to avoid having two forward slashes in result + // skip initial forward slash in name to avoid having two forward slashes in + // result result.append(name + 1); } else { result.append(name); @@ -109,7 +110,8 @@ std::string buildFilename(std::string const& path, std::string const& name) { } if (!result.empty() && !name.empty() && name[0] == TRI_DIR_SEPARATOR_CHAR) { - // skip initial forward slash in name to avoid having two forward slashes in result + // skip initial forward slash in name to avoid having two forward slashes in + // result result.append(name.c_str() + 1, name.size() - 1); } else { result.append(name); @@ -119,7 +121,7 @@ std::string buildFilename(std::string const& path, std::string const& name) { return result; } -void throwFileReadError(int fd, std::string const& filename) { +static void throwFileReadError(int fd, std::string const& filename) { TRI_set_errno(TRI_ERROR_SYS_ERROR); int res = TRI_errno(); @@ -134,21 +136,6 @@ void throwFileReadError(int fd, std::string const& filename) { THROW_ARANGO_EXCEPTION(TRI_ERROR_SYS_ERROR); } -void throwFileWriteError(int fd, std::string const& filename) { - TRI_set_errno(TRI_ERROR_SYS_ERROR); - int res = TRI_errno(); - - if (fd >= 0) { - TRI_CLOSE(fd); - } - - std::string message("write failed for file '" + filename + "': " + - strerror(res)); - LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "" << message; - - THROW_ARANGO_EXCEPTION(TRI_ERROR_SYS_ERROR); -} - std::string slurp(std::string const& filename) { int fd = TRI_OPEN(filename.c_str(), O_RDONLY | TRI_O_CLOEXEC); @@ -212,6 +199,21 @@ void slurp(std::string const& filename, StringBuffer& result) { TRI_CLOSE(fd); } +static void throwFileWriteError(int fd, std::string const& filename) { + TRI_set_errno(TRI_ERROR_SYS_ERROR); + int res = TRI_errno(); + + if (fd >= 0) { + TRI_CLOSE(fd); + } + + std::string message("write failed for file '" + filename + "': " + + strerror(res)); + LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "" << message; + + THROW_ARANGO_EXCEPTION(TRI_ERROR_SYS_ERROR); +} + void spit(std::string const& filename, char const* ptr, size_t len) { int fd = TRI_CREATE(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | TRI_O_CLOEXEC, @@ -356,11 +358,10 @@ bool copyRecursive(std::string const& source, std::string const& target, bool copyDirectoryRecursive(std::string const& source, std::string const& target, std::string& error) { - bool rc = true; - + auto isSubDirectory = [](std::string const& name) -> bool { - return isDirectory(name); + return isDirectory(name); }; #ifdef TRI_HAVE_WIN32_LIST_FILES struct _finddata_t oneItem; @@ -386,7 +387,8 @@ bool copyDirectoryRecursive(std::string const& source, struct dirent* oneItem = nullptr; // do not use readdir_r() here anymore as it is not safe and deprecated - // in newer versions of libc: http://man7.org/linux/man-pages/man3/readdir_r.3.html + // in newer versions of libc: + // http://man7.org/linux/man-pages/man3/readdir_r.3.html // the man page recommends to use plain readdir() because it can be expected // to be thread-safe in reality, and newer versions of POSIX may require its // thread-safety formally, and in addition obsolete readdir_r() altogether @@ -561,17 +563,13 @@ FileResult changeDirectory(std::string const& path) { int res = TRI_CHDIR(path.c_str()); if (res == 0) { - return FileResult(true); + return FileResult(); } else { - return FileResult(false, errno); + return FileResult(errno); } } -std::string currentDirectory(int* errorNumber) { - if (errorNumber != 0) { - *errorNumber = 0; - } - +FileResultString currentDirectory() { size_t len = 1000; char* current = new char[len]; @@ -583,19 +581,13 @@ std::string currentDirectory(int* errorNumber) { } else { delete[] current; - if (errorNumber != 0) { - *errorNumber = errno; - } - - return "."; + return FileResultString(errno, "."); } } std::string result = current; - delete[] current; - - return result; + return FileResultString(result); } std::string homeDirectory() { @@ -610,7 +602,7 @@ std::string configDirectory(char const* binaryPath) { char* dir = TRI_LocateConfigDirectory(binaryPath); if (dir == nullptr) { - return currentDirectory(); + return currentDirectory().result(); } std::string result = dir; @@ -631,15 +623,12 @@ std::string dirname(std::string const& name) { return base; } -void makePathAbsolute(std::string &path) { - int err = 0; - - std::string cwd = FileUtils::currentDirectory(&err); - char * p = TRI_GetAbsolutePath(path.c_str(), cwd.c_str()); +void makePathAbsolute(std::string& path) { + std::string cwd = FileUtils::currentDirectory().result(); + char* p = TRI_GetAbsolutePath(path.c_str(), cwd.c_str()); path = p; TRI_FreeString(TRI_CORE_MEM_ZONE, p); } - } } } diff --git a/lib/Basics/FileUtils.h b/lib/Basics/FileUtils.h index aed0e98ac4..b87803add3 100644 --- a/lib/Basics/FileUtils.h +++ b/lib/Basics/FileUtils.h @@ -26,8 +26,9 @@ #include "Basics/Common.h" -#include "Basics/files.h" #include "Basics/FileResult.h" +#include "Basics/FileResultString.h" +#include "Basics/files.h" namespace arangodb { namespace basics { @@ -55,12 +56,6 @@ inline std::string buildFilename(std::string path, std::string name, Args... arg return buildFilename(buildFilename(path, name), args...); } -// throws a read error -void throwFileReadError(int fd, std::string const& filename); - -// throws a write error -void throwFileWriteError(int fd, std::string const& filename); - // reads file into string std::string slurp(std::string const& filename); void slurp(std::string const& filename, StringBuffer&); @@ -72,6 +67,8 @@ void spit(std::string const& filename, StringBuffer const& content); // returns true if a file could be removed bool remove(std::string const& fileName, int* errorNumber = 0); + +// returns true if a file could be renamed bool rename(std::string const& oldName, std::string const& newName, int* errorNumber = 0); @@ -112,7 +109,7 @@ std::string stripExtension(std::string const& path, FileResult changeDirectory(std::string const& path); // returns the current directory -std::string currentDirectory(int* errorNumber = 0); +FileResultString currentDirectory(); // returns the home directory std::string homeDirectory(); diff --git a/lib/Basics/Result.h b/lib/Basics/Result.h index 49c0497d9a..0f40845b17 100644 --- a/lib/Basics/Result.h +++ b/lib/Basics/Result.h @@ -29,20 +29,26 @@ namespace arangodb { class Result { public: Result() : _errorNumber(TRI_ERROR_NO_ERROR) {} - Result(int errorNumber, std::string const& errorMessage) + + Result(int errorNumber) + : _errorNumber(errorNumber), + _errorMessage(TRI_errno_string(errorNumber)) {} + + Result(int errorNumber, std::string const& errorMessage) : _errorNumber(errorNumber), _errorMessage(errorMessage) {} - Result(int errorNumber, std::string&& errorMessage) + + Result(int errorNumber, std::string&& errorMessage) : _errorNumber(errorNumber), _errorMessage(std::move(errorMessage)) {} virtual ~Result() {} public: - // the default implementations are const, but subclasses might - // really do more work to compute - for example - the error - // string. + bool ok() const { return _errorNumber == TRI_ERROR_NO_ERROR; } + int errorNumber() const { return _errorNumber; } + + // the default implementations is const, but sub-classes might + // really do more work to compute. - virtual bool ok() { return _errorNumber == TRI_ERROR_NO_ERROR; } - virtual int errorNumber() { return _errorNumber; } virtual std::string errorMessage() { return _errorMessage; } protected: diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 7ce774c2dc..dd81cec000 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -130,7 +130,6 @@ add_library(${LIB_ARANGO} STATIC Basics/ConditionVariable.cpp Basics/DataProtector.cpp Basics/Exceptions.cpp - Basics/FileResult.cpp Basics/FileUtils.cpp Basics/HybridLogicalClock.cpp Basics/LocalTaskQueue.cpp diff --git a/lib/V8/v8-utils.cpp b/lib/V8/v8-utils.cpp index 7dd0f5e789..729867ce6f 100644 --- a/lib/V8/v8-utils.cpp +++ b/lib/V8/v8-utils.cpp @@ -27,9 +27,9 @@ #include "Basics/win-utils.h" #endif +#include #include #include -#include #include "3rdParty/valgrind/valgrind.h" #include "unicode/normalizer2.h" @@ -112,7 +112,8 @@ static void CreateErrorObject(v8::Isolate* isolate, int errorNumber, std::string const& message) noexcept { try { if (errorNumber == TRI_ERROR_OUT_OF_MEMORY) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "encountered out-of-memory error"; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "encountered out-of-memory error"; } v8::Handle errorMessage = TRI_V8_STD_STRING(message); @@ -137,7 +138,7 @@ static void CreateErrorObject(v8::Isolate* isolate, int errorNumber, } errorObject->Set(TRI_V8_ASCII_STRING("errorNum"), - v8::Number::New(isolate, errorNumber)); + v8::Number::New(isolate, errorNumber)); errorObject->Set(TRI_V8_ASCII_STRING("errorMessage"), errorMessage); TRI_GET_GLOBALS(); @@ -169,8 +170,9 @@ static bool LoadJavaScriptFile(v8::Isolate* isolate, char const* filename, char* content = TRI_SlurpFile(TRI_UNKNOWN_MEM_ZONE, filename, &length); if (content == nullptr) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "cannot load java script file '" << filename - << "': " << TRI_last_error(); + LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "cannot load java script file '" + << filename + << "': " << TRI_last_error(); return false; } @@ -205,8 +207,9 @@ static bool LoadJavaScriptFile(v8::Isolate* isolate, char const* filename, } if (content == nullptr) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "cannot load java script file '" << filename - << "': " << TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY); + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "cannot load java script file '" << filename + << "': " << TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY); return false; } @@ -227,8 +230,9 @@ static bool LoadJavaScriptFile(v8::Isolate* isolate, char const* filename, // compilation failed, print errors that happened during compilation if (script.IsEmpty()) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "cannot load java script file '" << filename - << "': compilation failed."; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "cannot load java script file '" + << filename + << "': compilation failed."; return false; } @@ -246,7 +250,8 @@ static bool LoadJavaScriptFile(v8::Isolate* isolate, char const* filename, } } - LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "loaded java script file: '" << filename << "'"; + LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "loaded java script file: '" + << filename << "'"; return true; } @@ -260,7 +265,8 @@ static bool LoadJavaScriptDirectory(v8::Isolate* isolate, char const* path, v8::HandleScope scope(isolate); bool result; - LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "loading JavaScript directory: '" << path << "'"; + LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "loading JavaScript directory: '" + << path << "'"; std::vector files = TRI_FilesDirectory(path); @@ -412,10 +418,13 @@ static void JS_Parse(v8::FunctionCallbackInfo const& args) { // compilation failed, we have caught an exception if (tryCatch.HasCaught()) { if (tryCatch.CanContinue()) { - v8::Local exceptionObj = tryCatch.Exception().As(); + v8::Local exceptionObj = + tryCatch.Exception().As(); v8::Handle message = tryCatch.Message(); - exceptionObj->Set(TRI_V8_ASCII_STRING("lineNumber"), v8::Number::New(isolate, message->GetLineNumber())); - exceptionObj->Set(TRI_V8_ASCII_STRING("columnNumber"), v8::Number::New(isolate, message->GetStartColumn())); + exceptionObj->Set(TRI_V8_ASCII_STRING("lineNumber"), + v8::Number::New(isolate, message->GetLineNumber())); + exceptionObj->Set(TRI_V8_ASCII_STRING("columnNumber"), + v8::Number::New(isolate, message->GetStartColumn())); exceptionObj->Set(TRI_V8_ASCII_STRING("fileName"), filename->ToString()); tryCatch.ReThrow(); return; @@ -472,19 +481,21 @@ static void JS_ParseFile(v8::FunctionCallbackInfo const& args) { } v8::TryCatch tryCatch; - v8::Handle script = - v8::Script::Compile(TRI_V8_PAIR_STRING(content, (int)length), - args[0]->ToString()); + v8::Handle script = v8::Script::Compile( + TRI_V8_PAIR_STRING(content, (int)length), args[0]->ToString()); TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, content); // compilation failed, we have caught an exception if (tryCatch.HasCaught()) { if (tryCatch.CanContinue()) { - v8::Local exceptionObj = tryCatch.Exception().As(); + v8::Local exceptionObj = + tryCatch.Exception().As(); v8::Handle message = tryCatch.Message(); - exceptionObj->Set(TRI_V8_ASCII_STRING("lineNumber"), v8::Number::New(isolate, message->GetLineNumber())); - exceptionObj->Set(TRI_V8_ASCII_STRING("columnNumber"), v8::Number::New(isolate, message->GetStartColumn())); + exceptionObj->Set(TRI_V8_ASCII_STRING("lineNumber"), + v8::Number::New(isolate, message->GetLineNumber())); + exceptionObj->Set(TRI_V8_ASCII_STRING("columnNumber"), + v8::Number::New(isolate, message->GetStartColumn())); exceptionObj->Set(TRI_V8_ASCII_STRING("fileName"), args[0]); tryCatch.ReThrow(); return; @@ -659,7 +670,7 @@ void JS_Download(v8::FunctionCallbackInfo const& args) { if (options.IsEmpty()) { TRI_V8_THROW_EXCEPTION_USAGE(signature); } - + // ssl protocol if (options->Has(TRI_V8_ASCII_STRING("sslProtocol"))) { if (sslProtocol >= SSL_LAST) { @@ -667,14 +678,15 @@ void JS_Download(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "invalid option value for sslProtocol"); } - - sslProtocol = TRI_ObjectToUInt64(options->Get(TRI_V8_ASCII_STRING("sslProtocol")), false); + + sslProtocol = TRI_ObjectToUInt64( + options->Get(TRI_V8_ASCII_STRING("sslProtocol")), false); } // method if (options->Has(TRI_V8_ASCII_STRING("method"))) { - std::string methodString = - TRI_ObjectToString(isolate, options->Get(TRI_V8_ASCII_STRING("method"))); + std::string methodString = TRI_ObjectToString( + isolate, options->Get(TRI_V8_ASCII_STRING("method"))); method = HttpRequest::translateMethod(methodString); } @@ -819,8 +831,9 @@ void JS_Download(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_SYNTAX_ERROR("unsupported URL specified"); } - LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "downloading file. endpoint: " << endpoint - << ", relative URL: " << url; + LOG_TOPIC(TRACE, arangodb::Logger::FIXME) + << "downloading file. endpoint: " << endpoint + << ", relative URL: " << url; std::unique_ptr ep(Endpoint::clientFactory(endpoint)); @@ -829,7 +842,8 @@ void JS_Download(v8::FunctionCallbackInfo const& args) { } std::unique_ptr connection( - GeneralClientConnection::factory(ep.get(), timeout, timeout, 3, sslProtocol)); + GeneralClientConnection::factory(ep.get(), timeout, timeout, 3, + sslProtocol)); if (connection == nullptr) { TRI_V8_THROW_EXCEPTION_MEMORY(); @@ -993,8 +1007,8 @@ static void JS_Execute(v8::FunctionCallbackInfo const& args) { TRI_Utf8ValueNFC keyName(TRI_UNKNOWN_MEM_ZONE, key); if (*keyName != nullptr) { - LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "copying key '" << *keyName - << "' from sandbox to context"; + LOG_TOPIC(TRACE, arangodb::Logger::FIXME) + << "copying key '" << *keyName << "' from sandbox to context"; } } @@ -1023,11 +1037,15 @@ static void JS_Execute(v8::FunctionCallbackInfo const& args) { } if (tryCatch.CanContinue()) { - v8::Local exceptionObj = tryCatch.Exception().As(); + v8::Local exceptionObj = + tryCatch.Exception().As(); v8::Handle message = tryCatch.Message(); - exceptionObj->Set(TRI_V8_ASCII_STRING("lineNumber"), v8::Number::New(isolate, message->GetLineNumber())); - exceptionObj->Set(TRI_V8_ASCII_STRING("columnNumber"), v8::Number::New(isolate, message->GetStartColumn())); - exceptionObj->Set(TRI_V8_ASCII_STRING("fileName"), filename->ToString()); + exceptionObj->Set(TRI_V8_ASCII_STRING("lineNumber"), + v8::Number::New(isolate, message->GetLineNumber())); + exceptionObj->Set(TRI_V8_ASCII_STRING("columnNumber"), + v8::Number::New(isolate, message->GetStartColumn())); + exceptionObj->Set(TRI_V8_ASCII_STRING("fileName"), + filename->ToString()); tryCatch.ReThrow(); return; } else { @@ -1071,8 +1089,8 @@ static void JS_Execute(v8::FunctionCallbackInfo const& args) { TRI_Utf8ValueNFC keyName(TRI_UNKNOWN_MEM_ZONE, key); if (*keyName != nullptr) { - LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "copying key '" << *keyName - << "' from context to sandbox"; + LOG_TOPIC(TRACE, arangodb::Logger::FIXME) + << "copying key '" << *keyName << "' from context to sandbox"; } } @@ -1361,20 +1379,22 @@ static void JS_MakeAbsolute(v8::FunctionCallbackInfo const& args) { TRI_V8_THROW_TYPE_ERROR(" must be a string"); } - int err = 0; - std::string cwd = arangodb::basics::FileUtils::currentDirectory(&err); - if (0 != err) { - TRI_V8_THROW_EXCEPTION_MESSAGE(err, "cannot get current working directory"); + FileResultString cwd = FileUtils::currentDirectory(); + + if (!cwd.ok()) { + TRI_V8_THROW_EXCEPTION_MESSAGE( + cwd.sysErrorNumber(), + "cannot get current working directory: " + cwd.errorMessage()); } - char* abs = TRI_GetAbsolutePath(*name, cwd.c_str()); + char* abs = TRI_GetAbsolutePath(*name, cwd.result().c_str()); v8::Handle res; - if (0 != abs) { + if (nullptr != abs) { res = TRI_V8_STRING(abs); TRI_Free(TRI_UNKNOWN_MEM_ZONE, abs); } else { - res = TRI_V8_STD_STRING(cwd); + res = TRI_V8_STD_STRING(cwd.result()); } // return result @@ -3183,7 +3203,7 @@ static void JS_PBKDF2HS1(v8::FunctionCallbackInfo const& args) { std::string result = SslInterface::sslPBKDF2HS1(salt.c_str(), salt.size(), password.c_str(), - password.size(), iterations, keyLength); + password.size(), iterations, keyLength); TRI_V8_RETURN_STD_STRING(result); TRI_V8_TRY_CATCH_END } @@ -3205,7 +3225,8 @@ static void JS_PBKDF2(v8::FunctionCallbackInfo const& args) { if (args.Length() < 4 || !args[0]->IsString() || !args[1]->IsString() || !args[2]->IsNumber() || !args[3]->IsNumber()) { TRI_V8_THROW_EXCEPTION_USAGE( - "PBKDF2_SHA(, , , , )"); + "PBKDF2_SHA(, , , , " + ")"); } SslInterface::Algorithm al = SslInterface::Algorithm::ALGORITHM_SHA1; @@ -3650,7 +3671,8 @@ static void JS_KillExternal(v8::FunctionCallbackInfo const& args) { // extract the arguments if (args.Length() < 1 || args.Length() > 2) { - TRI_V8_THROW_EXCEPTION_USAGE("killExternal(, )"); + TRI_V8_THROW_EXCEPTION_USAGE( + "killExternal(, )"); } int signal = SIGTERM; if (args.Length() == 2) { @@ -3812,11 +3834,13 @@ static void JS_V8ToVPack(v8::FunctionCallbackInfo const& args) { } VPackSlice slice = builder.slice(); - - V8Buffer* buffer = V8Buffer::New(isolate, slice.startAs(), slice.byteSize()); - v8::Local bufferObject = v8::Local::New(isolate, buffer->_handle); + + V8Buffer* buffer = + V8Buffer::New(isolate, slice.startAs(), slice.byteSize()); + v8::Local bufferObject = + v8::Local::New(isolate, buffer->_handle); TRI_V8_RETURN(bufferObject); - + TRI_V8_RETURN_FALSE(); TRI_V8_TRY_CATCH_END } @@ -3834,9 +3858,9 @@ static void JS_VPackToV8(v8::FunctionCallbackInfo const& args) { if (args[0]->IsString() || args[0]->IsStringObject()) { // supplied argument is a string std::string const value = TRI_ObjectToString(isolate, args[0]); - + VPackValidator validator; - validator.validate(value.c_str(), value.size(), false); + validator.validate(value.c_str(), value.size(), false); VPackSlice slice(value.c_str()); v8::Handle result = TRI_VPackToV8(isolate, slice); @@ -3847,16 +3871,17 @@ static void JS_VPackToV8(v8::FunctionCallbackInfo const& args) { size_t size = V8Buffer::length(args[0].As()); VPackValidator validator; - validator.validate(data, size, false); + validator.validate(data, size, false); VPackSlice slice(data); v8::Handle result = TRI_VPackToV8(isolate, slice); TRI_V8_RETURN(result); } else { - TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, "invalid argument type for VPACK_TO_V8()"); + TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, + "invalid argument type for VPACK_TO_V8()"); } - + TRI_V8_RETURN_FALSE(); TRI_V8_TRY_CATCH_END } @@ -4092,7 +4117,8 @@ void TRI_LogV8Exception(v8::Isolate* isolate, v8::TryCatch* tryCatch) { if (exceptionString == nullptr) { LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "JavaScript exception"; } else { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "JavaScript exception: " << exceptionString; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "JavaScript exception: " + << exceptionString; } } else { TRI_Utf8ValueNFC filename(TRI_UNKNOWN_MEM_ZONE, @@ -4108,16 +4134,18 @@ void TRI_LogV8Exception(v8::Isolate* isolate, v8::TryCatch* tryCatch) { if (exceptionString == nullptr) { LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "JavaScript exception"; } else { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "JavaScript exception: " << exceptionString; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "JavaScript exception: " + << exceptionString; } } else { if (exceptionString == nullptr) { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "JavaScript exception in file '" << filenameString - << "' at " << linenum << "," << start; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "JavaScript exception in file '" << filenameString << "' at " + << linenum << "," << start; } else { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "JavaScript exception in file '" << filenameString - << "' at " << linenum << "," << start << ": " - << exceptionString; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "JavaScript exception in file '" << filenameString << "' at " + << linenum << "," << start << ": " << exceptionString; } } @@ -4225,7 +4253,8 @@ v8::Handle TRI_ExecuteJavaScriptString( } } } else { - LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "no output function defined in Javascript context"; + LOG_TOPIC(ERR, arangodb::Logger::FIXME) + << "no output function defined in Javascript context"; } } @@ -4590,8 +4619,8 @@ void TRI_InitV8Utils(v8::Isolate* isolate, v8::Handle context, TRI_V8_ASCII_STRING("SYS_PARSE"), JS_Parse); TRI_AddGlobalFunctionVocbase( isolate, context, TRI_V8_ASCII_STRING("SYS_PARSE_FILE"), JS_ParseFile); - TRI_AddGlobalFunctionVocbase(isolate, context, - TRI_V8_ASCII_STRING("SYS_PBKDF2HS1"), JS_PBKDF2HS1); + TRI_AddGlobalFunctionVocbase( + isolate, context, TRI_V8_ASCII_STRING("SYS_PBKDF2HS1"), JS_PBKDF2HS1); TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("SYS_PBKDF2"), JS_PBKDF2); TRI_AddGlobalFunctionVocbase(isolate, context, @@ -4636,10 +4665,10 @@ void TRI_InitV8Utils(v8::Isolate* isolate, v8::Handle context, TRI_AddGlobalFunctionVocbase( isolate, context, TRI_V8_ASCII_STRING("SYS_IS_STOPPING"), JS_IsStopping); - + TRI_AddGlobalFunctionVocbase( isolate, context, TRI_V8_ASCII_STRING("V8_TO_VPACK"), JS_V8ToVPack); - + TRI_AddGlobalFunctionVocbase( isolate, context, TRI_V8_ASCII_STRING("VPACK_TO_V8"), JS_VPackToV8);