Browse Source

Added filesystem::is_executable

pipelines/353213535
eidheim 4 years ago
parent
commit
c3afe1009b
  1. 42
      src/filesystem.cpp
  2. 21
      src/filesystem.hpp
  3. 14
      src/notebook.cpp
  4. 18
      tests/filesystem_test.cpp

42
src/filesystem.cpp

@ -36,7 +36,7 @@ bool filesystem::write(const std::string &path, const std::string &new_content)
return true;
}
std::string filesystem::escape_argument(const std::string &argument) {
std::string filesystem::escape_argument(const std::string &argument) noexcept {
auto escaped = argument;
for(size_t pos = 0; pos < escaped.size(); ++pos) {
if(escaped[pos] == ' ' || escaped[pos] == '(' || escaped[pos] == ')' || escaped[pos] == '\'' || escaped[pos] == '"') {
@ -47,7 +47,7 @@ std::string filesystem::escape_argument(const std::string &argument) {
return escaped;
}
std::string filesystem::unescape_argument(const std::string &argument) {
std::string filesystem::unescape_argument(const std::string &argument) noexcept {
auto unescaped = argument;
if(unescaped.size() >= 2) {
@ -204,13 +204,13 @@ boost::filesystem::path filesystem::get_long_path(const boost::filesystem::path
#endif
}
bool filesystem::file_in_path(const boost::filesystem::path &file_path, const boost::filesystem::path &path) {
bool filesystem::file_in_path(const boost::filesystem::path &file_path, const boost::filesystem::path &path) noexcept {
if(std::distance(file_path.begin(), file_path.end()) < std::distance(path.begin(), path.end()))
return false;
return std::equal(path.begin(), path.end(), file_path.begin());
}
boost::filesystem::path filesystem::find_file_in_path_parents(const std::string &file_name, const boost::filesystem::path &path) {
boost::filesystem::path filesystem::find_file_in_path_parents(const std::string &file_name, const boost::filesystem::path &path) noexcept {
auto current_path = path;
boost::system::error_code ec;
while(true) {
@ -283,7 +283,7 @@ boost::filesystem::path filesystem::get_executable(const boost::filesystem::path
try {
for(auto &path : bin_paths) {
if(boost::filesystem::exists(path / executable_name))
if(is_executable(path / executable_name))
return executable_name;
}
@ -317,7 +317,7 @@ boost::filesystem::path filesystem::get_executable(const boost::filesystem::path
}
// Based on https://stackoverflow.com/a/11295568
const std::vector<boost::filesystem::path> &filesystem::get_executable_search_paths() {
const std::vector<boost::filesystem::path> &filesystem::get_executable_search_paths() noexcept {
auto get_paths = [] {
std::vector<boost::filesystem::path> paths;
@ -347,21 +347,16 @@ const std::vector<boost::filesystem::path> &filesystem::get_executable_search_pa
return *executable_search_paths;
}
boost::filesystem::path filesystem::find_executable(const std::string &executable_name) {
boost::filesystem::path filesystem::find_executable(const std::string &executable_name) noexcept {
for(auto &path : get_executable_search_paths()) {
boost::system::error_code ec;
#ifdef _WIN32
auto executable_path = path / (executable_name + ".exe");
#else
auto executable_path = path / executable_name;
#endif
if(boost::filesystem::exists(executable_path, ec))
if(is_executable(executable_path))
return executable_path;
}
return boost::filesystem::path();
}
std::string filesystem::get_uri_from_path(const boost::filesystem::path &path) {
std::string filesystem::get_uri_from_path(const boost::filesystem::path &path) noexcept {
std::string uri{"file://"};
static auto hex_chars = "0123456789ABCDEF";
@ -378,7 +373,7 @@ std::string filesystem::get_uri_from_path(const boost::filesystem::path &path) {
return uri;
}
boost::filesystem::path filesystem::get_path_from_uri(const std::string &uri) {
boost::filesystem::path filesystem::get_path_from_uri(const std::string &uri) noexcept {
std::string encoded;
if(starts_with(uri, "file://"))
@ -403,7 +398,7 @@ boost::filesystem::path filesystem::get_path_from_uri(const std::string &uri) {
return unencoded;
}
boost::filesystem::path filesystem::get_canonical_path(const boost::filesystem::path &path) {
boost::filesystem::path filesystem::get_canonical_path(const boost::filesystem::path &path) noexcept {
try {
return boost::filesystem::canonical(path);
}
@ -411,3 +406,18 @@ boost::filesystem::path filesystem::get_canonical_path(const boost::filesystem::
return path;
}
}
bool filesystem::is_executable(const boost::filesystem::path &path) noexcept {
if(path.empty())
return false;
boost::system::error_code ec;
#ifdef _WIN32
// Cannot for sure identify executable files in MSYS2
if(boost::filesystem::exists(path, ec))
return !boost::filesystem::is_directory(path, ec);
auto filename = path.filename().string() + ".exe";
return boost::filesystem::exists(path.has_parent_path() ? path.parent_path() / filename : filename, ec);
#else
return boost::filesystem::exists(path, ec) && !boost::filesystem::is_directory(path, ec) && boost::filesystem::status(path, ec).permissions() & (boost::filesystem::perms::owner_exe | boost::filesystem::perms::group_exe | boost::filesystem::perms::others_exe);
#endif
}

21
src/filesystem.hpp

@ -14,8 +14,8 @@ public:
static bool write(const std::string &path) { return write(path, ""); };
static bool write(const boost::filesystem::path &path) { return write(path, ""); };
static std::string escape_argument(const std::string &argument);
static std::string unescape_argument(const std::string &argument);
static std::string escape_argument(const std::string &argument) noexcept;
static std::string unescape_argument(const std::string &argument) noexcept;
/// Does not resolve symbolic links. Returns empty path on failure.
static const boost::filesystem::path &get_current_path() noexcept;
@ -34,8 +34,8 @@ public:
/// Replaces ~ with home path (boost::filesystem does not recognize ~)
static boost::filesystem::path get_long_path(const boost::filesystem::path &path) noexcept;
static bool file_in_path(const boost::filesystem::path &file_path, const boost::filesystem::path &path);
static boost::filesystem::path find_file_in_path_parents(const std::string &file_name, const boost::filesystem::path &path);
static bool file_in_path(const boost::filesystem::path &file_path, const boost::filesystem::path &path) noexcept;
static boost::filesystem::path find_file_in_path_parents(const std::string &file_name, const boost::filesystem::path &path) noexcept;
/// Return path with dot, dot-dot and directory separator elements removed
static boost::filesystem::path get_normal_path(const boost::filesystem::path &path) noexcept;
@ -47,18 +47,21 @@ public:
/// Return executable with latest version in filename on systems that is lacking executable_name symbolic link
static boost::filesystem::path get_executable(const boost::filesystem::path &executable_name) noexcept;
static const std::vector<boost::filesystem::path> &get_executable_search_paths();
static const std::vector<boost::filesystem::path> &get_executable_search_paths() noexcept;
/// Set to {} to reset get_executable_search_paths
static boost::optional<std::vector<boost::filesystem::path>> executable_search_paths;
/// Returns full executable path if found, or empty path otherwise.
static boost::filesystem::path find_executable(const std::string &executable_name);
static boost::filesystem::path find_executable(const std::string &executable_name) noexcept;
/// Get uri from path
static std::string get_uri_from_path(const boost::filesystem::path &path);
static std::string get_uri_from_path(const boost::filesystem::path &path) noexcept;
/// Get path from file uri
static boost::filesystem::path get_path_from_uri(const std::string &uri);
static boost::filesystem::path get_path_from_uri(const std::string &uri) noexcept;
/// Returns path on error. Do not use boost::filesystem::canonical_path since it is bugged when current_folder() fails.
static boost::filesystem::path get_canonical_path(const boost::filesystem::path &path);
static boost::filesystem::path get_canonical_path(const boost::filesystem::path &path) noexcept;
/// Platform independent check if path is executable
static bool is_executable(const boost::filesystem::path &path) noexcept;
};

14
src/notebook.cpp

@ -208,25 +208,15 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
// Try find rust-analyzer installed with rustup
auto sysroot = filesystem::get_rust_sysroot_path();
if(!sysroot.empty()) {
#ifdef _WIN32
auto rust_analyzer = sysroot / "bin" / "rust-analyzer.exe";
#else
auto rust_analyzer = sysroot / "bin" / "rust-analyzer";
#endif
boost::system::error_code ec;
if(boost::filesystem::exists(rust_analyzer, ec))
if(filesystem::is_executable(rust_analyzer))
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, filesystem::escape_argument(rust_analyzer.string())));
else {
// Workaround while rust-analyzer is in nightly toolchain only
auto nightly_sysroot = filesystem::get_rust_nightly_sysroot_path();
if(!nightly_sysroot.empty()) {
#ifdef _WIN32
auto nightly_rust_analyzer = nightly_sysroot / "bin" / "rust-analyzer.exe";
#else
auto nightly_rust_analyzer = nightly_sysroot / "bin" / "rust-analyzer";
#endif
boost::system::error_code ec;
if(boost::filesystem::exists(nightly_rust_analyzer, ec))
if(filesystem::is_executable(nightly_rust_analyzer))
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, filesystem::escape_argument(nightly_rust_analyzer.string())));
}
}

18
tests/filesystem_test.cpp

@ -20,10 +20,10 @@ int main() {
g_assert(!paths.empty());
for(auto &path : paths) {
g_assert(!path.empty());
#ifndef _WIN32
if(path.string() != "C:\\msys64\\usr\\local\\bin") { // Workaround for MSYS2
g_assert(boost::filesystem::exists(path));
g_assert(boost::filesystem::is_directory(path));
#endif
}
}
}
@ -119,4 +119,18 @@ int main() {
g_assert(uri == "file:///ro%20ot/te%20st%C3%A6%C3%B8%C3%A5.txt");
g_assert(path == filesystem::get_path_from_uri(uri));
}
{
g_assert(!filesystem::is_executable(filesystem::get_home_path()));
g_assert(!filesystem::is_executable(filesystem::get_current_path()));
g_assert(!filesystem::is_executable(tests_path));
#ifdef _WIN32
g_assert(filesystem::is_executable(tests_path / ".." / "LICENSE"));
#else
g_assert(!filesystem::is_executable(tests_path / ".." / "LICENSE"));
#endif
auto ls = filesystem::find_executable("ls");
g_assert(!ls.empty());
g_assert(filesystem::is_executable(ls));
}
}

Loading…
Cancel
Save