From a090e9e640a274de72c61fc0f63ac30f26f710ca Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Wed, 29 Apr 2020 19:56:36 -0400 Subject: [PATCH] reworked tools and run_tool() to use member functions to various settings --- src/conf.cpp | 2 +- src/main.cpp | 327 +++++++++++++++++++++++++++++++++--------------- src/net.cpp | 15 +-- src/tools.cpp | 308 ++++++++++++++++++++++++++++++--------------- src/tools.h | 172 +++++++++++++++++-------- src/utility.cpp | 40 ++++-- src/utility.h | 27 ++-- 7 files changed, 604 insertions(+), 287 deletions(-) diff --git a/src/conf.cpp b/src/conf.cpp index c5fd3c9..1892ae4 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -91,7 +91,7 @@ const std::string& get_conf(const std::string& name) } -bool conf::verbose() { return true; } +bool conf::verbose() { return false; } bool conf::dry() { return false; } fs::path third_party::sevenz() { return "7z"; } diff --git a/src/main.cpp b/src/main.cpp index e56ccdd..a783507 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -103,7 +103,10 @@ public: void fetch() { do_fetch(); - run_tool(paths::patches() / name_, get_source_path()); + + run_tool(patcher() + .task(name_) + .root(get_source_path())); } void build_and_install() @@ -113,7 +116,7 @@ public: protected: task(std::string name) - : name_(std::move(name)), interrupted_(false) + : name_(std::move(name)), interrupted_(false), tool_(nullptr) { } @@ -126,26 +129,24 @@ protected: virtual void do_fetch() {}; virtual void do_build_and_install() {}; - template - std::unique_ptr run_tool(Args&&... args) + template + auto run_tool(Tool&& t) { - Tool* p = nullptr; - { + tool_ = &t; std::scoped_lock lock(tool_mutex_); - p = new Tool(std::forward(args)...); - tool_.reset(p); } check_interrupted(); - p->run(); + t.run(); check_interrupted(); { std::scoped_lock lock(tool_mutex_); - tool_.release(); - return std::unique_ptr(p); + tool_ = nullptr; } + + return t.result(); } private: @@ -153,7 +154,7 @@ private: std::thread thread_; std::atomic interrupted_; - std::unique_ptr tool_; + tool* tool_; std::mutex tool_mutex_; static std::mutex interrupt_mutex_; @@ -191,24 +192,41 @@ public: protected: void do_fetch() override { - const auto nodots = replace_all(versions::sevenzip(), ".", ""); + const auto file = run_tool(downloader(source_url())); - const auto file = run_tool( - "https://www.7-zip.org/a/7z" + nodots + "-src.7z")->file(); - - run_tool(file, source_path()); + run_tool(decompresser() + .file(file) + .output(source_path())); } void do_build_and_install() override { - const fs::path src = - source_path() / "CPP" / "7zip" / "Bundles" / "Format7zF"; + run_tool(jom() + .path(module_to_build()) + .def("CPU=x64") + .def("NEW_COMPILER=1") + .def("MY_STATIC_LINK=1") + .def("NO_BUFFEROVERFLOWU=1")); - run_tool(src, "", - "/NOLOGO CPU=x64 NEW_COMPILER=1 " - "MY_STATIC_LINK=1 NO_BUFFEROVERFLOWU=1"); + op::copy_file_to_dir_if_better( + module_to_build() / "x64/7z.dll", + paths::install_dlls()); + } - op::copy_file_to_dir_if_better(src / "x64/7z.dll", paths::install_dlls()); +private: + url source_url() const + { + return "https://www.7-zip.org/a/7z" + version_for_url() + "-src.7z"; + } + + fs::path module_to_build() const + { + return source_path() / "CPP" / "7zip" / "Bundles" / "Format7zF"; + } + + std::string version_for_url() const + { + return replace_all(versions::sevenzip(), ".", ""); } }; @@ -229,21 +247,34 @@ public: protected: void do_fetch() override { - const auto file = run_tool( - "http://zlib.net/zlib-" + versions::zlib() + ".tar.gz")->file(); + const auto file = run_tool(downloader(source_url())); - run_tool(file, source_path()); + run_tool(decompresser() + .file(file) + .output(source_path())); } void do_build_and_install() override { - run_tool(source_path(), "", source_path()); - run_tool(source_path() / cmake_for_nmake::build_path(), "install", ""); + const auto build_path = run_tool(cmake() + .generator(cmake::nmake) + .root(source_path()) + .prefix(source_path())); + + run_tool(jom() + .path(build_path) + .target("install")); op::copy_file_to_dir_if_better( - source_path() / cmake_for_nmake::build_path() / "zconf.h", + build_path / "zconf.h", source_path()); } + +private: + url source_url() const + { + return "https://zlib.net/zlib-" + versions::zlib() + ".tar.gz"; + } }; @@ -299,14 +330,11 @@ private: void fetch_prebuilt() { - const auto underscores = replace_all(versions::boost(), ".", "_"); + const auto file = run_tool(downloader(prebuilt_url())); - const auto file = run_tool( - "https://github.com/ModOrganizer2/modorganizer-umbrella/" - "releases/download/1.1/boost_prebuilt_" + underscores + ".7z") - ->file(); - - run_tool(file, source_path()); + run_tool(decompresser() + .file(file) + .output(source_path())); } void build_and_install_prebuilt() @@ -317,18 +345,35 @@ private: void fetch_from_source() { - const auto file = run_tool( - "https://dl.bintray.com/boostorg/release/" + - boost_version_no_tags() + "/source/" + - boost_version_all_underscores() + ".zip")->file(); + const auto file = run_tool(downloader(source_url())); - run_tool(file, source_path()); + run_tool(decompresser() + .file(file) + .output(source_path())); } void build_and_install_from_source() { } + + url prebuilt_url() const + { + const auto underscores = replace_all(versions::boost(), ".", "_"); + + return + "https://github.com/ModOrganizer2/modorganizer-umbrella/" + "releases/download/1.1/boost_prebuilt_" + underscores + ".7z"; + } + + url source_url() const + { + return + "https://dl.bintray.com/boostorg/release/" + + boost_version_no_tags() + "/source/" + + boost_version_all_underscores() + ".zip"; + } + fs::path lib_path() const { const std::string lib = "lib64-msvc-" + versions::boost_vs(); @@ -426,17 +471,30 @@ public: protected: void do_fetch() override { - const auto file = run_tool( - "https://github.com/fmtlib/fmt/releases/download/" + - versions::fmt() + "/fmt-" + versions::fmt() + ".zip")->file(); + const auto file = run_tool(downloader(source_url())); - run_tool(file, source_path()); + run_tool(decompresser() + .file(file) + .output(source_path())); } void do_build_and_install() override { - run_tool(source_path(), "-DFMT_TEST=OFF -DFMT_DOC=OFF"); - run_tool(source_path() / cmake_for_nmake::build_path(), "", ""); + const auto build_path = run_tool(cmake() + .generator(cmake::nmake) + .root(source_path()) + .def("FMT_TEST=OFF") + .def("FMT_DOC=OFF")); + + run_tool(jom().path(build_path)); + } + +private: + url source_url() const + { + return + "https://github.com/fmtlib/fmt/releases/download/" + + versions::fmt() + "/fmt-" + versions::fmt() + ".zip"; } }; @@ -457,13 +515,21 @@ public: protected: void do_fetch() override { - run_tool("google", "googletest", versions::gtest(), source_path()); + run_tool(git_clone() + .org("google") + .repo("googletest") + .branch(versions::gtest()) + .output(source_path())); } void do_build_and_install() override { - run_tool(source_path()); - run_tool(source_path() / cmake_for_nmake::build_path(), "", ""); + const auto build_path = run_tool(cmake() + .generator(cmake::nmake) + .root(source_path())); + + run_tool(jom() + .path(build_path)); } }; @@ -489,11 +555,11 @@ protected: void do_fetch() override { - const auto file = run_tool( - "https://github.com/ModOrganizer2/libbsarch/releases/download/" + - versions::libbsarch() + "/" + dir_name() + ".7z")->file(); + const auto file = run_tool(downloader(source_url())); - run_tool(file, source_path()); + run_tool(decompresser() + .file(file) + .output(source_path())); } void do_build_and_install() override @@ -502,6 +568,14 @@ protected: source_path() / "libbsarch.dll", paths::install_dlls()); } + +private: + url source_url() const + { + return + "https://github.com/ModOrganizer2/libbsarch/releases/download/" + + versions::libbsarch() + "/" + dir_name() + ".7z"; + } }; @@ -532,11 +606,11 @@ protected: void do_fetch() override { - const auto file = run_tool( - "https://github.com/loot/libloot/releases/download/" + - versions::libloot() + "/" + dir_name() + ".7z")->file(); + const auto file = run_tool(downloader(source_url())); - run_tool(file, source_path()); + run_tool(decompresser() + .file(file) + .output(source_path())); } void do_build_and_install() override @@ -545,6 +619,14 @@ protected: source_path() / "loot.dll", paths::install_loot()); } + +private: + url source_url() const + { + return + "https://github.com/loot/libloot/releases/download/" + + versions::libloot() + "/" + dir_name() + ".7z"; + } }; @@ -574,9 +656,11 @@ public: protected: void do_fetch() override { - run_tool( - "python", "cpython-bin-deps", "libffi", - source_path()); + run_tool(git_clone() + .org("python") + .repo("cpython-bin-deps") + .branch("libffi") + .output(source_path())); } }; @@ -607,11 +691,11 @@ protected: void do_fetch() override { - const std::string filename = "openssl-" + versions::openssl() + ".tar.gz"; - const auto file = run_tool( - "https://www.openssl.org/source/" + filename)->file(); + const auto file = run_tool(downloader(source_url())); - run_tool(file, source_path()); + run_tool(decompresser() + .file(file) + .output(source_path())); } void do_build_and_install() override @@ -630,10 +714,10 @@ protected: private: void configure() { - run_tool(cmd(third_party::perl()) + run_tool(process_runner(third_party::perl(), cmd::stdout_is_verbose) .arg("Configure") - .arg("--openssldir", build_path()) - .arg("--prefix", build_path()) + .arg("--openssldir=", build_path()) + .arg("--prefix=", build_path()) .arg("-FS") .arg("-MP1") .arg("VC-WIN64A") @@ -644,14 +728,19 @@ private: { for (int tries=0; tries<3; ++tries) { - const auto tool = run_tool( - source_path(), "install_engines", "", jom::accept_failure); + int exit_code = run_tool(jom() + .path(source_path()) + .target("install_engines") + .flag(jom::accept_failure)); - if (tool->exit_code() == 0) + if (exit_code == 0) return; } - run_tool(source_path(), "install_engines", "", jom::single_job); + run_tool(jom() + .path(source_path()) + .target("install_engines") + .flag(jom::single_job)); } void copy_files() @@ -683,6 +772,14 @@ private: } } + + url source_url() const + { + return + "https://www.openssl.org/source/" + "openssl-" + versions::openssl() + ".tar.gz"; + } + std::vector output_names() const { return @@ -752,11 +849,19 @@ public: protected: void do_fetch() override { - const auto file = run_tool( - "https://sourceforge.net/projects/bzip2/files/" - "bzip2-" + versions::bzip2() + ".tar.gz/download")->file(); + const auto file = run_tool(downloader(source_url())); - run_tool(file, source_path()); + run_tool(decompresser() + .file(file) + .output(source_path())); + } + +private: + url source_url() const + { + return + "https://sourceforge.net/projects/bzip2/files/" + "bzip2-" + versions::bzip2() + ".tar.gz/download"; } }; @@ -777,9 +882,11 @@ public: protected: void do_fetch() override { - const auto file = run_tool( - "python", "cpython", "v" + versions::python(), - source_path()); + run_tool(git_clone() + .org("python") + .repo("cpython") + .branch("v" + versions::python()) + .output(source_path())); if (fs::exists(source_path() / "PCBuild" / "UpgradeLog.htm")) debug("project already upgraded"); @@ -789,22 +896,18 @@ protected: void do_build_and_install() override { - run_tool( - solution_file(), - std::vector - { + run_tool(msbuild() + .solution(solution_file()) + .projects({ "python", "pythonw", "python3dll", "select", "pyexpat", - "unicodedata", "_queue", "_bz2", "_ssl" - }, - std::vector - { + "unicodedata", "_queue", "_bz2", "_ssl"}) + .parameters({ "bz2Dir=" + bzip2::source_path().string(), "zlibDir=" + zlib::source_path().string(), "opensslIncludeDir=" + openssl::include_path().string(), "opensslOutDir=" + openssl::source_path().string(), "libffiIncludeDir=" + libffi::include_path().string(), - "libffiOutDir=" + libffi::lib_path().string() - }); + "libffiOutDir=" + libffi::lib_path().string()})); if (fs::exists(build_path() / "_mob_packaged")) { @@ -812,7 +915,9 @@ protected: } else { - run_tool(cmd(source_path() / "python.bat") + const auto bat = source_path() / "python.bat"; + + run_tool(process_runner(bat, cmd::stdout_is_verbose) .name("package python") .arg(fs::path("PC/layout")) .arg("--source", source_path()) @@ -849,7 +954,7 @@ protected: private: void upgrade_project() { - run_tool(cmd(third_party::devenv()) + run_tool(process_runner(third_party::devenv(), cmd::stdout_is_verbose) .name("upgrade project") .arg(solution_file()) .arg("/upgrade")); @@ -925,26 +1030,41 @@ BOOL WINAPI signal_handler(DWORD) noexcept } +struct curl_init +{ + curl_init() + { + curl_global_init(CURL_GLOBAL_ALL ); + } + + ~curl_init() + { + curl_global_cleanup(); + } +}; + + int run(int argc, char** argv) { try { ::SetConsoleCtrlHandler(signal_handler, TRUE); + curl_init curl; vcvars(); prepend_to_path(find_third_party_directory() / "bin"); g_tasks.push_back(std::make_unique()); - //g_tasks.push_back(std::make_unique()); - //g_tasks.push_back(std::make_unique()); + g_tasks.push_back(std::make_unique()); + g_tasks.push_back(std::make_unique()); g_tasks.push_back(std::make_unique()); - //g_tasks.push_back(std::make_unique()); - //g_tasks.push_back(std::make_unique()); - //g_tasks.push_back(std::make_unique()); - //g_tasks.push_back(std::make_unique()); - //g_tasks.push_back(std::make_unique()); - //g_tasks.push_back(std::make_unique()); - //g_tasks.push_back(std::make_unique()); + g_tasks.push_back(std::make_unique()); + g_tasks.push_back(std::make_unique()); + g_tasks.push_back(std::make_unique()); + g_tasks.push_back(std::make_unique()); + g_tasks.push_back(std::make_unique()); + g_tasks.push_back(std::make_unique()); + g_tasks.push_back(std::make_unique()); if (argc > 1) { @@ -969,10 +1089,13 @@ int run(int argc, char** argv) for (auto&& t : g_tasks) + { t->run(); - - for (auto&& t : g_tasks) t->join(); + } + + //for (auto&& t : g_tasks) + // t->join(); return 0; } diff --git a/src/net.cpp b/src/net.cpp index 43c90ab..b5bbde6 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -7,15 +7,6 @@ namespace builder { -std::string redir_nul() -{ - if (conf::verbose()) - return {}; - else - return " > NUL"; -} - - url::url(const char* p) : s_(p) { @@ -86,10 +77,13 @@ void curl_downloader::run() { auto* c = curl_easy_init(); + char error_buffer[CURL_ERROR_SIZE + 1] = {}; + curl_easy_setopt(c, CURLOPT_URL, url_.c_str()); curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, on_write_static); curl_easy_setopt(c, CURLOPT_WRITEDATA, this); curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1l); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, error_buffer); file_deleter output_deleter(path_); @@ -99,7 +93,7 @@ void curl_downloader::run() if (interrupt_) return; - if (r == 0) + if (r == CURLE_OK) { long h = 0; curl_easy_getinfo(c, CURLINFO_RESPONSE_CODE, &h); @@ -117,6 +111,7 @@ void curl_downloader::run() else { error(url_.string() + " curl: " + curl_easy_strerror(r)); + error(error_buffer); } curl_easy_cleanup(c); diff --git a/src/tools.cpp b/src/tools.cpp index 61bf8c9..b76dcb6 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -74,6 +74,18 @@ tool::tool(std::string name) { } +tool::tool(tool&& t) + : name_(std::move(t.name_)), interrupted_(t.interrupted_.load()) +{ +} + +tool& tool::operator=(tool&& t) +{ + name_ = std::move(t.name_); + interrupted_ = t.interrupted_.load(); + return *this; +} + void tool::run() { do_run(); @@ -95,39 +107,29 @@ bool tool::interrupted() const } -process_runner::process_runner(std::string name) +basic_process_runner::basic_process_runner(std::string name) : tool(std::move(name)) { } -process_runner::process_runner(std::string name, std::string cmd, fs::path cwd) - : tool(std::move(name)), cmd_(std::move(cmd)), cwd_(std::move(cwd)) -{ -} - -void process_runner::do_run() -{ - execute_and_join(op::run(cmd_, cwd_)); -} - -void process_runner::do_interrupt() +void basic_process_runner::do_interrupt() { process_.interrupt(); } -int process_runner::execute_and_join(process p, bool check_exit_code) +int basic_process_runner::execute_and_join(process p, bool check_exit_code) { process_ = std::move(p); join(check_exit_code); return process_.exit_code(); } -int process_runner::execute_and_join(const cmd& c, bool check_exit_code) +int basic_process_runner::execute_and_join(const cmd& c, bool check_exit_code) { return execute_and_join(op::run(c.string(), c.cwd()), check_exit_code); } -void process_runner::join(bool check_exit_code) +void basic_process_runner::join(bool check_exit_code) { process_.join(); @@ -142,30 +144,38 @@ void process_runner::join(bool check_exit_code) } } -int process_runner::exit_code() const +int basic_process_runner::exit_code() const { return process_.exit_code(); } -downloader::downloader(url u) +downloader::downloader() + : tool("downloader") +{ +} + +downloader::downloader(builder::url u) : tool("downloader") { urls_.push_back(std::move(u)); } -downloader::downloader(std::vector urls) - : tool("downloader"), urls_(std::move(urls)) +downloader& downloader::url(const builder::url& u) { + urls_.push_back(u); + return *this; } -fs::path downloader::file() const +fs::path downloader::result() const { return file_; } void downloader::do_run() { + dl_.reset(new curl_downloader); + // check if one the urls has already been downloaded for (auto&& u : urls_) { @@ -183,26 +193,30 @@ void downloader::do_run() { const fs::path file = path_for_url(u); - dl_.start(u, file); - dl_.join(); + dl_->start(u, file); + dl_->join(); - if (dl_.ok()) + if (dl_->ok()) { file_ = file; return; } } + if (interrupted()) + return; + // all failed bail_out("all urls failed"); } void downloader::do_interrupt() { - dl_.interrupt(); + if (dl_) + dl_->interrupt(); } -fs::path downloader::path_for_url(const url& u) const +fs::path downloader::path_for_url(const builder::url& u) const { std::string filename; @@ -216,7 +230,7 @@ fs::path downloader::path_for_url(const url& u) const if (url_string.ends_with(strip)) url_string = url_string.substr(0, url_string.size() - strip.size()); - filename = url(url_string).filename(); + filename = builder::url(url_string).filename(); } else { @@ -227,15 +241,35 @@ fs::path downloader::path_for_url(const url& u) const } -git_clone::git_clone(std::string a, std::string r, std::string b, fs::path w) : - process_runner("git_clone"), - author_(std::move(a)), - repo_(std::move(r)), - branch_(std::move(b)), - where_(std::move(w)) +git_clone::git_clone() + : basic_process_runner("git_clone") { } +git_clone& git_clone::org(const std::string& name) +{ + org_ = name; + return *this; +} + +git_clone& git_clone::repo(const std::string& name) +{ + repo_ = name; + return *this; +} + +git_clone& git_clone::branch(const std::string& name) +{ + branch_ = name; + return *this; +} + +git_clone& git_clone::output(const fs::path& dir) +{ + where_ = dir; + return *this; +} + void git_clone::do_run() { const fs::path dot_git = where_ / ".git"; @@ -248,7 +282,7 @@ void git_clone::do_run() void git_clone::clone() { - execute_and_join(cmd(third_party::git()) + execute_and_join(cmd(third_party::git(), cmd::stdout_is_verbose) .arg("clone") .arg("--recurse-submodules") .arg("--depth", "1") @@ -261,7 +295,7 @@ void git_clone::clone() void git_clone::pull() { - execute_and_join(cmd(third_party::git()) + execute_and_join(cmd(third_party::git(), cmd::stdout_is_verbose) .arg("pull") .arg("--recurse-submodules") .arg("--quiet", cmd::quiet) @@ -272,16 +306,27 @@ void git_clone::pull() url git_clone::repo_url() const { - return "https://github.com/" + author_ + "/" + repo_ + ".git"; + return "https://github.com/" + org_ + "/" + repo_ + ".git"; } -decompresser::decompresser(fs::path file, fs::path where) : - process_runner("decompresser"), - file_(std::move(file)), where_(std::move(where)) +decompresser::decompresser() + : basic_process_runner("decompresser") { } +decompresser& decompresser::file(const fs::path& file) +{ + file_ = file; + return *this; +} + +decompresser& decompresser::output(const fs::path& dir) +{ + where_ = dir; + return *this; +} + void decompresser::do_run() { if (fs::exists(interrupt_file())) @@ -321,14 +366,14 @@ void decompresser::do_run() if (file_.string().ends_with(".tar.gz")) { - c = cmd(third_party::sevenz()) + c = cmd(third_party::sevenz(), cmd::noflags) .arg("x") .arg("-so", file_) .string(); c += " | "; - c += cmd(third_party::sevenz()) + c += cmd(third_party::sevenz(), cmd::noflags) .arg("x") .arg("-aoa") .arg("-si") @@ -338,7 +383,7 @@ void decompresser::do_run() } else { - c = cmd(third_party::sevenz()) + c = cmd(third_party::sevenz(), cmd::stdout_is_verbose) .arg("x") .arg("-aoa") .arg("-bd") @@ -414,18 +459,29 @@ void decompresser::check_duplicate_directory() } -patcher::patcher(fs::path patch_dir, fs::path output_dir) : - process_runner("patcher"), - patches_(std::move(patch_dir)), output_(std::move(output_dir)) +patcher::patcher() + : basic_process_runner("patcher") { } +patcher& patcher::task(const std::string& name) +{ + patches_ = paths::patches() / name; + return *this; +} + +patcher& patcher::root(const fs::path& dir) +{ + output_ = dir; + return *this; +} + void patcher::do_run() { if (!fs::exists(patches_)) return; - const auto base = cmd(third_party::patch()) + const auto base = cmd(third_party::patch(), cmd::stdout_is_verbose) .arg("--read-only", "ignore") .arg("--strip", "0") .arg("--directory", output_) @@ -475,105 +531,157 @@ void patcher::do_run() } -process do_cmake( - const fs::path& build, const fs::path& prefix, - const std::string& args, const std::string& generator) +cmake::cmake() : + basic_process_runner("cmake"), + gen_(nmake), cmd_(third_party::cmake(), cmd::stdout_is_verbose) { - auto c = cmd(third_party::cmake()) - .arg("-G", generator) - .arg("-DCMAKE_INSTALL_MESSAGE=NEVER") +} + +cmake& cmake::generator(generators g) +{ + gen_ = g; + return *this; +} + +cmake& cmake::root(const fs::path& p) +{ + root_ = p; + return *this; +} + +cmake& cmake::prefix(const fs::path& s) +{ + prefix_ = s; + return *this; +} + +cmake& cmake::def(const std::string& s) +{ + cmd_.arg("-D" + s); + return *this; +} + +fs::path cmake::result() const +{ + return output_; +} + +void cmake::do_run() +{ + std::string g; + + switch (gen_) + { + case nmake: + { + output_ = root_ / "build"; + g = "NMake Makefiles"; + break; + } + + case vs: + { + output_ = root_ / "vsbuild"; + g = "Visual Studio " + versions::vs() + " " + versions::vs_year(); + break; + } + } + + + cmd_ + .arg("-G", "\"" + g + "\"") + .arg("-DCMAKE_INSTALL_MESSAGE=NEVER", cmd::quiet) .arg("--log-level", "WARNING", cmd::quiet); - if (!prefix.empty()) - c.arg("-DCMAKE_INSTALL_PREFIX=", prefix, cmd::nospace); + if (!prefix_.empty()) + cmd_.arg("-DCMAKE_INSTALL_PREFIX=", prefix_, cmd::nospace); - c - .arg(args) - .arg(".."); + cmd_.arg(".."); + cmd_.cwd(output_); - return op::run(c.string(), build); + execute_and_join(cmd_); } -cmake_for_nmake::cmake_for_nmake(fs::path r, std::string a, fs::path p) : - process_runner("cmake_for_nmake"), - root_(std::move(r)), args_(std::move(a)), prefix_(std::move(p)) + +jom::jom() : + basic_process_runner("jom"), + cmd_(third_party::jom(), cmd::stdout_is_verbose), flags_(noflags) { } -fs::path cmake_for_nmake::build_path() +jom& jom::path(const fs::path& p) { - return "build"; + cmd_.cwd(p); + return *this; } -void cmake_for_nmake::do_run() +jom& jom::target(const std::string& s) { - const auto build = root_ / build_path(); - const std::string g = "NMake Makefiles"; - execute_and_join(do_cmake(build, prefix_, args_, g)); + target_ = s; + return *this; } - -cmake_for_vs::cmake_for_vs(fs::path r, std::string a, fs::path p) : - process_runner("cmake_for_vs"), - root_(std::move(r)), args_(std::move(a)), prefix_(std::move(p)) +jom& jom::def(const std::string& s) { + cmd_.arg(s); + return *this; } -fs::path cmake_for_vs::build_path() +jom& jom::flag(flags f) { - return "vsbuild"; + flags_ = f; + return *this; } -void cmake_for_vs::do_run() -{ - const auto build = root_ / build_path(); - const std::string g = "Visual Studio " + versions::vs() + " " + versions::vs_year(); - execute_and_join(do_cmake(build, prefix_, args_, g)); -} - - -jom::jom(fs::path dir, std::string target, std::string args, flags f) : - process_runner("jom " + target), - dir_(std::move(dir)), target_(std::move(target)), - args_(std::move(args)), flags_(f) +int jom::result() const { + return exit_code(); } void jom::do_run() { - auto c = cmd(third_party::jom()) + cmd_ .arg("/C", cmd::quiet) .arg("/S", cmd::quiet) .arg("/K"); if (flags_ & single_job) - c.arg("/J", "1"); + cmd_.arg("/J", "1"); - c - .arg(args_) - .arg(target_) - .cwd(dir_); + cmd_.arg(target_); const bool check_exit_code = !(flags_ & accept_failure); - execute_and_join(c, check_exit_code); + execute_and_join(cmd_, check_exit_code); } -msbuild::msbuild( - fs::path sln, - std::vector projects, - std::vector params) : - process_runner("msbuild"), - sln_(std::move(sln)), - projects_(std::move(projects)), - params_(std::move(params)) +msbuild::msbuild() + : basic_process_runner("msbuild") { } +msbuild& msbuild::solution(const fs::path& sln) +{ + sln_ = sln; + return *this; +} + +msbuild& msbuild::projects(const std::vector& names) +{ + projects_ = names; + return *this; +} + +msbuild& msbuild::parameters(const std::vector& params) +{ + params_ = params; + return *this; +} + void msbuild::do_run() { - auto c = cmd(third_party::msbuild()) + auto c = cmd(third_party::msbuild(), cmd::noflags) .arg("-nologo") .arg("-maxCpuCount") .arg("-property:UseMultiToolTask=true") diff --git a/src/tools.h b/src/tools.h index b4d0c26..e54a413 100644 --- a/src/tools.h +++ b/src/tools.h @@ -12,11 +12,16 @@ void vcvars(); class tool { public: + tool(tool&& t); + tool& operator=(tool&& t); + virtual ~tool() = default; void run(); void interrupt(); + void result() {} + protected: tool(std::string name); @@ -34,37 +39,35 @@ private: class downloader : public tool { public: - downloader(url u); - downloader(std::vector urls); + downloader(); + downloader(builder::url u); - fs::path file() const; + downloader& url(const builder::url& u); + + fs::path result() const; protected: void do_run() override; void do_interrupt() override; private: - curl_downloader dl_; + std::unique_ptr dl_; fs::path file_; - std::vector urls_; + std::vector urls_; - fs::path path_for_url(const url& u) const; + fs::path path_for_url(const builder::url& u) const; }; -class process_runner : public tool +class basic_process_runner : public tool { public: - process_runner(std::string name, std::string cmd, fs::path cwd={}); - process_runner(const cmd& c); - void join(bool check_exit_code=true); int exit_code() const; protected: - process_runner(std::string name); + basic_process_runner(std::string name); - void do_run() override; void do_interrupt() override; int execute_and_join(process p, bool check_exit_code=true); @@ -77,17 +80,74 @@ private: }; -class git_clone : public process_runner +class process_runner : public basic_process_runner { public: - git_clone( - std::string author, std::string repo, std::string b, fs::path where); + process_runner(fs::path exe, cmd::flags flags) + : basic_process_runner(exe.filename().string()), cmd_(exe, flags) + { + } + + process_runner& name(const std::string& s) + { + cmd_.name(s); + return *this; + } + + const std::string& name() const + { + return cmd_.name(); + } + + process_runner& cwd(const fs::path& p) + { + cmd_.cwd(p); + return *this; + } + + const fs::path& cwd() const + { + return cmd_.cwd(); + } + + template + process_runner& arg(Args&&... args) + { + cmd_.arg(std::forward(args)...); + return *this; + } + + int result() const + { + return exit_code(); + } + +protected: + void do_run() override + { + execute_and_join(cmd_); + } + +private: + cmd cmd_; +}; + + +class git_clone : public basic_process_runner +{ +public: + git_clone(); + + git_clone& org(const std::string& name); + git_clone& repo(const std::string& name); + git_clone& branch(const std::string& name); + git_clone& output(const fs::path& dir); protected: void do_run() override; private: - std::string author_; + std::string org_; std::string repo_; std::string branch_; fs::path where_; @@ -98,10 +158,12 @@ private: }; -class decompresser : public process_runner +class decompresser : public basic_process_runner { public: - decompresser(fs::path file, fs::path where); + decompresser(); + decompresser& file(const fs::path& file); + decompresser& output(const fs::path& dir); protected: void do_run() override; @@ -115,10 +177,13 @@ private: }; -class patcher : public process_runner +class patcher : public basic_process_runner { public: - patcher(fs::path patch_dir, fs::path output_dir); + patcher(); + + patcher& task(const std::string& name); + patcher& root(const fs::path& dir); protected: void do_run() override; @@ -129,70 +194,73 @@ private: }; -class cmake_for_nmake : public process_runner +class cmake : public basic_process_runner { public: - cmake_for_nmake(fs::path root, std::string args={}, fs::path prefix={}); - static fs::path build_path(); + enum generators + { + vs = 0x01, + nmake = 0x02 + }; + + cmake(); + + cmake& generator(generators g); + cmake& root(const fs::path& p); + cmake& prefix(const fs::path& s); + cmake& def(const std::string& s); + + fs::path result() const; protected: void do_run() override; private: fs::path root_; - std::string args_; + generators gen_; fs::path prefix_; + fs::path output_; + cmd cmd_; }; -class cmake_for_vs : public process_runner -{ -public: - cmake_for_vs(fs::path root, std::string args={}, fs::path prefix={}); - static fs::path build_path(); - -protected: - void do_run() override; - -private: - fs::path root_; - std::string args_; - fs::path prefix_; -}; - - -class jom : public process_runner +class jom : public basic_process_runner { public: enum flags { - default_flags = 0x00, + noflags = 0x00, single_job = 0x01, accept_failure = 0x02 }; - jom( - fs::path dir, std::string target, std::string args, - flags f=default_flags); + jom(); + + jom& path(const fs::path& p); + jom& target(const std::string& s); + jom& def(const std::string& s); + jom& flag(flags f); + + int result() const; protected: void do_run() override; private: - fs::path dir_; + cmd cmd_; std::string target_; - std::string args_; flags flags_; }; -class msbuild : public process_runner +class msbuild : public basic_process_runner { public: - msbuild( - fs::path sln, - std::vector projects, - std::vector params); + msbuild(); + + msbuild& solution(const fs::path& sln); + msbuild& projects(const std::vector& names); + msbuild& parameters(const std::vector& params); protected: void do_run() override; diff --git a/src/utility.cpp b/src/utility.cpp index 90d641f..94df9f1 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -189,6 +189,16 @@ std::string join(const std::vector& v, const std::string& sep) return s; } + +std::string redir_nul() +{ + if (conf::verbose()) + return {}; + else + return " > NUL"; +} + + cmd& cmd::name(const std::string& s) { name_ = s; @@ -214,40 +224,48 @@ const fs::path& cmd::cwd() const return cwd_; } -void cmd::add_arg(const std::string& name, const std::string& value, flags f) +std::string cmd::string() const +{ + if (flags_ & stdout_is_verbose) + return s_ + redir_nul(); + else + return s_; +} + +void cmd::add_arg(const std::string& k, const std::string& v, arg_flags f) { if ((f & quiet) && conf::verbose()) return; - if (name.empty() && value.empty()) + if (k.empty() && v.empty()) return; - if (name.empty()) - s_ += " " + value; - else if (f & nospace) - s_ += " " + name + value; + if (k.empty()) + s_ += " " + v; + else if ((f & nospace) || k.back() == '=') + s_ += " " + k + v; else - s_ += " " + name + " " + value; + s_ += " " + k + " " + v; } std::string cmd::arg_to_string(const char* s) { - return std::string(" ") + s; + return s; } std::string cmd::arg_to_string(const std::string& s) { - return " " + s; + return s; } std::string cmd::arg_to_string(const fs::path& p) { - return " \"" + p.string() + "\""; + return "\"" + p.string() + "\""; } std::string cmd::arg_to_string(const url& u) { - return " " + u.string(); + return u.string(); } diff --git a/src/utility.h b/src/utility.h index f611e85..7ce766a 100644 --- a/src/utility.h +++ b/src/utility.h @@ -144,15 +144,22 @@ std::string join(const std::vector& v, const std::string& sep); class cmd { public: - enum flags + enum arg_flags { - noflags = 0x00, + noargflags = 0x00, quiet = 0x01, nospace = 0x02 }; - cmd(const fs::path& exe) - : exe_(exe.filename().string()) + enum flags + { + noflags = 0x00, + stdout_is_verbose = 0x01 + }; + + + cmd(const fs::path& exe, flags f) + : exe_(exe.filename().string()), flags_(f) { s_ += arg_to_string(exe); } @@ -164,31 +171,29 @@ public: const fs::path& cwd() const; template - cmd& arg(const T& value, flags f=noflags) + cmd& arg(const T& value, arg_flags f=noargflags) { add_arg("", arg_to_string(value), f); return *this; } template - cmd& arg(const std::string& name, const T& value, flags f=noflags) + cmd& arg(const std::string& name, const T& value, arg_flags f=noargflags) { add_arg(name, arg_to_string(value), f); return *this; } - const std::string& string() const - { - return s_; - } + std::string string() const; private: std::string name_; std::string exe_; fs::path cwd_; std::string s_; + flags flags_; - void add_arg(const std::string& name, const std::string& value, flags f); + void add_arg(const std::string& k, const std::string& v, arg_flags f); std::string arg_to_string(const char* s); std::string arg_to_string(const std::string& s);