Read the Wine version without Boost.Process

By spawning the process using posix_spawn and manually reading from a
pipe.
This commit is contained in:
Robbert van der Helm
2022-04-11 14:33:35 +02:00
parent 60e4619ef1
commit 006cc6f52a
4 changed files with 251 additions and 43 deletions
+65 -42
View File
@@ -83,14 +83,35 @@ bp::environment PluginInfo::create_host_env() const {
return env;
}
ProcessEnvironment PluginInfo::create_host_env_2() const {
ProcessEnvironment env(environ);
// Only set the prefix when could auto detect it and it's not being
// overridden (this entire `std::visit` instead of `std::has_alternative` is
// just for clarity's sake)
std::visit(overload{
[](const OverridenWinePrefix&) {},
[&](const ghc::filesystem::path& prefix) {
env.insert("WINEPREFIX", prefix.string());
},
[](const DefaultWinePrefix&) {},
},
wine_prefix_);
return env;
}
ghc::filesystem::path PluginInfo::normalize_wine_prefix() const {
return std::visit(
overload{
[](const OverridenWinePrefix& prefix) { return prefix.value; },
[](const ghc::filesystem::path& prefix) { return prefix; },
[](const DefaultWinePrefix&) {
const bp::environment env = boost::this_process::environment();
return fs::path(env.at("HOME").to_string()) / ".wine";
// NOLINTNEXTLINE(concurrency-mt-unsafe)
const char* home_dir = getenv("HOME");
assert(home_dir);
return fs::path(home_dir) / ".wine";
},
},
wine_prefix_);
@@ -99,38 +120,40 @@ ghc::filesystem::path PluginInfo::normalize_wine_prefix() const {
std::string PluginInfo::wine_version() const {
// The '*.exe' scripts generated by winegcc allow you to override the binary
// used to run Wine, so will will handle this in the same way for our Wine
// version detection
// FIXME: Replace Boost.Filesystem usage
boost::filesystem::path wine_path;
bp::environment env = create_host_env();
if (const std::string wineloader_path = env["WINELOADER"].to_string();
access(wineloader_path.c_str(), X_OK) == 0) {
// version detection. We'll be using `execvpe`
std::string wine_path = "wine";
// NOLINTNEXTLINE(concurrency-mt-unsafe)
if (const char* wineloader_path = getenv("WINELOADER");
wineloader_path && access(wineloader_path, X_OK) == 0) {
wine_path = wineloader_path;
} else {
wine_path = bp::search_path("wine").string();
}
bp::ipstream output;
try {
bp::system(wine_path, "--version", bp::std_out = output, bp::env = env,
bp::posix::use_vfork);
} catch (const std::system_error&) {
return "<NOT FOUND>";
}
Process process(wine_path);
process.arg("--version");
process.environment(create_host_env_2());
// `wine --version` might contain additional output in certain custom Wine
// builds, so we only want to look at the first line
std::string version_string;
std::getline(output, version_string);
auto result = process.spawn_get_stdout_line();
return std::visit(
overload{
[](std::string version_string) -> std::string {
// Strip the `wine-` prefix from the output, could potentially
// be absent in custom Wine builds
constexpr std::string_view version_prefix("wine-");
if (version_string.starts_with(version_prefix)) {
version_string =
version_string.substr(version_prefix.size());
}
// Strip the `wine-` prefix from the output, could potentially be absent in
// custom Wine builds
constexpr std::string_view version_prefix("wine-");
if (version_string.starts_with(version_prefix)) {
version_string = version_string.substr(version_prefix.size());
}
return version_string;
return version_string;
},
[](const Process::CommandNotFound&) -> std::string {
return "<NOT FOUND>";
},
[](const std::error_code& err) -> std::string {
return "<ERROR SPAWNING WINE: " + err.message() + " >";
},
},
result);
}
fs::path find_plugin_library(const fs::path& this_plugin_path,
@@ -256,9 +279,9 @@ fs::path normalize_plugin_path(const fs::path& windows_library_path,
std::variant<OverridenWinePrefix, fs::path, DefaultWinePrefix> find_wine_prefix(
fs::path windows_plugin_path) {
const bp::environment env = boost::this_process::environment();
if (const auto prefix = env.find("WINEPREFIX"); prefix != env.end()) {
return OverridenWinePrefix{prefix->to_string()};
// NOLINTNEXTLINE(concurrency-mt-unsafe)
if (const auto prefix = getenv("WINEPREFIX")) {
return OverridenWinePrefix{prefix};
}
const std::optional<fs::path> dosdevices_dir = find_dominating_file(
@@ -411,16 +434,14 @@ std::vector<boost::filesystem::path> get_augmented_search_path() {
std::vector<boost::filesystem::path> search_path =
boost::this_process::path();
const bp::environment environment = boost::this_process::environment();
if (auto xdg_data_home = environment.find("XDG_DATA_HOME");
xdg_data_home != environment.end()) {
search_path.push_back(
boost::filesystem::path(xdg_data_home->to_string()) / "yabridge");
} else if (auto home_directory = environment.find("HOME");
home_directory != environment.end()) {
search_path.push_back(
boost::filesystem::path(home_directory->to_string()) / ".local" /
"share" / "yabridge");
// NOLINTNEXTLINE(concurrency-mt-unsafe)
if (const char* xdg_data_home = getenv("XDG_DATA_HOME")) {
search_path.push_back(boost::filesystem::path(xdg_data_home) /
"yabridge");
// NOLINTNEXTLINE(concurrency-mt-unsafe)
} else if (const char* home_directory = getenv("HOME")) {
search_path.push_back(boost::filesystem::path(home_directory) /
".local" / "share" / "yabridge");
}
return search_path;
@@ -472,6 +493,8 @@ bool send_notification(const std::string& title,
}
}
// TODO: Also use a custom process here, and wrap the above code in a
// class
try {
return bp::system(notify_send_path, "--urgency=normal",
"--expire-time=15000", "--app-name=yabridge", title,
+3
View File
@@ -22,6 +22,7 @@
#include "../common/configuration.h"
#include "../common/plugins.h"
#include "../common/process.h"
#include "../common/utils.h"
/**
@@ -76,6 +77,8 @@ struct PluginInfo {
* unset if we could not detect a prefix.
*/
boost::process::environment create_host_env() const;
// FIXME: Replace create_host_env with this one
ProcessEnvironment create_host_env_2() const;
/**
* Return the path to the actual Wine prefix in use, taking into account