From 33feedef86e5ddef6d18bd6a5ac64be967010534 Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Wed, 31 Jul 2013 21:13:59 +0100 Subject: [PATCH] Merged svn-support into master. --- src/backend/network.cpp | 136 +++++++++++++++++++++++++++++----------- src/backend/network.h | 2 +- 2 files changed, 99 insertions(+), 39 deletions(-) diff --git a/src/backend/network.cpp b/src/backend/network.cpp index bb140ec2..c67d8ef4 100644 --- a/src/backend/network.cpp +++ b/src/backend/network.cpp @@ -37,7 +37,7 @@ # include "windows.h" # include "shlobj.h" #endif -#define BUFSIZE 4096 +#define BUFSIZE 4096 using namespace std; @@ -51,14 +51,14 @@ namespace boss { SECURITY_ATTRIBUTES saAttr; - PROCESS_INFORMATION piProcInfo; + PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; CHAR chBuf[BUFSIZE]; DWORD dwRead; - + DWORD exitCode; - + //Init attributes. saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; @@ -75,7 +75,7 @@ namespace boss { ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); - siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = consoleWrite; siStartInfo.hStdOutput = consoleWrite; siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; @@ -85,15 +85,15 @@ namespace boss { wchar_t * cmdLine = new wchar_t[utf16Len]; MultiByteToWideChar(CP_UTF8, 0, command.c_str(), -1, cmdLine, utf16Len); - bool result = CreateProcess(NULL, - cmdLine, // command line - NULL, // process security attributes - NULL, // primary thread security attributes - TRUE, // handles are inherited - 0, // creation flags - NULL, // use parent's environment - NULL, // use parent's current directory - &siStartInfo, // STARTUPINFO pointer + bool result = CreateProcess(NULL, + cmdLine, // command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + NULL, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer &piProcInfo); // receives PROCESS_INFORMATION delete [] cmdLine; @@ -109,14 +109,14 @@ namespace boss { BOOST_LOG_TRIVIAL(error) << "Could not get Subversion process exit code."; throw error(error::subversion_error, "Could not get Subversion process exit code."); } - + if (!ReadFile(consoleRead, chBuf, BUFSIZE, &dwRead, NULL)) { BOOST_LOG_TRIVIAL(error) << "Could not read Subversion process output."; throw error(error::subversion_error, "Could not read Subversion process output."); } - + output = string(chBuf, dwRead); - + return exitCode == 0; } @@ -124,11 +124,11 @@ namespace boss { string GetRevision(const std::string& buffer) { string revision, date; size_t pos1, pos2; - + pos1 = buffer.rfind("Revision: "); if (pos1 == string::npos) return ""; - + pos2 = buffer.find('\n', pos1); revision = buffer.substr(pos1+10, pos2-pos1-10); @@ -141,8 +141,21 @@ namespace boss { return revision + " (" + date + ")"; } - std::string UpdateMasterlist(const Game& game, std::vector& parsingErrors) { - + //Gets repository URL string. + string GetURL(const std::string& buffer) { + size_t pos1, pos2; + + pos1 = buffer.rfind("Repository Root: "); + if (pos1 == string::npos) + return ""; + + pos2 = buffer.find('\n', pos1); + + return buffer.substr(pos1+17, pos2-pos1-17); + } + + std::string UpdateMasterlist(Game& game, std::vector& parsingErrors) { + string command, output, revision; //First check if the working copy is set up or not. command = g_path_svn.string() + " info \"" + game.MasterlistPath().string() + "\""; @@ -158,7 +171,7 @@ namespace boss { else return "N/A"; } - + if (!success) { BOOST_LOG_TRIVIAL(trace) << "Working copy is not set up, checking out repository."; //Working copy not set up, perform a checkout. @@ -167,6 +180,30 @@ namespace boss { BOOST_LOG_TRIVIAL(error) << "Subversion could not perform a checkout. Details: " << output; throw error(error::subversion_error, "Subversion could not perform a checkout. Details: " + output); } + } else { + //A working copy exists, but we need to make sure that it points to the right repository. + BOOST_LOG_TRIVIAL(trace) << "Comparing working copy repository URL with BOSS's URL"; + + command = g_path_svn.string() + " info \"" + game.MasterlistPath().string() + "\""; + + if (!RunCommand(command, output)) { + BOOST_LOG_TRIVIAL(error) << "Subversion could not get the repository URL. Details: " << output; + throw error(error::subversion_error, "Subversion could not get the repository URL. Details: " + output); + } + + string url = GetURL(output); + + //Now compare URLs. + if (url != game.URL()) { + BOOST_LOG_TRIVIAL(trace) << "URLs do not match: relocating the working copy."; + + command = g_path_svn.string() + " relocate " + game.URL(); + + if (!RunCommand(command, output)) { + BOOST_LOG_TRIVIAL(error) << "Subversion could not relocate the working copy. Details: " << output; + throw error(error::subversion_error, "Subversion could not relocate the working copy. Details: " + output); + } + } } //Now update masterlist. @@ -177,35 +214,58 @@ namespace boss { throw error(error::subversion_error, "Subversion could not update the masterlist. Details: " + output); } - while (true) { + bool parsingFailed = false; + do { + //Now get the masterlist revision. + BOOST_LOG_TRIVIAL(trace) << "Getting the new masterlist version."; + command = g_path_svn.string() + " info \"" + game.MasterlistPath().string() + "\""; + if (!RunCommand(command, output)) { + BOOST_LOG_TRIVIAL(error) << "Subversion could not read the masterlist revision number. Details: " << output; + throw error(error::subversion_error, "Subversion could not read the masterlist revision number. Details: " + output); + } + + BOOST_LOG_TRIVIAL(trace) << "Reading the masterlist version from the svn info output."; + revision = GetRevision(output); + try { - - //Now get the masterlist revision. - BOOST_LOG_TRIVIAL(trace) << "Getting the new masterlist version."; - command = g_path_svn.string() + " info \"" + game.MasterlistPath().string() + "\""; - if (!RunCommand(command, output)) { - BOOST_LOG_TRIVIAL(error) << "Subversion could not read the masterlist revision number. Details: " << output; - throw error(error::subversion_error, "Subversion could not read the masterlist revision number. Details: " + output); - } - - BOOST_LOG_TRIVIAL(trace) << "Reading the masterlist version from the svn info output."; - revision = GetRevision(output); - //Now test masterlist to see if it parses OK. BOOST_LOG_TRIVIAL(trace) << "Testing the new masterlist to see if it parses OK."; YAML::Node mlist = YAML::LoadFile(game.MasterlistPath().string()); - return revision; - } catch (YAML::Exception& e) { + list messages; + list plugins; + + if (mlist["globals"]) + messages = mlist["globals"].as< list >(); + if (mlist["plugins"]) + plugins = mlist["plugins"].as< list >(); + + for (list::iterator it=plugins.begin(), endIt=plugins.end(); it != endIt; ++it) { + it->EvalAllConditions(game, g_lang_any); + } + + for (list::iterator it=messages.begin(), endIt=messages.end(); it != endIt; ++it) { + it->EvalCondition(game, g_lang_any); + } + + parsingFailed = false; + + } catch (exception& e) { + parsingFailed = true; + //Roll back one revision if there's an error. BOOST_LOG_TRIVIAL(error) << "Masterlist parsing failed. Masterlist revision " + revision + ": " + e.what(); parsingErrors.push_back("Masterlist revision " + revision + ": " + e.what()); + + command = g_path_svn.string() + " update --revision PREV \"" + game.MasterlistPath().string() + "\""; if (!RunCommand(command, output)) { BOOST_LOG_TRIVIAL(error) << "Subversion could not update the masterlist. Details: " << output; throw error(error::subversion_error, "Subversion could not update the masterlist. Details: " + output); } } - } + } while (parsingFailed); + + return revision; } } diff --git a/src/backend/network.h b/src/backend/network.h index eb8c343f..823ccd4e 100644 --- a/src/backend/network.h +++ b/src/backend/network.h @@ -57,6 +57,6 @@ namespace boss { ```svn info masterlist.txt``` returns a bunch of info: the line "Revision: XXXX" contains the revision number. */ - std::string UpdateMasterlist(const Game& game, std::vector& parsingErrors); + std::string UpdateMasterlist(Game& game, std::vector& parsingErrors); } #endif