feat(Core/DBUpdater): implement db auto update (#6576)

* feat(Core/DBUpdater): implement db auto update

* 1

* 2

* 3

* Some minor improvements

* add find bin for mysql 8.0

* lic

Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com>
This commit is contained in:
Kargatum
2021-06-27 23:59:44 +07:00
committed by GitHub
parent ccd73918ae
commit 2d2857ce81
25 changed files with 929 additions and 79 deletions

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
*/
#include "BuiltInConfig.h"
#include "Config.h"
#include "GitRevision.h"
template<typename Fn>
static std::string GetStringWithDefaultValueFromFunction(
std::string const& key, Fn getter)
{
std::string const value = sConfigMgr->GetOption<std::string>(key, "");
return value.empty() ? getter() : value;
}
std::string BuiltInConfig::GetCMakeCommand()
{
return GetStringWithDefaultValueFromFunction(
"CMakeCommand", GitRevision::GetCMakeCommand);
}
std::string BuiltInConfig::GetBuildDirectory()
{
return GetStringWithDefaultValueFromFunction(
"BuildDirectory", GitRevision::GetBuildDirectory);
}
std::string BuiltInConfig::GetSourceDirectory()
{
return GetStringWithDefaultValueFromFunction(
"SourceDirectory", GitRevision::GetSourceDirectory);
}
std::string BuiltInConfig::GetMySQLExecutable()
{
return GetStringWithDefaultValueFromFunction(
"MySQLExecutable", GitRevision::GetMySQLExecutable);
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
*/
#ifndef BUILT_IN_CONFIG_H
#define BUILT_IN_CONFIG_H
#include "Define.h"
#include <string>
/// Provides helper functions to access built-in values
/// which can be overwritten in config
namespace BuiltInConfig
{
/// Returns the CMake command when any is specified in the config,
/// returns the built-in path otherwise
AC_COMMON_API std::string GetCMakeCommand();
/// Returns the build directory path when any is specified in the config,
/// returns the built-in one otherwise
AC_COMMON_API std::string GetBuildDirectory();
/// Returns the source directory path when any is specified in the config,
/// returns the built-in one otherwise
AC_COMMON_API std::string GetSourceDirectory();
/// Returns the path to the mysql executable (`mysql`) when any is specified
/// in the config, returns the built-in one otherwise
AC_COMMON_API std::string GetMySQLExecutable();
} // namespace BuiltInConfig
#endif // BUILT_IN_CONFIG_H

View File

@@ -21,6 +21,11 @@ char const* GitRevision::GetBranch()
return _BRANCH;
}
char const* GitRevision::GetCMakeCommand()
{
return _CMAKE_COMMAND;
}
char const* GitRevision::GetCMakeVersion()
{
return _CMAKE_VERSION;
@@ -31,6 +36,21 @@ char const* GitRevision::GetHostOSVersion()
return _CMAKE_HOST_SYSTEM;
}
char const* GitRevision::GetBuildDirectory()
{
return _BUILD_DIRECTORY;
}
char const* GitRevision::GetSourceDirectory()
{
return _SOURCE_DIRECTORY;
}
char const* GitRevision::GetMySQLExecutable()
{
return _MYSQL_EXECUTABLE;
}
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
# ifdef _WIN64
# define AZEROTH_PLATFORM_STR "Win64"

View File

@@ -10,16 +10,20 @@
namespace GitRevision
{
char const* GetHash();
char const* GetDate();
char const* GetBranch();
char const* GetCMakeVersion();
char const* GetHostOSVersion();
char const* GetFullVersion();
char const* GetCompanyNameStr();
char const* GetLegalCopyrightStr();
char const* GetFileVersionStr();
char const* GetProductVersionStr();
AC_COMMON_API char const* GetHash();
AC_COMMON_API char const* GetDate();
AC_COMMON_API char const* GetBranch();
AC_COMMON_API char const* GetCMakeCommand();
AC_COMMON_API char const* GetCMakeVersion();
AC_COMMON_API char const* GetHostOSVersion();
AC_COMMON_API char const* GetBuildDirectory();
AC_COMMON_API char const* GetSourceDirectory();
AC_COMMON_API char const* GetMySQLExecutable();
AC_COMMON_API char const* GetFullVersion();
AC_COMMON_API char const* GetCompanyNameStr();
AC_COMMON_API char const* GetLegalCopyrightStr();
AC_COMMON_API char const* GetFileVersionStr();
AC_COMMON_API char const* GetProductVersionStr();
}
#endif

View File

@@ -0,0 +1,257 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
*/
#include "StartProcess.h"
#include "Errors.h"
#include "Log.h"
#include "Optional.h"
#include "Util.h"
#include <boost/algorithm/string/join.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/process/args.hpp>
#include <boost/process/child.hpp>
#include <boost/process/env.hpp>
#include <boost/process/exe.hpp>
#include <boost/process/io.hpp>
#include <boost/process/pipe.hpp>
#include <boost/process/search_path.hpp>
using namespace boost::process;
using namespace boost::iostreams;
namespace Acore
{
template<typename T>
class ACLogSink
{
T callback_;
public:
typedef char char_type;
typedef sink_tag category;
// Requires a callback type which has a void(std::string) signature
ACLogSink(T callback)
: callback_(std::move(callback)) { }
std::streamsize write(char const* str, std::streamsize size)
{
std::string consoleStr(str, size);
std::string utf8;
if (consoleToUtf8(consoleStr, utf8))
callback_(utf8);
return size;
}
};
template<typename T>
auto MakeACLogSink(T&& callback)
-> ACLogSink<typename std::decay<T>::type>
{
return { std::forward<T>(callback) };
}
template<typename T>
static int CreateChildProcess(T waiter, std::string const& executable,
std::vector<std::string> const& argsVector,
std::string const& logger, std::string const& input,
bool secure)
{
ipstream outStream;
ipstream errStream;
if (!secure)
{
LOG_TRACE(logger, "Starting process \"%s\" with arguments: \"%s\".",
executable.c_str(), boost::algorithm::join(argsVector, " ").c_str());
}
// prepare file with only read permission (boost process opens with read_write)
std::shared_ptr<FILE> inputFile(!input.empty() ? fopen(input.c_str(), "rb") : nullptr, [](FILE* ptr)
{
if (ptr != nullptr)
fclose(ptr);
});
// Start the child process
child c = [&]()
{
if (inputFile)
{
// With binding stdin
return child{
exe = boost::filesystem::absolute(executable).string(),
args = argsVector,
env = environment(boost::this_process::environment()),
std_in = inputFile.get(),
std_out = outStream,
std_err = errStream
};
}
else
{
// Without binding stdin
return child{
exe = boost::filesystem::absolute(executable).string(),
args = argsVector,
env = environment(boost::this_process::environment()),
std_in = boost::process::close,
std_out = outStream,
std_err = errStream
};
}
}();
auto outInfo = MakeACLogSink([&](std::string const& msg)
{
LOG_INFO(logger, "%s", msg.c_str());
});
auto outError = MakeACLogSink([&](std::string const& msg)
{
LOG_ERROR(logger, "%s", msg.c_str());
});
copy(outStream, outInfo);
copy(errStream, outError);
// Call the waiter in the current scope to prevent
// the streams from closing too early on leaving the scope.
int const result = waiter(c);
if (!secure)
{
LOG_TRACE(logger, ">> Process \"%s\" finished with return value %i.",
executable.c_str(), result);
}
return result;
}
int StartProcess(std::string const& executable, std::vector<std::string> const& args,
std::string const& logger, std::string input_file, bool secure)
{
return CreateChildProcess([](child& c) -> int
{
try
{
c.wait();
return c.exit_code();
}
catch (...)
{
return EXIT_FAILURE;
}
}, executable, args, logger, input_file, secure);
}
class AsyncProcessResultImplementation
: public AsyncProcessResult
{
std::string const executable;
std::vector<std::string> const args;
std::string const logger;
std::string const input_file;
bool const is_secure;
std::atomic<bool> was_terminated;
// Workaround for missing move support in boost < 1.57
Optional<std::shared_ptr<std::future<int>>> result;
Optional<std::reference_wrapper<child>> my_child;
public:
explicit AsyncProcessResultImplementation(std::string executable_, std::vector<std::string> args_,
std::string logger_, std::string input_file_,
bool secure)
: executable(std::move(executable_)), args(std::move(args_)),
logger(std::move(logger_)), input_file(input_file_),
is_secure(secure), was_terminated(false) { }
AsyncProcessResultImplementation(AsyncProcessResultImplementation const&) = delete;
AsyncProcessResultImplementation& operator= (AsyncProcessResultImplementation const&) = delete;
AsyncProcessResultImplementation(AsyncProcessResultImplementation&&) = delete;
AsyncProcessResultImplementation& operator= (AsyncProcessResultImplementation&&) = delete;
int StartProcess()
{
ASSERT(!my_child, "Process started already!");
return CreateChildProcess([&](child& c) -> int
{
int result;
my_child = std::reference_wrapper<child>(c);
try
{
c.wait();
result = c.exit_code();
}
catch (...)
{
result = EXIT_FAILURE;
}
my_child.reset();
return was_terminated ? EXIT_FAILURE : result;
}, executable, args, logger, input_file, is_secure);
}
void SetFuture(std::future<int> result_)
{
result = std::make_shared<std::future<int>>(std::move(result_));
}
/// Returns the future which contains the result of the process
/// as soon it is finished.
std::future<int>& GetFutureResult() override
{
ASSERT(*result, "The process wasn't started!");
return **result;
}
/// Tries to terminate the process
void Terminate() override
{
if (my_child)
{
was_terminated = true;
try
{
my_child->get().terminate();
}
catch (...)
{
// Do nothing
}
}
}
};
std::shared_ptr<AsyncProcessResult>
StartAsyncProcess(std::string executable, std::vector<std::string> args,
std::string logger, std::string input_file, bool secure)
{
auto handle = std::make_shared<AsyncProcessResultImplementation>(
std::move(executable), std::move(args), std::move(logger), std::move(input_file), secure);
handle->SetFuture(std::async(std::launch::async, [handle] { return handle->StartProcess(); }));
return handle;
}
std::string SearchExecutableInPath(std::string const& filename)
{
try
{
return search_path(filename).string();
}
catch (...)
{
return "";
}
}
} // namespace Acore

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
*/
#ifndef __PROCESS_H__
#define __PROCESS_H__
#include "Define.h"
#include <future>
#include <memory>
#include <string>
#include <vector>
namespace Acore
{
/// Starts a process with the given arguments and parameters and will block
/// until the process is finished.
/// When an input path is given, the file will be routed to the processes stdin.
/// When the process is marked as secure no arguments are leaked to logs.
/// Note that most executables expect it's name as the first argument.
AC_COMMON_API int StartProcess(std::string const& executable, std::vector<std::string> const& args,
std::string const& logger, std::string input_file = "",
bool secure = false);
/// Platform and library independent representation
/// of asynchronous process results
class AsyncProcessResult
{
public:
virtual ~AsyncProcessResult() { }
/// Returns the future which contains the result of the process
/// as soon it is finished.
virtual std::future<int>& GetFutureResult() = 0;
/// Tries to terminate the process
virtual void Terminate() = 0;
};
/// Starts a process asynchronously with the given arguments and parameters and
/// returns an AsyncProcessResult immediately which is set, when the process exits.
/// When an input path is given, the file will be routed to the processes stdin.
/// When the process is marked as secure no arguments are leaked to logs.
/// Note that most executables expect it's name as the first argument.
AC_COMMON_API std::shared_ptr<AsyncProcessResult> StartAsyncProcess(std::string executable, std::vector<std::string> args,
std::string logger, std::string input_file = "",
bool secure = false);
/// Searches for the given executable in the PATH variable
/// and returns a non-empty string when it was found.
AC_COMMON_API std::string SearchExecutableInPath(std::string const& filename);
} // namespace Acore
#endif // __PROCESS_H__