diff options
Diffstat (limited to 'Source/cmServerProtocol.cxx')
-rw-r--r-- | Source/cmServerProtocol.cxx | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx new file mode 100644 index 0000000..c3a4d8e --- /dev/null +++ b/Source/cmServerProtocol.cxx @@ -0,0 +1,264 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Tobias Hunger <tobias.hunger@qt.io> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmServerProtocol.h" + +#include "cmExternalMakefileProjectGenerator.h" +#include "cmServer.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#if defined(CMAKE_BUILD_WITH_CMAKE) +#include "cm_jsoncpp_reader.h" +#include "cm_jsoncpp_value.h" +#endif + +namespace { +// Vocabulary: + +const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; +const std::string kCOOKIE_KEY = "cookie"; +const std::string kEXTRA_GENERATOR_KEY = "extraGenerator"; +const std::string kGENERATOR_KEY = "generator"; +const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory"; +const std::string kTYPE_KEY = "type"; + +} // namespace + +cmServerRequest::cmServerRequest(cmServer* server, const std::string& t, + const std::string& c, const Json::Value& d) + : Type(t) + , Cookie(c) + , Data(d) + , m_Server(server) +{ +} + +void cmServerRequest::ReportProgress(int min, int current, int max, + const std::string& message) const +{ + this->m_Server->WriteProgress(*this, min, current, max, message); +} + +cmServerResponse cmServerRequest::Reply(const Json::Value& data) const +{ + cmServerResponse response(*this); + response.SetData(data); + return response; +} + +cmServerResponse cmServerRequest::ReportError(const std::string& message) const +{ + cmServerResponse response(*this); + response.SetError(message); + return response; +} + +cmServerResponse::cmServerResponse(const cmServerRequest& request) + : Type(request.Type) + , Cookie(request.Cookie) +{ +} + +void cmServerResponse::SetData(const Json::Value& data) +{ + assert(this->m_Payload == PAYLOAD_UNKNOWN); + if (!data[kCOOKIE_KEY].isNull() || !data[kTYPE_KEY].isNull()) { + this->SetError("Response contains cookie or type field."); + return; + } + this->m_Payload = PAYLOAD_DATA; + this->m_Data = data; +} + +void cmServerResponse::SetError(const std::string& message) +{ + assert(this->m_Payload == PAYLOAD_UNKNOWN); + this->m_Payload = PAYLOAD_ERROR; + this->m_ErrorMessage = message; +} + +bool cmServerResponse::IsComplete() const +{ + return this->m_Payload != PAYLOAD_UNKNOWN; +} + +bool cmServerResponse::IsError() const +{ + assert(this->m_Payload != PAYLOAD_UNKNOWN); + return this->m_Payload == PAYLOAD_ERROR; +} + +std::string cmServerResponse::ErrorMessage() const +{ + if (this->m_Payload == PAYLOAD_ERROR) + return this->m_ErrorMessage; + else + return std::string(); +} + +Json::Value cmServerResponse::Data() const +{ + assert(this->m_Payload != PAYLOAD_UNKNOWN); + return this->m_Data; +} + +bool cmServerProtocol::Activate(const cmServerRequest& request, + std::string* errorMessage) +{ + this->m_CMakeInstance = std::make_unique<cmake>(); + const bool result = this->DoActivate(request, errorMessage); + if (!result) + this->m_CMakeInstance = CM_NULLPTR; + return result; +} + +cmake* cmServerProtocol::CMakeInstance() const +{ + return this->m_CMakeInstance.get(); +} + +bool cmServerProtocol::DoActivate(const cmServerRequest& /*request*/, + std::string* /*errorMessage*/) +{ + return true; +} + +std::pair<int, int> cmServerProtocol1_0::ProtocolVersion() const +{ + return std::make_pair(1, 0); +} + +bool cmServerProtocol1_0::DoActivate(const cmServerRequest& request, + std::string* errorMessage) +{ + std::string sourceDirectory = request.Data[kSOURCE_DIRECTORY_KEY].asString(); + const std::string buildDirectory = + request.Data[kBUILD_DIRECTORY_KEY].asString(); + std::string generator = request.Data[kGENERATOR_KEY].asString(); + std::string extraGenerator = request.Data[kEXTRA_GENERATOR_KEY].asString(); + + if (buildDirectory.empty()) { + if (errorMessage) + *errorMessage = + std::string("\"") + kBUILD_DIRECTORY_KEY + "\" is missing."; + return false; + } + cmake* cm = CMakeInstance(); + if (cmSystemTools::PathExists(buildDirectory)) { + if (!cmSystemTools::FileIsDirectory(buildDirectory)) { + if (errorMessage) + *errorMessage = std::string("\"") + kBUILD_DIRECTORY_KEY + + "\" exists but is not a directory."; + return false; + } + + const std::string cachePath = cm->FindCacheFile(buildDirectory); + if (cm->LoadCache(cachePath)) { + cmState* state = cm->GetState(); + + // Check generator: + const std::string cachedGenerator = + std::string(state->GetCacheEntryValue("CMAKE_GENERATOR")); + if (cachedGenerator.empty() && generator.empty()) { + if (errorMessage) + *errorMessage = + std::string("\"") + kGENERATOR_KEY + "\" is required but unset."; + return false; + } + if (generator.empty()) { + generator = cachedGenerator; + } + if (generator != cachedGenerator) { + if (errorMessage) + *errorMessage = std::string("\"") + kGENERATOR_KEY + + "\" set but incompatible with configured generator."; + return false; + } + + // check extra generator: + const std::string cachedExtraGenerator = + std::string(state->GetCacheEntryValue("CMAKE_EXTRA_GENERATOR")); + if (!cachedExtraGenerator.empty() && !extraGenerator.empty() && + cachedExtraGenerator != extraGenerator) { + if (errorMessage) + *errorMessage = std::string("\"") + kEXTRA_GENERATOR_KEY + + "\" is set but incompatible with configured extra generator."; + return false; + } + if (extraGenerator.empty()) { + extraGenerator = cachedExtraGenerator; + } + + // check sourcedir: + const std::string cachedSourceDirectory = + std::string(state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY")); + if (!cachedSourceDirectory.empty() && !sourceDirectory.empty() && + cachedSourceDirectory != sourceDirectory) { + if (errorMessage) + *errorMessage = std::string("\"") + kSOURCE_DIRECTORY_KEY + + "\" is set but incompatible with configured source directory."; + return false; + } + if (sourceDirectory.empty()) { + sourceDirectory = cachedSourceDirectory; + } + } + } + + if (sourceDirectory.empty()) { + if (errorMessage) + *errorMessage = std::string("\"") + kSOURCE_DIRECTORY_KEY + + "\" is unset but required."; + return false; + } + if (!cmSystemTools::FileIsDirectory(sourceDirectory)) { + if (errorMessage) + *errorMessage = + std::string("\"") + kSOURCE_DIRECTORY_KEY + "\" is not a directory."; + return false; + } + if (generator.empty()) { + if (errorMessage) + *errorMessage = + std::string("\"") + kGENERATOR_KEY + "\" is unset but required."; + return false; + } + + const std::string fullGeneratorName = + cmExternalMakefileProjectGenerator::CreateFullGeneratorName( + generator, extraGenerator); + + cmGlobalGenerator* gg = cm->CreateGlobalGenerator(fullGeneratorName); + if (!gg) { + if (errorMessage) + *errorMessage = + std::string("Could not set up the requested combination of \"") + + kGENERATOR_KEY + "\" and \"" + kEXTRA_GENERATOR_KEY + "\""; + return false; + } + + cm->SetGlobalGenerator(gg); + cm->SetHomeDirectory(sourceDirectory); + cm->SetHomeOutputDirectory(buildDirectory); + + this->m_State = STATE_ACTIVE; + return true; +} + +const cmServerResponse cmServerProtocol1_0::Process( + const cmServerRequest& request) +{ + assert(this->m_State >= STATE_ACTIVE); + + return request.ReportError("Unknown command!"); +} |