split paths

This commit is contained in:
isanae
2020-12-03 17:45:32 -05:00
parent ca1cd358bb
commit 54c4fb313d
9 changed files with 464 additions and 424 deletions
+1 -420
View File
@@ -3,6 +3,7 @@
#include "context.h"
#include "env.h"
#include "ini.h"
#include "paths.h"
#include "../utility.h"
#include "../tasks/task.h"
#include "../tools/tools.h"
@@ -228,59 +229,6 @@ std::vector<std::string> format_options()
return lines;
}
fs::path find_in_path(std::string_view exe)
{
const std::wstring wexe = utf8_to_utf16(exe);
const std::size_t size = MAX_PATH;
wchar_t buffer[size + 1] = {};
if (SearchPathW(nullptr, wexe.c_str(), nullptr, size, buffer, nullptr))
return buffer;
else
return {};
}
fs::path find_iscc()
{
const auto tasks = find_tasks("installer");
MOB_ASSERT(tasks.size() == 1);
if (!tasks[0]->enabled())
return {};
auto iscc = conf().tool().get("iscc");
if (iscc.is_absolute())
{
if (!fs::exists(iscc))
{
gcx().bail_out(context::conf,
"{} doesn't exist (from ini, absolute path)", iscc);
}
return iscc;
}
fs::path p = find_in_path(path_to_utf8(iscc));
if (fs::exists(p))
return fs::canonical(fs::absolute(p));
for (int v : {5, 6, 7, 8})
{
const fs::path inno = fmt::format("inno setup {}", v);
for (fs::path pf : {conf().path().pf_x86(), conf().path().pf_x64()})
{
p = pf / inno / iscc;
if (fs::exists(p))
return fs::canonical(fs::absolute(p));
}
}
gcx().bail_out(context::conf, "can't find {} anywhere", iscc);
}
void set_special_options()
{
conf().global().set_output_log_level(
@@ -341,356 +289,6 @@ void make_canonical_path(
details::set_string("paths", key, path_to_utf8(p));
}
bool try_parts(fs::path& check, const std::vector<std::string>& parts)
{
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);
if (fs::exists(p))
{
check = p;
return true;
}
}
return false;
}
fs::path mob_exe_path()
{
// double the buffer size 10 times
const int max_tries = 10;
DWORD buffer_size = MAX_PATH;
for (int tries=0; tries<max_tries; ++tries)
{
auto buffer = std::make_unique<wchar_t[]>(buffer_size + 1);
DWORD n = GetModuleFileNameW(0, buffer.get(), buffer_size);
if (n == 0) {
const auto e = GetLastError();
gcx().bail_out(context::conf,
"can't get module filename, {}", error_message(e));
}
else if (n >= buffer_size) {
// buffer is too small, try again
buffer_size *= 2;
} else {
// if GetModuleFileName() works, `n` does not include the null
// terminator
const std::wstring s(buffer.get(), n);
return fs::canonical(s);
}
}
gcx().bail_out(context::conf, "can't get module filename");
}
fs::path find_root(bool verbose)
{
gcx().trace(context::conf, "looking for root directory");
fs::path mob_exe_dir = mob_exe_path().parent_path();
auto third_party = mob_exe_dir / "third-party";
if (!fs::exists(third_party))
{
if (verbose)
u8cout << "no third-party here\n";
auto p = mob_exe_dir;
if (p.filename().u8string() == u8"x64")
{
p = p.parent_path();
if (p.filename().u8string() == u8"Debug" ||
p.filename().u8string() == u8"Release")
{
if (verbose)
u8cout << "this is mob's build directory, looking up\n";
// mob_exe_dir is in the build directory
third_party = mob_exe_dir / ".." / ".." / ".." / "third-party";
}
}
}
if (!fs::exists(third_party))
gcx().bail_out(context::conf, "root directory not found");
const auto p = fs::canonical(third_party.parent_path());
gcx().trace(context::conf, "found root directory at {}", p);
return p;
}
fs::path find_in_root(const fs::path& file)
{
static fs::path root = find_root();
fs::path p = root / file;
if (!fs::exists(p))
gcx().bail_out(context::conf, "{} not found", p);
gcx().trace(context::conf, "found {}", p);
return p;
}
fs::path find_third_party_directory()
{
static fs::path path = find_in_root("third-party");
return path;
}
bool find_qmake(fs::path& check)
{
// try Qt/Qt5.14.2/msvc*/bin/qmake.exe
if (try_parts(check, {
"Qt",
"Qt" + qt::version(),
"msvc" + qt::vs_version() + "_64",
"bin",
"qmake.exe"}))
{
return true;
}
// try Qt/5.14.2/msvc*/bin/qmake.exe
if (try_parts(check, {
"Qt",
qt::version(),
"msvc" + qt::vs_version() + "_64",
"bin",
"qmake.exe"}))
{
return true;
}
return false;
}
bool try_qt_location(fs::path& check)
{
if (!find_qmake(check))
return false;
check = fs::absolute(check.parent_path() / "..");
return true;
}
fs::path find_qt()
{
fs::path p = conf().path().qt_install();
if (!p.empty())
{
p = fs::absolute(p);
if (!try_qt_location(p))
gcx().bail_out(context::conf, "no qt install in {}", p);
return p;
}
std::vector<fs::path> locations =
{
conf().path().pf_x64(),
"C:\\",
"D:\\"
};
// look for qmake, which is in %qt%/version/msvc.../bin
fs::path qmake = find_in_path("qmake.exe");
if (!qmake.empty())
locations.insert(locations.begin(), qmake.parent_path() / "../../");
// look for qtcreator.exe, which is in %qt%/Tools/QtCreator/bin
fs::path qtcreator = find_in_path("qtcreator.exe");
if (!qtcreator.empty())
locations.insert(locations.begin(), qtcreator.parent_path() / "../../../");
for (fs::path loc : locations)
{
loc = fs::absolute(loc);
if (try_qt_location(loc))
return loc;
}
gcx().bail_out(context::conf, "can't find qt install");
}
void validate_qt()
{
fs::path p = qt::installation_path();
if (!try_qt_location(p))
gcx().bail_out(context::conf, "qt path {} doesn't exist", p);
details::set_string("paths", "qt_install", path_to_utf8(p));
}
fs::path get_known_folder(const GUID& id)
{
wchar_t* buffer = nullptr;
const auto r = ::SHGetKnownFolderPath(id, 0, 0, &buffer);
if (r != S_OK)
return {};
fs::path p = buffer;
::CoTaskMemFree(buffer);
return p;
}
fs::path find_program_files_x86()
{
fs::path p = get_known_folder(FOLDERID_ProgramFilesX86);
if (p.empty())
{
const auto e = GetLastError();
p = fs::path(R"(C:\Program Files (x86))");
gcx().warning(context::conf,
"failed to get x86 program files folder, defaulting to {}, {}",
p, error_message(e));
}
else
{
gcx().trace(context::conf, "x86 program files is {}", p);
}
return p;
}
fs::path find_program_files_x64()
{
fs::path p = get_known_folder(FOLDERID_ProgramFilesX64);
if (p.empty())
{
const auto e = GetLastError();
p = fs::path(R"(C:\Program Files)");
gcx().warning(context::conf,
"failed to get x64 program files folder, defaulting to {}, {}",
p, error_message(e));
}
else
{
gcx().trace(context::conf, "x64 program files is {}", p);
}
return p;
}
fs::path find_temp_dir()
{
const std::size_t buffer_size = MAX_PATH + 2;
wchar_t buffer[buffer_size] = {};
if (GetTempPathW(static_cast<DWORD>(buffer_size), buffer) == 0)
{
const auto e = GetLastError();
gcx().bail_out(context::conf, "can't get temp path", error_message(e));
}
fs::path p(buffer);
gcx().trace(context::conf, "temp dir is {}", p);
return p;
}
fs::path find_vs()
{
if (conf::dry())
return vs::vswhere();
const auto path = vswhere::find_vs();
if (path.empty())
gcx().bail_out(context::conf, "vswhere failed");
const auto lines = split(path_to_utf8(path), "\r\n");
if (lines.empty())
{
gcx().bail_out(context::conf, "vswhere didn't output anything");
}
else if (lines.size() > 1)
{
gcx().error(context::conf, "vswhere returned multiple installations:");
for (auto&& line : lines)
gcx().error(context::conf, " - {}", line);
gcx().bail_out(context::conf,
"specify the `vs` path in the `[paths]` section of the INI, or "
"pass -s paths/vs=PATH` to pick an installation");
}
if (!fs::exists(path))
{
gcx().bail_out(context::conf,
"the path given by vswhere doesn't exist: {}", path);
}
return path;
}
bool try_vcvars(fs::path& bat)
{
if (!fs::exists(bat))
return false;
bat = fs::canonical(fs::absolute(bat));
return true;
}
void find_vcvars()
{
fs::path bat = conf().tool().get("vcvars");
if (conf::dry())
{
if (bat.empty())
bat = "vcvars.bat";
return;
}
else
{
if (bat.empty())
{
bat = vs::installation_path()
/ "VC" / "Auxiliary" / "Build" / "vcvarsall.bat";
if (!try_vcvars(bat))
gcx().bail_out(context::conf, "vcvars not found at {}", bat);
}
else
{
if (!try_vcvars(bat))
gcx().bail_out(context::conf, "vcvars not found at {}", bat);
}
}
details::set_string("tools", "vcvars", path_to_utf8(bat));
gcx().trace(context::conf, "using vcvars at {}", bat);
}
struct parsed_option
{
std::string task, section, key, value;
@@ -929,23 +527,6 @@ void dump_available_options()
}
fs::path make_temp_file()
{
static fs::path dir = conf().path().temp_dir();
wchar_t name[MAX_PATH + 1] = {};
if (GetTempFileNameW(dir.native().c_str(), L"mob", 0, name) == 0)
{
const auto e = GetLastError();
gcx().bail_out(context::conf,
"can't create temp file in {}, {}", dir, error_message(e));
}
return dir / name;
}
conf_global conf::global()
{
return {};
-4
View File
@@ -22,10 +22,6 @@ bool verify_options();
void log_options();
void dump_available_options();
fs::path find_root(bool verbose=false);
fs::path find_in_root(const fs::path& file);
fs::path make_temp_file();
template <class DefaultType>
class conf_section
+1
View File
@@ -1,5 +1,6 @@
#include "pch.h"
#include "ini.h"
#include "paths.h"
#include "context.h"
#include "env.h"
#include "conf.h"
+410
View File
@@ -0,0 +1,410 @@
#include "pch.h"
#include "paths.h"
#include "../tasks/tasks.h"
#include "../utility/string.h"
namespace mob
{
fs::path find_in_path(std::string_view exe)
{
const std::wstring wexe = utf8_to_utf16(exe);
const std::size_t size = MAX_PATH;
wchar_t buffer[size + 1] = {};
if (SearchPathW(nullptr, wexe.c_str(), nullptr, size, buffer, nullptr))
return buffer;
else
return {};
}
fs::path find_iscc()
{
const auto tasks = find_tasks("installer");
MOB_ASSERT(tasks.size() == 1);
if (!tasks[0]->enabled())
return {};
auto iscc = conf().tool().get("iscc");
if (iscc.is_absolute())
{
if (!fs::exists(iscc))
{
gcx().bail_out(context::conf,
"{} doesn't exist (from ini, absolute path)", iscc);
}
return iscc;
}
fs::path p = find_in_path(path_to_utf8(iscc));
if (fs::exists(p))
return fs::canonical(fs::absolute(p));
for (int v : {5, 6, 7, 8})
{
const fs::path inno = fmt::format("inno setup {}", v);
for (fs::path pf : {conf().path().pf_x86(), conf().path().pf_x64()})
{
p = pf / inno / iscc;
if (fs::exists(p))
return fs::canonical(fs::absolute(p));
}
}
gcx().bail_out(context::conf, "can't find {} anywhere", iscc);
}
bool try_parts(fs::path& check, const std::vector<std::string>& parts)
{
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);
if (fs::exists(p))
{
check = p;
return true;
}
}
return false;
}
fs::path mob_exe_path()
{
// double the buffer size 10 times
const int max_tries = 10;
DWORD buffer_size = MAX_PATH;
for (int tries=0; tries<max_tries; ++tries)
{
auto buffer = std::make_unique<wchar_t[]>(buffer_size + 1);
DWORD n = GetModuleFileNameW(0, buffer.get(), buffer_size);
if (n == 0) {
const auto e = GetLastError();
gcx().bail_out(context::conf,
"can't get module filename, {}", error_message(e));
}
else if (n >= buffer_size) {
// buffer is too small, try again
buffer_size *= 2;
} else {
// if GetModuleFileName() works, `n` does not include the null
// terminator
const std::wstring s(buffer.get(), n);
return fs::canonical(s);
}
}
gcx().bail_out(context::conf, "can't get module filename");
}
fs::path find_root(bool verbose)
{
gcx().trace(context::conf, "looking for root directory");
fs::path mob_exe_dir = mob_exe_path().parent_path();
auto third_party = mob_exe_dir / "third-party";
if (!fs::exists(third_party))
{
if (verbose)
u8cout << "no third-party here\n";
auto p = mob_exe_dir;
if (p.filename().u8string() == u8"x64")
{
p = p.parent_path();
if (p.filename().u8string() == u8"Debug" ||
p.filename().u8string() == u8"Release")
{
if (verbose)
u8cout << "this is mob's build directory, looking up\n";
// mob_exe_dir is in the build directory
third_party = mob_exe_dir / ".." / ".." / ".." / "third-party";
}
}
}
if (!fs::exists(third_party))
gcx().bail_out(context::conf, "root directory not found");
const auto p = fs::canonical(third_party.parent_path());
gcx().trace(context::conf, "found root directory at {}", p);
return p;
}
fs::path find_in_root(const fs::path& file)
{
static fs::path root = find_root();
fs::path p = root / file;
if (!fs::exists(p))
gcx().bail_out(context::conf, "{} not found", p);
gcx().trace(context::conf, "found {}", p);
return p;
}
fs::path find_third_party_directory()
{
static fs::path path = find_in_root("third-party");
return path;
}
bool find_qmake(fs::path& check)
{
// try Qt/Qt5.14.2/msvc*/bin/qmake.exe
if (try_parts(check, {
"Qt",
"Qt" + qt::version(),
"msvc" + qt::vs_version() + "_64",
"bin",
"qmake.exe"}))
{
return true;
}
// try Qt/5.14.2/msvc*/bin/qmake.exe
if (try_parts(check, {
"Qt",
qt::version(),
"msvc" + qt::vs_version() + "_64",
"bin",
"qmake.exe"}))
{
return true;
}
return false;
}
bool try_qt_location(fs::path& check)
{
if (!find_qmake(check))
return false;
check = fs::absolute(check.parent_path() / "..");
return true;
}
fs::path find_qt()
{
fs::path p = conf().path().qt_install();
if (!p.empty())
{
p = fs::absolute(p);
if (!try_qt_location(p))
gcx().bail_out(context::conf, "no qt install in {}", p);
return p;
}
std::vector<fs::path> locations =
{
conf().path().pf_x64(),
"C:\\",
"D:\\"
};
// look for qmake, which is in %qt%/version/msvc.../bin
fs::path qmake = find_in_path("qmake.exe");
if (!qmake.empty())
locations.insert(locations.begin(), qmake.parent_path() / "../../");
// look for qtcreator.exe, which is in %qt%/Tools/QtCreator/bin
fs::path qtcreator = find_in_path("qtcreator.exe");
if (!qtcreator.empty())
locations.insert(locations.begin(), qtcreator.parent_path() / "../../../");
for (fs::path loc : locations)
{
loc = fs::absolute(loc);
if (try_qt_location(loc))
return loc;
}
gcx().bail_out(context::conf, "can't find qt install");
}
void validate_qt()
{
fs::path p = qt::installation_path();
if (!try_qt_location(p))
gcx().bail_out(context::conf, "qt path {} doesn't exist", p);
details::set_string("paths", "qt_install", path_to_utf8(p));
}
fs::path get_known_folder(const GUID& id)
{
wchar_t* buffer = nullptr;
const auto r = ::SHGetKnownFolderPath(id, 0, 0, &buffer);
if (r != S_OK)
return {};
fs::path p = buffer;
::CoTaskMemFree(buffer);
return p;
}
fs::path find_program_files_x86()
{
fs::path p = get_known_folder(FOLDERID_ProgramFilesX86);
if (p.empty())
{
const auto e = GetLastError();
p = fs::path(R"(C:\Program Files (x86))");
gcx().warning(context::conf,
"failed to get x86 program files folder, defaulting to {}, {}",
p, error_message(e));
}
else
{
gcx().trace(context::conf, "x86 program files is {}", p);
}
return p;
}
fs::path find_program_files_x64()
{
fs::path p = get_known_folder(FOLDERID_ProgramFilesX64);
if (p.empty())
{
const auto e = GetLastError();
p = fs::path(R"(C:\Program Files)");
gcx().warning(context::conf,
"failed to get x64 program files folder, defaulting to {}, {}",
p, error_message(e));
}
else
{
gcx().trace(context::conf, "x64 program files is {}", p);
}
return p;
}
fs::path find_temp_dir()
{
const std::size_t buffer_size = MAX_PATH + 2;
wchar_t buffer[buffer_size] = {};
if (GetTempPathW(static_cast<DWORD>(buffer_size), buffer) == 0)
{
const auto e = GetLastError();
gcx().bail_out(context::conf, "can't get temp path", error_message(e));
}
fs::path p(buffer);
gcx().trace(context::conf, "temp dir is {}", p);
return p;
}
fs::path find_vs()
{
if (conf::dry())
return vs::vswhere();
const auto path = vswhere::find_vs();
if (path.empty())
gcx().bail_out(context::conf, "vswhere failed");
const auto lines = split(path_to_utf8(path), "\r\n");
if (lines.empty())
{
gcx().bail_out(context::conf, "vswhere didn't output anything");
}
else if (lines.size() > 1)
{
gcx().error(context::conf, "vswhere returned multiple installations:");
for (auto&& line : lines)
gcx().error(context::conf, " - {}", line);
gcx().bail_out(context::conf,
"specify the `vs` path in the `[paths]` section of the INI, or "
"pass -s paths/vs=PATH` to pick an installation");
}
if (!fs::exists(path))
{
gcx().bail_out(context::conf,
"the path given by vswhere doesn't exist: {}", path);
}
return path;
}
bool try_vcvars(fs::path& bat)
{
if (!fs::exists(bat))
return false;
bat = fs::canonical(fs::absolute(bat));
return true;
}
void find_vcvars()
{
fs::path bat = conf().tool().get("vcvars");
if (conf::dry())
{
if (bat.empty())
bat = "vcvars.bat";
return;
}
else
{
if (bat.empty())
{
bat = vs::installation_path()
/ "VC" / "Auxiliary" / "Build" / "vcvarsall.bat";
if (!try_vcvars(bat))
gcx().bail_out(context::conf, "vcvars not found at {}", bat);
}
else
{
if (!try_vcvars(bat))
gcx().bail_out(context::conf, "vcvars not found at {}", bat);
}
}
details::set_string("tools", "vcvars", path_to_utf8(bat));
gcx().trace(context::conf, "using vcvars at {}", bat);
}
} // namespace
+22
View File
@@ -0,0 +1,22 @@
#pragma once
namespace mob
{
fs::path find_root(bool verbose=false);
fs::path find_in_root(const fs::path& file);
fs::path find_third_party_directory();
fs::path find_program_files_x86();
fs::path find_program_files_x64();
fs::path find_vs();
fs::path find_qt();
fs::path find_iscc();
fs::path find_temp_dir();
void find_vcvars();
void validate_qt();
fs::path mob_exe_path();
} // namespace
+17
View File
@@ -8,6 +8,23 @@
namespace mob
{
fs::path make_temp_file()
{
static fs::path dir = conf().path().temp_dir();
wchar_t name[MAX_PATH + 1] = {};
if (GetTempFileNameW(dir.native().c_str(), L"mob", 0, name) == 0)
{
const auto e = GetLastError();
gcx().bail_out(context::conf,
"can't create temp file in {}, {}", dir, error_message(e));
}
return dir / name;
}
file_deleter::file_deleter(const context& cx, fs::path p)
: cx_(cx), p_(std::move(p)), delete_(true)
{
+5
View File
@@ -6,6 +6,11 @@ namespace mob
class context;
// returns a unique filename in the temp directory; requires inis to be loaded
//
fs::path make_temp_file();
struct handle_closer
{
using pointer = HANDLE;
+2
View File
@@ -71,6 +71,7 @@
<ClCompile Include="..\src\core\env.cpp" />
<ClCompile Include="..\src\core\ini.cpp" />
<ClCompile Include="..\src\core\op.cpp" />
<ClCompile Include="..\src\core\paths.cpp" />
<ClCompile Include="..\src\core\pipe.cpp" />
<ClCompile Include="..\src\core\process.cpp" />
<ClCompile Include="..\src\main.cpp" />
@@ -128,6 +129,7 @@
<ClInclude Include="..\src\core\env.h" />
<ClInclude Include="..\src\core\ini.h" />
<ClInclude Include="..\src\core\op.h" />
<ClInclude Include="..\src\core\paths.h" />
<ClInclude Include="..\src\core\pipe.h" />
<ClInclude Include="..\src\core\process.h" />
<ClInclude Include="..\src\net.h" />
+6
View File
@@ -198,6 +198,9 @@
<ClCompile Include="..\src\core\ini.cpp">
<Filter>src\core</Filter>
</ClCompile>
<ClCompile Include="..\src\core\paths.cpp">
<Filter>src\core</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\pch.h">
@@ -263,5 +266,8 @@
<ClInclude Include="..\src\core\ini.h">
<Filter>src\core</Filter>
</ClInclude>
<ClInclude Include="..\src\core\paths.h">
<Filter>src\core</Filter>
</ClInclude>
</ItemGroup>
</Project>