mirror of
https://github.com/ModOrganizer2/mob.git
synced 2026-07-27 14:07:05 -07:00
fixed a few leaking exceptions
force filenames for stylesheets, some are just version numbers changed curl downloader to use CreateFile(), was getting access denied errors fixed curl sometimes getting stuck sip has to start downloading after python because it uses python.exe fixed op::check() to be case insensitive better message when important variables are missing bootstrap: uses vcvars, multi process
This commit is contained in:
+33
-1
@@ -1 +1,33 @@
|
||||
@msbuild vs/builder.sln -m -p:Configuration=Release -noLogo -clp:ErrorsOnly;Verbosity=minimal
|
||||
@echo off
|
||||
Setlocal EnableDelayedExpansion
|
||||
|
||||
set "vswhere_cmd=third-party\bin\vswhere.exe -nologo -prerelease -latest -property installationPath"
|
||||
|
||||
for /F "tokens=* USEBACKQ" %%F in (`%vswhere_cmd%`) do (
|
||||
set ret=%errorlevel%
|
||||
if %errorlevel% neq 0 (
|
||||
echo %%F
|
||||
echo vswhere returned %ret%
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set installation_path=%%F
|
||||
|
||||
if "%installation_path%" == "" (
|
||||
echo empty installation path
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
set "opts="
|
||||
set "opts=%opts% vs/mob.sln"
|
||||
set "opts=%opts% -m "
|
||||
set "opts=%opts% -p:Configuration=Release"
|
||||
set "opts=%opts% -noLogo "
|
||||
set "opts=%opts% -p:UseMultiToolTask=true"
|
||||
set "opts=%opts% -p:EnforceProcessCountAcrossBuilds=true"
|
||||
set "opts=%opts% -clp:ErrorsOnly;Verbosity=minimal"
|
||||
|
||||
set "vcvars=%installation_path%\VC\Auxiliary\Build\vcvarsall.bat"
|
||||
cmd /c ""%vcvars%" amd64 > NUL && msbuild %opts%"
|
||||
echo run `mob` to start building
|
||||
|
||||
+22
-11
@@ -277,13 +277,15 @@ void dump_available_options()
|
||||
|
||||
bool try_parts(fs::path& check, const std::vector<std::string>& parts)
|
||||
{
|
||||
for (std::size_t i=0; i<parts.size() - 1; ++i)
|
||||
for (std::size_t i=0; i<parts.size(); ++i)
|
||||
{
|
||||
fs::path p = check;
|
||||
|
||||
for (std::size_t j=i; j<parts.size(); ++j)
|
||||
p /= parts[j];
|
||||
|
||||
gcx().trace(context::conf, "trying parts " + p.string());
|
||||
|
||||
if (fs::exists(p))
|
||||
{
|
||||
check = p;
|
||||
@@ -702,29 +704,38 @@ void check_missing_options()
|
||||
{
|
||||
if (conf::mo_org().empty())
|
||||
{
|
||||
gcx().bail_out(context::conf,
|
||||
"missing mo_org; either specify it the [options] section of "
|
||||
"the ini or pass '-s options/mo_org=something'");
|
||||
std::cerr
|
||||
<< "missing mo_org; either specify it the [options] section of "
|
||||
<< "the ini or pass '-s options/mo_org=something'\n";
|
||||
|
||||
throw bailed("");
|
||||
}
|
||||
|
||||
if (conf::mo_branch().empty())
|
||||
{
|
||||
gcx().bail_out(context::conf,
|
||||
"missing mo_branch; either specify it the [options] section of "
|
||||
"the ini or pass '-s options/mo_org=something'");
|
||||
std::cerr
|
||||
<< "missing mo_branch; either specify it the [options] section of "
|
||||
<< "the ini or pass '-s options/mo_org=something'\n";
|
||||
|
||||
throw bailed("");
|
||||
}
|
||||
|
||||
if (paths::prefix().empty())
|
||||
{
|
||||
gcx().bail_out(context::conf,
|
||||
"missing prefix; either specify it the [paths] section of "
|
||||
"the ini or pass '-d path'");
|
||||
std::cerr
|
||||
<< "missing prefix; either specify it the [paths] section of "
|
||||
<< "the ini or pass '-d path'\n";
|
||||
|
||||
throw bailed("");
|
||||
}
|
||||
|
||||
for (auto&& [k, v] : g_versions)
|
||||
{
|
||||
if (v.empty())
|
||||
gcx().bail_out(context::conf, "missing version for " + k);
|
||||
{
|
||||
std::cerr << "missing version for " << k << "\n";
|
||||
throw bailed("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-2
@@ -181,6 +181,16 @@ int run(int argc, char** argv)
|
||||
{
|
||||
if (auto r=handle_command_line(argc, argv))
|
||||
return *r;
|
||||
}
|
||||
catch(bailed&)
|
||||
{
|
||||
// silent
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
::SetConsoleCtrlHandler(signal_handler, TRUE);
|
||||
|
||||
@@ -208,8 +218,15 @@ int main(int argc, char** argv)
|
||||
{
|
||||
int r = mob::run(argc, argv);
|
||||
|
||||
mob::gcx().debug(mob::context::generic,
|
||||
"mob finished with exit code " + std::to_string(r));
|
||||
if (r == 0)
|
||||
{
|
||||
mob::gcx().debug(mob::context::generic, "mob done");
|
||||
}
|
||||
else
|
||||
{
|
||||
mob::gcx().debug(mob::context::generic,
|
||||
"mob finished with exit code " + std::to_string(r));
|
||||
}
|
||||
|
||||
mob::dump_logs();
|
||||
|
||||
|
||||
+80
-6
@@ -72,7 +72,17 @@ void curl_downloader::start(const url& u, const fs::path& path)
|
||||
if (conf::dry())
|
||||
return;
|
||||
|
||||
thread_ = std::thread([&] { run(); });
|
||||
thread_ = std::thread([&]
|
||||
{
|
||||
try
|
||||
{
|
||||
run();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// eat it
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void curl_downloader::join()
|
||||
@@ -104,6 +114,11 @@ void curl_downloader::run()
|
||||
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_PROGRESSFUNCTION, on_progress_static);
|
||||
curl_easy_setopt(c, CURLOPT_PROGRESSDATA, this);
|
||||
curl_easy_setopt(c, CURLOPT_XFERINFOFUNCTION, on_xfer_static);
|
||||
curl_easy_setopt(c, CURLOPT_XFERINFODATA, this);
|
||||
curl_easy_setopt(c, CURLOPT_NOPROGRESS, 0l);
|
||||
curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1l);
|
||||
curl_easy_setopt(c, CURLOPT_ERRORBUFFER, error_buffer);
|
||||
|
||||
@@ -120,7 +135,11 @@ void curl_downloader::run()
|
||||
const auto r = curl_easy_perform(c);
|
||||
cx_.trace(context::net, "curl: transfer finished " + url_.string());
|
||||
|
||||
file_.reset();
|
||||
if (file_)
|
||||
{
|
||||
::FlushFileBuffers(file_.get());
|
||||
file_.reset();
|
||||
}
|
||||
|
||||
if (interrupt_)
|
||||
{
|
||||
@@ -152,8 +171,8 @@ void curl_downloader::run()
|
||||
{
|
||||
cx_.error(context::net,
|
||||
std::string("curl: ") +
|
||||
curl_easy_strerror(r) + ", " + error_buffer + ", " +
|
||||
url_.string());
|
||||
curl_easy_strerror(r) + ", " + trim_copy(error_buffer) + " " +
|
||||
"(" + url_.string() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +188,13 @@ size_t curl_downloader::on_write_static(
|
||||
}
|
||||
|
||||
self->on_write(ptr, size * nmemb);
|
||||
|
||||
if (self->interrupt_)
|
||||
{
|
||||
debug("downloader: interrupting");
|
||||
return (size * nmemb) + 1; // force failure
|
||||
}
|
||||
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
@@ -179,11 +205,59 @@ void curl_downloader::on_write(char* ptr, std::size_t n) noexcept
|
||||
op::create_directories(cx_, path_.parent_path());
|
||||
|
||||
cx_.trace(context::net, "opening " + path_.string());
|
||||
file_.reset(_wfopen(path_.native().c_str(), L"wb"));
|
||||
|
||||
HANDLE h = ::CreateFileA(
|
||||
path_.string().c_str(), GENERIC_WRITE, FILE_SHARE_READ,
|
||||
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
const auto e = GetLastError();
|
||||
cx_.error(context::net, "failed to open " + path_.string(), e);
|
||||
interrupt_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
file_.reset(h);
|
||||
}
|
||||
|
||||
bytes_ += n;
|
||||
std::fwrite(ptr, n, 1, file_.get());
|
||||
|
||||
DWORD written = 0;
|
||||
if (!::WriteFile(file_.get(), ptr, static_cast<DWORD>(n), &written, nullptr))
|
||||
{
|
||||
const auto e = GetLastError();
|
||||
cx_.error(context::net, "failed to write to " + path_.string(), e);
|
||||
interrupt_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
int curl_downloader::on_progress_static(
|
||||
void* user, double, double, double, double) noexcept
|
||||
{
|
||||
auto* self = static_cast<curl_downloader*>(user);
|
||||
|
||||
if (self->interrupt_)
|
||||
{
|
||||
debug("downloader: interrupting");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int curl_downloader::on_xfer_static(
|
||||
void* user, curl_off_t, curl_off_t, curl_off_t, curl_off_t) noexcept
|
||||
{
|
||||
auto* self = static_cast<curl_downloader*>(user);
|
||||
|
||||
if (self->interrupt_)
|
||||
{
|
||||
debug("downloader: interrupting");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int curl_downloader::on_debug_static(
|
||||
|
||||
@@ -48,7 +48,7 @@ private:
|
||||
const context& cx_;
|
||||
url url_;
|
||||
fs::path path_;
|
||||
file_ptr file_;
|
||||
handle_ptr file_;
|
||||
std::thread thread_;
|
||||
std::size_t bytes_;
|
||||
std::atomic<bool> interrupt_;
|
||||
@@ -61,6 +61,13 @@ private:
|
||||
|
||||
void on_write(char* ptr, std::size_t n) noexcept;
|
||||
|
||||
static int on_progress_static(
|
||||
void* user, double dltotal, double dlnow,
|
||||
double ultotal, double ulnow) noexcept;
|
||||
|
||||
static int on_xfer_static(
|
||||
void* user, curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow) noexcept;
|
||||
|
||||
static int on_debug_static(
|
||||
CURL* handle, curl_infotype type,
|
||||
|
||||
+19
-3
@@ -484,13 +484,29 @@ void check(const context& cx, const fs::path& p)
|
||||
if (p.empty())
|
||||
cx.bail_out(context::fs, "path is empty");
|
||||
|
||||
if (p.native().starts_with(paths::prefix().native()))
|
||||
auto is_inside = [](auto&& p, auto&& dir)
|
||||
{
|
||||
const std::string s = p.string();
|
||||
const std::string prefix = dir.string();
|
||||
|
||||
if (s.size() < prefix.size())
|
||||
return false;
|
||||
|
||||
const std::string scut = s.substr(0, prefix.size());
|
||||
|
||||
if (_stricmp(scut.c_str(), prefix.c_str()) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (is_inside(p, paths::prefix()))
|
||||
return;
|
||||
|
||||
if (p.native().starts_with(paths::temp_dir().native()))
|
||||
if (is_inside(p, paths::temp_dir()))
|
||||
return;
|
||||
|
||||
if (p.native().starts_with(paths::licenses().native()))
|
||||
if (is_inside(p, paths::licenses()))
|
||||
return;
|
||||
|
||||
cx.bail_out(context::fs, "path " + p.string() + " is outside prefix");
|
||||
|
||||
@@ -607,7 +607,10 @@ void process::on_completed()
|
||||
|
||||
// success
|
||||
if (code_ == 0)
|
||||
{
|
||||
cx_->trace(context::cmd, "process exit code is 0");
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags_ & allow_failure)
|
||||
{
|
||||
|
||||
+11
-9
@@ -46,12 +46,23 @@ void sip::do_clean_for_rebuild()
|
||||
}
|
||||
|
||||
void sip::do_fetch()
|
||||
{
|
||||
// downloading uses python.exe and so has to wait until it's built
|
||||
}
|
||||
|
||||
void sip::do_build_and_install()
|
||||
{
|
||||
download();
|
||||
|
||||
run_tool(extractor()
|
||||
.file(download_file())
|
||||
.output(source_path()));
|
||||
|
||||
generate();
|
||||
|
||||
op::copy_file_to_dir_if_better(cx(),
|
||||
source_path() / "sip.h",
|
||||
python::include_path());
|
||||
}
|
||||
|
||||
void sip::download()
|
||||
@@ -84,15 +95,6 @@ void sip::download()
|
||||
.arg("sip==" + versions::sip())));
|
||||
}
|
||||
|
||||
void sip::do_build_and_install()
|
||||
{
|
||||
generate();
|
||||
|
||||
op::copy_file_to_dir_if_better(cx(),
|
||||
source_path() / "sip.h",
|
||||
python::include_path());
|
||||
}
|
||||
|
||||
void sip::generate()
|
||||
{
|
||||
const auto header = source_path() / "sip.h";
|
||||
|
||||
@@ -22,9 +22,11 @@ void stylesheets::do_fetch()
|
||||
|
||||
for (auto&& r : releases())
|
||||
{
|
||||
const auto file = run_tool(downloader(
|
||||
"https://github.com/" + r.repo + "/" + r.name + "/releases/"
|
||||
"download/v" + r.version + "/" + r.file + ".7z"));
|
||||
const auto file = run_tool(downloader()
|
||||
.url(
|
||||
"https://github.com/" + r.repo + "/" + r.name + "/releases/"
|
||||
"download/v" + r.version + "/" + r.file + ".7z")
|
||||
.file(paths::cache() / (r.name + ".7z")));
|
||||
|
||||
run_tool(extractor()
|
||||
.file(file)
|
||||
|
||||
+2
-1
@@ -232,7 +232,8 @@ void task::fetch()
|
||||
|
||||
if (!get_source_path().empty())
|
||||
{
|
||||
cx().info(context::generic, "patching");
|
||||
cx().debug(context::generic, "patching");
|
||||
|
||||
run_tool(patcher()
|
||||
.task(name())
|
||||
.root(get_source_path()));
|
||||
|
||||
+43
-21
@@ -17,9 +17,13 @@ downloader::downloader(mob::url u)
|
||||
|
||||
downloader& downloader::url(const mob::url& u)
|
||||
{
|
||||
cx_->trace(context::net, "adding url " + u.string());
|
||||
urls_.push_back(u);
|
||||
return *this;
|
||||
}
|
||||
|
||||
downloader& downloader::file(const fs::path& p)
|
||||
{
|
||||
file_ = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -34,28 +38,23 @@ void downloader::do_run()
|
||||
|
||||
cx_->trace(context::net, "looking for already downloaded files");
|
||||
|
||||
for (auto&& u : urls_)
|
||||
if (!file_.empty())
|
||||
{
|
||||
const auto file = path_for_url(u);
|
||||
|
||||
if (fs::exists(file))
|
||||
if (try_picking(file_))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto&& u : urls_)
|
||||
{
|
||||
if (conf::redownload())
|
||||
const auto file = path_for_url(u);
|
||||
|
||||
if (try_picking(file))
|
||||
{
|
||||
cx_->trace(context::redownload, "deleting " + file.string());
|
||||
op::delete_file(*cx_, file, op::optional);
|
||||
}
|
||||
else
|
||||
{
|
||||
cx_->trace(context::bypass, "picking " + file_.string());
|
||||
file_ = file;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cx_->trace(context::net, "no " + file.string());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,19 +66,19 @@ void downloader::do_run()
|
||||
// try them in order
|
||||
for (auto&& u : urls_)
|
||||
{
|
||||
const fs::path file = path_for_url(u);
|
||||
if (file_.empty())
|
||||
file_ = path_for_url(u);
|
||||
|
||||
cx_->trace(context::net,
|
||||
"trying " + u.string() + " into " + file.string());
|
||||
"trying " + u.string() + " into " + file_.string());
|
||||
|
||||
dl_->start(u, file);
|
||||
dl_->start(u, file_);
|
||||
cx_->trace(context::net, "waiting for download");
|
||||
dl_->join();
|
||||
|
||||
if (dl_->ok())
|
||||
{
|
||||
cx_->trace(context::net, "file " + file.string() + " downloaded");
|
||||
file_ = file;
|
||||
cx_->trace(context::net, "file " + file_.string() + " downloaded");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -102,6 +101,29 @@ void downloader::do_interrupt()
|
||||
dl_->interrupt();
|
||||
}
|
||||
|
||||
bool downloader::try_picking(const fs::path& file)
|
||||
{
|
||||
if (fs::exists(file))
|
||||
{
|
||||
if (conf::redownload())
|
||||
{
|
||||
cx_->trace(context::redownload, "deleting " + file.string());
|
||||
op::delete_file(*cx_, file, op::optional);
|
||||
}
|
||||
else
|
||||
{
|
||||
cx_->trace(context::bypass, "picking " + file_.string());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cx_->trace(context::net, "no " + file.string());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fs::path downloader::path_for_url(const mob::url& u) const
|
||||
{
|
||||
std::string filename;
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ void tool::interrupt()
|
||||
{
|
||||
if (!interrupted_)
|
||||
{
|
||||
cx_->info(context::interruption, "interrupting " + name_);
|
||||
cx_->debug(context::interruption, "interrupting " + name_);
|
||||
interrupted_ = true;
|
||||
do_interrupt();
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
downloader(mob::url u);
|
||||
|
||||
downloader& url(const mob::url& u);
|
||||
downloader& file(const fs::path& p);
|
||||
|
||||
fs::path result() const;
|
||||
|
||||
@@ -62,6 +63,7 @@ private:
|
||||
std::vector<mob::url> urls_;
|
||||
|
||||
fs::path path_for_url(const mob::url& u) const;
|
||||
bool try_picking(const fs::path& file);
|
||||
};
|
||||
|
||||
|
||||
|
||||
+18
-4
@@ -84,8 +84,15 @@ file_deleter::file_deleter(const context& cx, fs::path p)
|
||||
|
||||
file_deleter::~file_deleter()
|
||||
{
|
||||
if (delete_)
|
||||
delete_now();
|
||||
try
|
||||
{
|
||||
if (delete_)
|
||||
delete_now();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// eat it
|
||||
}
|
||||
}
|
||||
|
||||
void file_deleter::delete_now()
|
||||
@@ -109,8 +116,15 @@ directory_deleter::directory_deleter(const context& cx, fs::path p)
|
||||
|
||||
directory_deleter::~directory_deleter()
|
||||
{
|
||||
if (delete_)
|
||||
delete_now();
|
||||
try
|
||||
{
|
||||
if (delete_)
|
||||
delete_now();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// eat it
|
||||
}
|
||||
}
|
||||
|
||||
void directory_deleter::delete_now()
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user